]> git.sur5r.net Git - cc65/commitdiff
This commit was generated by cvs2svn to compensate for changes in r2,
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 28 May 2000 13:40:48 +0000 (13:40 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 28 May 2000 13:40:48 +0000 (13:40 +0000)
which included commits to RCS files with non-trunk default branches.

git-svn-id: svn://svn.cc65.org/cc65/trunk@3 b7a2c559-68d2-44c3-8de9-860c34a00d81

847 files changed:
.cvsignore [new file with mode: 0644]
doc/BUGS [new file with mode: 0644]
doc/CREDITS [new file with mode: 0644]
doc/ar65.txt [new file with mode: 0644]
doc/ca65.txt [new file with mode: 0644]
doc/cc65.txt [new file with mode: 0644]
doc/cl65.txt [new file with mode: 0644]
doc/coding.txt [new file with mode: 0644]
doc/compile.txt [new file with mode: 0644]
doc/debugging.txt [new file with mode: 0644]
doc/internal.doc [new file with mode: 0644]
doc/intro.txt [new file with mode: 0644]
doc/ld65.txt [new file with mode: 0644]
doc/library.txt [new file with mode: 0644]
doc/newvers.txt [new file with mode: 0644]
doc/readme.1st [new file with mode: 0644]
doc/readme.txt [new file with mode: 0644]
include/6502.h [new file with mode: 0644]
include/_6525.h [new file with mode: 0644]
include/_6526.h [new file with mode: 0644]
include/_6545.h [new file with mode: 0644]
include/_6551.h [new file with mode: 0644]
include/_antic.h [new file with mode: 0644]
include/_gtia.h [new file with mode: 0644]
include/_pbi.h [new file with mode: 0644]
include/_pia.h [new file with mode: 0644]
include/_pokey.h [new file with mode: 0644]
include/_sid.h [new file with mode: 0644]
include/_vdc.h [new file with mode: 0644]
include/_vic.h [new file with mode: 0644]
include/ace.h [new file with mode: 0644]
include/apple2.h [new file with mode: 0644]
include/assert.h [new file with mode: 0644]
include/atari.h [new file with mode: 0644]
include/c128.h [new file with mode: 0644]
include/c64.h [new file with mode: 0644]
include/cbm.h [new file with mode: 0644]
include/cbm610.h [new file with mode: 0644]
include/conio.h [new file with mode: 0644]
include/ctype.h [new file with mode: 0644]
include/dbg.h [new file with mode: 0644]
include/errno.h [new file with mode: 0644]
include/fcntl.h [new file with mode: 0644]
include/geos.h [new file with mode: 0644]
include/geos/gconst.h [new file with mode: 0644]
include/geos/gdisk.h [new file with mode: 0644]
include/geos/gdlgbox.h [new file with mode: 0644]
include/geos/gfile.h [new file with mode: 0644]
include/geos/ggraph.h [new file with mode: 0644]
include/geos/gmemory.h [new file with mode: 0644]
include/geos/gmenu.h [new file with mode: 0644]
include/geos/gprocess.h [new file with mode: 0644]
include/geos/gsprite.h [new file with mode: 0644]
include/geos/gstruct.h [new file with mode: 0644]
include/geos/gsym.h [new file with mode: 0644]
include/geos/gsys.h [new file with mode: 0644]
include/iso646.h [new file with mode: 0644]
include/joystick.h [new file with mode: 0644]
include/limits.h [new file with mode: 0644]
include/locale.h [new file with mode: 0644]
include/mouse.h [new file with mode: 0644]
include/pet.h [new file with mode: 0644]
include/plus4.h [new file with mode: 0644]
include/rs232.h [new file with mode: 0644]
include/setjmp.h [new file with mode: 0644]
include/stdarg.h [new file with mode: 0644]
include/stddef.h [new file with mode: 0644]
include/stdio.h [new file with mode: 0644]
include/stdlib.h [new file with mode: 0644]
include/string.h [new file with mode: 0644]
include/time.h [new file with mode: 0644]
libsrc/.cvsignore [new file with mode: 0644]
libsrc/Makefile [new file with mode: 0644]
libsrc/apple2/Makefile [new file with mode: 0644]
libsrc/apple2/apple2.inc [new file with mode: 0644]
libsrc/apple2/break.s [new file with mode: 0644]
libsrc/apple2/cclear.s [new file with mode: 0644]
libsrc/apple2/cgetc.s [new file with mode: 0644]
libsrc/apple2/chline.s [new file with mode: 0644]
libsrc/apple2/clrscr.s [new file with mode: 0644]
libsrc/apple2/color.s [new file with mode: 0644]
libsrc/apple2/cputc.s [new file with mode: 0644]
libsrc/apple2/crt0.s [new file with mode: 0644]
libsrc/apple2/ctype.s [new file with mode: 0644]
libsrc/apple2/cvline.s [new file with mode: 0644]
libsrc/apple2/kbhit.s [new file with mode: 0644]
libsrc/apple2/read.s [new file with mode: 0644]
libsrc/apple2/revers.s [new file with mode: 0644]
libsrc/apple2/where.s [new file with mode: 0644]
libsrc/apple2/write.s [new file with mode: 0644]
libsrc/atari/Makefile [new file with mode: 0644]
libsrc/atari/atari.inc [new file with mode: 0644]
libsrc/atari/break.s [new file with mode: 0644]
libsrc/atari/cclear.s [new file with mode: 0644]
libsrc/atari/cgetc.s [new file with mode: 0644]
libsrc/atari/chline.s [new file with mode: 0644]
libsrc/atari/close.s [new file with mode: 0644]
libsrc/atari/clrscr.s [new file with mode: 0644]
libsrc/atari/color.s [new file with mode: 0644]
libsrc/atari/conio.s [new file with mode: 0644]
libsrc/atari/cputc.s [new file with mode: 0644]
libsrc/atari/crt0.s [new file with mode: 0644]
libsrc/atari/ctype.s [new file with mode: 0644]
libsrc/atari/cvline.s [new file with mode: 0644]
libsrc/atari/fdtable.s [new file with mode: 0644]
libsrc/atari/getargs.s [new file with mode: 0644]
libsrc/atari/gotox.s [new file with mode: 0644]
libsrc/atari/gotoxy.s [new file with mode: 0644]
libsrc/atari/gotoy.s [new file with mode: 0644]
libsrc/atari/kbhit.s [new file with mode: 0644]
libsrc/atari/open.s [new file with mode: 0644]
libsrc/atari/oserror.s [new file with mode: 0644]
libsrc/atari/read.s [new file with mode: 0644]
libsrc/atari/readjoy.s [new file with mode: 0644]
libsrc/atari/revers.s [new file with mode: 0644]
libsrc/atari/rwcommon.s [new file with mode: 0644]
libsrc/atari/savevec.s [new file with mode: 0644]
libsrc/atari/where.s [new file with mode: 0644]
libsrc/atari/write.s [new file with mode: 0644]
libsrc/c128/Makefile [new file with mode: 0644]
libsrc/c128/break.s [new file with mode: 0644]
libsrc/c128/c128.inc [new file with mode: 0644]
libsrc/c128/cgetc.s [new file with mode: 0644]
libsrc/c128/clrscr.s [new file with mode: 0644]
libsrc/c128/color.s [new file with mode: 0644]
libsrc/c128/conio.s [new file with mode: 0644]
libsrc/c128/cputc.s [new file with mode: 0644]
libsrc/c128/crt0.s [new file with mode: 0644]
libsrc/c128/dbgbreak.s [new file with mode: 0644]
libsrc/c128/kbhit.s [new file with mode: 0644]
libsrc/c128/readjoy.s [new file with mode: 0644]
libsrc/c64/Makefile [new file with mode: 0644]
libsrc/c64/break.s [new file with mode: 0644]
libsrc/c64/c64.inc [new file with mode: 0644]
libsrc/c64/cgetc.s [new file with mode: 0644]
libsrc/c64/clrscr.s [new file with mode: 0644]
libsrc/c64/color.s [new file with mode: 0644]
libsrc/c64/conio.s [new file with mode: 0644]
libsrc/c64/cputc.s [new file with mode: 0644]
libsrc/c64/crt0.s [new file with mode: 0644]
libsrc/c64/kbhit.s [new file with mode: 0644]
libsrc/c64/mouse.s [new file with mode: 0644]
libsrc/c64/read.s [new file with mode: 0644]
libsrc/c64/readjoy.s [new file with mode: 0644]
libsrc/c64/rs232.s [new file with mode: 0644]
libsrc/c64/write.s [new file with mode: 0644]
libsrc/cbm/Makefile [new file with mode: 0644]
libsrc/cbm/c_acptr.s [new file with mode: 0644]
libsrc/cbm/c_basin.s [new file with mode: 0644]
libsrc/cbm/c_bsout.s [new file with mode: 0644]
libsrc/cbm/c_ciout.s [new file with mode: 0644]
libsrc/cbm/c_ckout.s [new file with mode: 0644]
libsrc/cbm/c_clall.s [new file with mode: 0644]
libsrc/cbm/c_close.s [new file with mode: 0644]
libsrc/cbm/c_clrch.s [new file with mode: 0644]
libsrc/cbm/c_iobase.s [new file with mode: 0644]
libsrc/cbm/c_listen.s [new file with mode: 0644]
libsrc/cbm/c_load.s [new file with mode: 0644]
libsrc/cbm/c_open.s [new file with mode: 0644]
libsrc/cbm/c_readst.s [new file with mode: 0644]
libsrc/cbm/c_setlfs.s [new file with mode: 0644]
libsrc/cbm/c_setnam.s [new file with mode: 0644]
libsrc/cbm/c_talk.s [new file with mode: 0644]
libsrc/cbm/c_unlsn.s [new file with mode: 0644]
libsrc/cbm/c_untlk.s [new file with mode: 0644]
libsrc/cbm/cbm.inc [new file with mode: 0644]
libsrc/cbm/cclear.s [new file with mode: 0644]
libsrc/cbm/chline.s [new file with mode: 0644]
libsrc/cbm/clock.s [new file with mode: 0644]
libsrc/cbm/ctype.s [new file with mode: 0644]
libsrc/cbm/cvline.s [new file with mode: 0644]
libsrc/cbm/getenv.s [new file with mode: 0644]
libsrc/cbm/gotox.s [new file with mode: 0644]
libsrc/cbm/gotoxy.s [new file with mode: 0644]
libsrc/cbm/gotoy.s [new file with mode: 0644]
libsrc/cbm/oserror.s [new file with mode: 0644]
libsrc/cbm/revers.s [new file with mode: 0644]
libsrc/cbm/where.s [new file with mode: 0644]
libsrc/cbm610/Makefile [new file with mode: 0644]
libsrc/cbm610/banking.s [new file with mode: 0644]
libsrc/cbm610/break.s [new file with mode: 0644]
libsrc/cbm610/cbm610.inc [new file with mode: 0644]
libsrc/cbm610/cgetc.s [new file with mode: 0644]
libsrc/cbm610/clrscr.s [new file with mode: 0644]
libsrc/cbm610/color.s [new file with mode: 0644]
libsrc/cbm610/conio.s [new file with mode: 0644]
libsrc/cbm610/cputc.s [new file with mode: 0644]
libsrc/cbm610/crt0.s [new file with mode: 0644]
libsrc/cbm610/crtc.s [new file with mode: 0644]
libsrc/cbm610/io.inc [new file with mode: 0644]
libsrc/cbm610/kbhit.s [new file with mode: 0644]
libsrc/cbm610/kirq.s [new file with mode: 0644]
libsrc/cbm610/kplot.s [new file with mode: 0644]
libsrc/cbm610/kscnkey.s [new file with mode: 0644]
libsrc/cbm610/kudtim.s [new file with mode: 0644]
libsrc/cbm610/page3.inc [new file with mode: 0644]
libsrc/cbm610/pokesys.s [new file with mode: 0644]
libsrc/cbm610/rs232.s [new file with mode: 0644]
libsrc/cbm610/zeropage.inc [new file with mode: 0644]
libsrc/common/.cvsignore [new file with mode: 0644]
libsrc/common/Makefile [new file with mode: 0644]
libsrc/common/_afailed.c [new file with mode: 0644]
libsrc/common/_fdesc.s [new file with mode: 0644]
libsrc/common/_file.h [new file with mode: 0644]
libsrc/common/_file.s [new file with mode: 0644]
libsrc/common/_fopen.c [new file with mode: 0644]
libsrc/common/_hadd.c [new file with mode: 0644]
libsrc/common/_heap.h [new file with mode: 0644]
libsrc/common/_heap.s [new file with mode: 0644]
libsrc/common/_hextab.c [new file with mode: 0644]
libsrc/common/_oserror.s [new file with mode: 0644]
libsrc/common/_printf.c [new file with mode: 0644]
libsrc/common/_printf.h [new file with mode: 0644]
libsrc/common/_stksize.s [new file with mode: 0644]
libsrc/common/_swap.s [new file with mode: 0644]
libsrc/common/_sys.s [new file with mode: 0644]
libsrc/common/abort.c [new file with mode: 0644]
libsrc/common/abs.s [new file with mode: 0644]
libsrc/common/atexit.s [new file with mode: 0644]
libsrc/common/atoi.s [new file with mode: 0644]
libsrc/common/bsearch.c [new file with mode: 0644]
libsrc/common/calloc.c [new file with mode: 0644]
libsrc/common/copydata.s [new file with mode: 0644]
libsrc/common/cprintf.c [new file with mode: 0644]
libsrc/common/errno.inc [new file with mode: 0644]
libsrc/common/errno.s [new file with mode: 0644]
libsrc/common/errormsg.c [new file with mode: 0644]
libsrc/common/fclose.c [new file with mode: 0644]
libsrc/common/fdopen.c [new file with mode: 0644]
libsrc/common/fgetc.c [new file with mode: 0644]
libsrc/common/fgets.c [new file with mode: 0644]
libsrc/common/fmisc.s [new file with mode: 0644]
libsrc/common/fmode.inc [new file with mode: 0644]
libsrc/common/fopen.c [new file with mode: 0644]
libsrc/common/fprintf.c [new file with mode: 0644]
libsrc/common/fputc.c [new file with mode: 0644]
libsrc/common/fputs.c [new file with mode: 0644]
libsrc/common/fread.c [new file with mode: 0644]
libsrc/common/free.c [new file with mode: 0644]
libsrc/common/freopen.c [new file with mode: 0644]
libsrc/common/fwrite.c [new file with mode: 0644]
libsrc/common/getchar.c [new file with mode: 0644]
libsrc/common/getcpu.s [new file with mode: 0644]
libsrc/common/gets.c [new file with mode: 0644]
libsrc/common/isalnum.s [new file with mode: 0644]
libsrc/common/isalpha.s [new file with mode: 0644]
libsrc/common/isblank.s [new file with mode: 0644]
libsrc/common/iscntrl.s [new file with mode: 0644]
libsrc/common/isdigit.s [new file with mode: 0644]
libsrc/common/isgraph.s [new file with mode: 0644]
libsrc/common/islower.s [new file with mode: 0644]
libsrc/common/isprint.s [new file with mode: 0644]
libsrc/common/ispunct.s [new file with mode: 0644]
libsrc/common/isspace.s [new file with mode: 0644]
libsrc/common/isupper.s [new file with mode: 0644]
libsrc/common/isxdigit.s [new file with mode: 0644]
libsrc/common/itoa.s [new file with mode: 0644]
libsrc/common/jmpvec.s [new file with mode: 0644]
libsrc/common/labs.s [new file with mode: 0644]
libsrc/common/locale.c [new file with mode: 0644]
libsrc/common/longjmp.s [new file with mode: 0644]
libsrc/common/ltoa.s [new file with mode: 0644]
libsrc/common/malloc.c [new file with mode: 0644]
libsrc/common/memchr.s [new file with mode: 0644]
libsrc/common/memcmp.s [new file with mode: 0644]
libsrc/common/memcpy.s [new file with mode: 0644]
libsrc/common/memset.s [new file with mode: 0644]
libsrc/common/perror.c [new file with mode: 0644]
libsrc/common/printf.c [new file with mode: 0644]
libsrc/common/putchar.c [new file with mode: 0644]
libsrc/common/puts.c [new file with mode: 0644]
libsrc/common/qsort.c [new file with mode: 0644]
libsrc/common/rand.s [new file with mode: 0644]
libsrc/common/realloc.c [new file with mode: 0644]
libsrc/common/setjmp.s [new file with mode: 0644]
libsrc/common/sprintf.c [new file with mode: 0644]
libsrc/common/stkcheck.s [new file with mode: 0644]
libsrc/common/strcat.s [new file with mode: 0644]
libsrc/common/strchr.s [new file with mode: 0644]
libsrc/common/strcmp.s [new file with mode: 0644]
libsrc/common/strcoll.s [new file with mode: 0644]
libsrc/common/strcpy.s [new file with mode: 0644]
libsrc/common/strcspn.s [new file with mode: 0644]
libsrc/common/strdup.c [new file with mode: 0644]
libsrc/common/strerror.s [new file with mode: 0644]
libsrc/common/stricmp.s [new file with mode: 0644]
libsrc/common/strlen.s [new file with mode: 0644]
libsrc/common/strlower.s [new file with mode: 0644]
libsrc/common/strncat.s [new file with mode: 0644]
libsrc/common/strncmp.s [new file with mode: 0644]
libsrc/common/strncpy.s [new file with mode: 0644]
libsrc/common/strpbrk.s [new file with mode: 0644]
libsrc/common/strrchr.s [new file with mode: 0644]
libsrc/common/strspn.s [new file with mode: 0644]
libsrc/common/strstr.s [new file with mode: 0644]
libsrc/common/strtok.c [new file with mode: 0644]
libsrc/common/strupper.s [new file with mode: 0644]
libsrc/common/strxfrm.c [new file with mode: 0644]
libsrc/common/tolower.s [new file with mode: 0644]
libsrc/common/toupper.s [new file with mode: 0644]
libsrc/common/vcprintf.c [new file with mode: 0644]
libsrc/common/vfprintf.c [new file with mode: 0644]
libsrc/common/vprintf.c [new file with mode: 0644]
libsrc/common/vsprintf.c [new file with mode: 0644]
libsrc/common/zerobss.s [new file with mode: 0644]
libsrc/conio/Makefile [new file with mode: 0644]
libsrc/conio/cputhex.s [new file with mode: 0644]
libsrc/conio/cputs.s [new file with mode: 0644]
libsrc/conio/cursor.s [new file with mode: 0644]
libsrc/conio/scrsize.s [new file with mode: 0644]
libsrc/dbg/.cvsignore [new file with mode: 0644]
libsrc/dbg/Makefile [new file with mode: 0644]
libsrc/dbg/asmtab.s [new file with mode: 0644]
libsrc/dbg/dbg.c [new file with mode: 0644]
libsrc/dbg/dbgdasm.s [new file with mode: 0644]
libsrc/dbg/dbgdump.s [new file with mode: 0644]
libsrc/dbg/dbgisram.s [new file with mode: 0644]
libsrc/dbg/dbgsupp.s [new file with mode: 0644]
libsrc/geos/Makefile [new file with mode: 0644]
libsrc/geos/devel/Makefile [new file with mode: 0644]
libsrc/geos/devel/crt0.s [new file with mode: 0644]
libsrc/geos/devel/cvthead.s [new file with mode: 0644]
libsrc/geos/disk/Makefile [new file with mode: 0644]
libsrc/geos/disk/blkalloc.s [new file with mode: 0644]
libsrc/geos/disk/calcblksfree.s [new file with mode: 0644]
libsrc/geos/disk/changediskdevice.s [new file with mode: 0644]
libsrc/geos/disk/chkdkgeos.s [new file with mode: 0644]
libsrc/geos/disk/enterturbo.s [new file with mode: 0644]
libsrc/geos/disk/exitturbo.s [new file with mode: 0644]
libsrc/geos/disk/findbambit.s [new file with mode: 0644]
libsrc/geos/disk/freeblock.s [new file with mode: 0644]
libsrc/geos/disk/getblock.s [new file with mode: 0644]
libsrc/geos/disk/getdirhead.s [new file with mode: 0644]
libsrc/geos/disk/getptrcurdknm.s [new file with mode: 0644]
libsrc/geos/disk/gettrse.s [new file with mode: 0644]
libsrc/geos/disk/newdisk.s [new file with mode: 0644]
libsrc/geos/disk/nxtblkalloc.s [new file with mode: 0644]
libsrc/geos/disk/opendisk.s [new file with mode: 0644]
libsrc/geos/disk/purgeturbo.s [new file with mode: 0644]
libsrc/geos/disk/putblock.s [new file with mode: 0644]
libsrc/geos/disk/putdirhead.s [new file with mode: 0644]
libsrc/geos/disk/readblock.s [new file with mode: 0644]
libsrc/geos/disk/readbuff.s [new file with mode: 0644]
libsrc/geos/disk/setgeosdisk.s [new file with mode: 0644]
libsrc/geos/disk/setnextfree.s [new file with mode: 0644]
libsrc/geos/disk/verwriteblock.s [new file with mode: 0644]
libsrc/geos/disk/writeblock.s [new file with mode: 0644]
libsrc/geos/disk/writebuff.s [new file with mode: 0644]
libsrc/geos/dlgbox/Makefile [new file with mode: 0644]
libsrc/geos/dlgbox/dbget2lines.s [new file with mode: 0644]
libsrc/geos/dlgbox/dlgboxfileselect.s [new file with mode: 0644]
libsrc/geos/dlgbox/dlgboxgetstring.s [new file with mode: 0644]
libsrc/geos/dlgbox/dlgboxok.s [new file with mode: 0644]
libsrc/geos/dlgbox/dlgboxokcancel.s [new file with mode: 0644]
libsrc/geos/dlgbox/dlgboxyesno.s [new file with mode: 0644]
libsrc/geos/dlgbox/dodlgbox.s [new file with mode: 0644]
libsrc/geos/dlgbox/rstrfrmdialogue.s [new file with mode: 0644]
libsrc/geos/file/Makefile [new file with mode: 0644]
libsrc/geos/file/appendrecord.s [new file with mode: 0644]
libsrc/geos/file/closerecordfile.s [new file with mode: 0644]
libsrc/geos/file/deletefile.s [new file with mode: 0644]
libsrc/geos/file/deleterecord.s [new file with mode: 0644]
libsrc/geos/file/findfile.s [new file with mode: 0644]
libsrc/geos/file/findftypes.s [new file with mode: 0644]
libsrc/geos/file/followchain.s [new file with mode: 0644]
libsrc/geos/file/freefile.s [new file with mode: 0644]
libsrc/geos/file/get1stdirentry.s [new file with mode: 0644]
libsrc/geos/file/getfhdrinfo.s [new file with mode: 0644]
libsrc/geos/file/getnxtdirentry.s [new file with mode: 0644]
libsrc/geos/file/insertrecord.s [new file with mode: 0644]
libsrc/geos/file/nextrecord.s [new file with mode: 0644]
libsrc/geos/file/openrecordfile.s [new file with mode: 0644]
libsrc/geos/file/pointrecord.s [new file with mode: 0644]
libsrc/geos/file/previousrecord.s [new file with mode: 0644]
libsrc/geos/file/readbyte.s [new file with mode: 0644]
libsrc/geos/file/readfile.s [new file with mode: 0644]
libsrc/geos/file/readrecord.s [new file with mode: 0644]
libsrc/geos/file/renamefile.s [new file with mode: 0644]
libsrc/geos/file/savefile.s [new file with mode: 0644]
libsrc/geos/file/updaterecordfile.s [new file with mode: 0644]
libsrc/geos/file/writerecord.s [new file with mode: 0644]
libsrc/geos/graph/Makefile [new file with mode: 0644]
libsrc/geos/graph/bitmapclip.s [new file with mode: 0644]
libsrc/geos/graph/bitmapregs.s [new file with mode: 0644]
libsrc/geos/graph/bitmapup.s [new file with mode: 0644]
libsrc/geos/graph/bitotherclip.s [new file with mode: 0644]
libsrc/geos/graph/drawline.s [new file with mode: 0644]
libsrc/geos/graph/drawpoint.s [new file with mode: 0644]
libsrc/geos/graph/framerectangle.s [new file with mode: 0644]
libsrc/geos/graph/getcharwidth.s [new file with mode: 0644]
libsrc/geos/graph/getintcharint.s [new file with mode: 0644]
libsrc/geos/graph/graphicsstring.s [new file with mode: 0644]
libsrc/geos/graph/hlineregs.s [new file with mode: 0644]
libsrc/geos/graph/horizontalline.s [new file with mode: 0644]
libsrc/geos/graph/imprintrectangle.s [new file with mode: 0644]
libsrc/geos/graph/initdrawwindow.s [new file with mode: 0644]
libsrc/geos/graph/invertline.s [new file with mode: 0644]
libsrc/geos/graph/invertrectangle.s [new file with mode: 0644]
libsrc/geos/graph/loadcharset.s [new file with mode: 0644]
libsrc/geos/graph/pointregs.s [new file with mode: 0644]
libsrc/geos/graph/putchar.s [new file with mode: 0644]
libsrc/geos/graph/putdecimal.s [new file with mode: 0644]
libsrc/geos/graph/putstring.s [new file with mode: 0644]
libsrc/geos/graph/recoverline.s [new file with mode: 0644]
libsrc/geos/graph/recoverrectangle.s [new file with mode: 0644]
libsrc/geos/graph/rectangle.s [new file with mode: 0644]
libsrc/geos/graph/setpattern.s [new file with mode: 0644]
libsrc/geos/graph/testpoint.s [new file with mode: 0644]
libsrc/geos/graph/usesystemfont.s [new file with mode: 0644]
libsrc/geos/graph/verticalline.s [new file with mode: 0644]
libsrc/geos/inc/const.inc [new file with mode: 0644]
libsrc/geos/inc/diskdrv.inc [new file with mode: 0644]
libsrc/geos/inc/geosmac.ca65.inc [new file with mode: 0644]
libsrc/geos/inc/geossym.inc [new file with mode: 0644]
libsrc/geos/inc/geossym2.inc [new file with mode: 0644]
libsrc/geos/inc/inputdrv.inc [new file with mode: 0644]
libsrc/geos/inc/jumptab.inc [new file with mode: 0644]
libsrc/geos/inc/printdrv.inc [new file with mode: 0644]
libsrc/geos/memory/Makefile [new file with mode: 0644]
libsrc/geos/memory/clearram.s [new file with mode: 0644]
libsrc/geos/memory/cmpfstring.s [new file with mode: 0644]
libsrc/geos/memory/cmpstring.s [new file with mode: 0644]
libsrc/geos/memory/copyfstring.s [new file with mode: 0644]
libsrc/geos/memory/copystring.s [new file with mode: 0644]
libsrc/geos/memory/crc.s [new file with mode: 0644]
libsrc/geos/memory/doublepop.s [new file with mode: 0644]
libsrc/geos/memory/doublespop.s [new file with mode: 0644]
libsrc/geos/memory/fetchram.s [new file with mode: 0644]
libsrc/geos/memory/fillram.s [new file with mode: 0644]
libsrc/geos/memory/initram.s [new file with mode: 0644]
libsrc/geos/memory/movedata.s [new file with mode: 0644]
libsrc/geos/memory/reuregs.s [new file with mode: 0644]
libsrc/geos/memory/stashram.s [new file with mode: 0644]
libsrc/geos/memory/swapram.s [new file with mode: 0644]
libsrc/geos/memory/verifyram.s [new file with mode: 0644]
libsrc/geos/menuicon/Makefile [new file with mode: 0644]
libsrc/geos/menuicon/doicons.s [new file with mode: 0644]
libsrc/geos/menuicon/domenu.s [new file with mode: 0644]
libsrc/geos/menuicon/dopreviousmenu.s [new file with mode: 0644]
libsrc/geos/menuicon/gotofirstmenu.s [new file with mode: 0644]
libsrc/geos/menuicon/recoverallmenus.s [new file with mode: 0644]
libsrc/geos/menuicon/recovermenu.s [new file with mode: 0644]
libsrc/geos/menuicon/redomenu.s [new file with mode: 0644]
libsrc/geos/mousesprite/Makefile [new file with mode: 0644]
libsrc/geos/mousesprite/clearmousemode.s [new file with mode: 0644]
libsrc/geos/mousesprite/disablsprite.s [new file with mode: 0644]
libsrc/geos/mousesprite/drawsprite.s [new file with mode: 0644]
libsrc/geos/mousesprite/enablsprite.s [new file with mode: 0644]
libsrc/geos/mousesprite/getnextchar.s [new file with mode: 0644]
libsrc/geos/mousesprite/inittextprompt.s [new file with mode: 0644]
libsrc/geos/mousesprite/ismseinregion.s [new file with mode: 0644]
libsrc/geos/mousesprite/mouseoff.s [new file with mode: 0644]
libsrc/geos/mousesprite/mouseup.s [new file with mode: 0644]
libsrc/geos/mousesprite/possprite.s [new file with mode: 0644]
libsrc/geos/mousesprite/promptoff.s [new file with mode: 0644]
libsrc/geos/mousesprite/prompton.s [new file with mode: 0644]
libsrc/geos/mousesprite/startmousemode.s [new file with mode: 0644]
libsrc/geos/process/Makefile [new file with mode: 0644]
libsrc/geos/process/processblock.s [new file with mode: 0644]
libsrc/geos/process/processfreeze.s [new file with mode: 0644]
libsrc/geos/process/processinitrestartenable.s [new file with mode: 0644]
libsrc/geos/process/sleep.s [new file with mode: 0644]
libsrc/geos/system/Makefile [new file with mode: 0644]
libsrc/geos/system/callroutine.s [new file with mode: 0644]
libsrc/geos/system/enterdesktop.s [new file with mode: 0644]
libsrc/geos/system/firstinit.s [new file with mode: 0644]
libsrc/geos/system/getrandom.s [new file with mode: 0644]
libsrc/geos/system/getserialnumber.s [new file with mode: 0644]
libsrc/geos/system/initdoneio.s [new file with mode: 0644]
libsrc/geos/system/mainloop.s [new file with mode: 0644]
libsrc/geos/system/panic.s [new file with mode: 0644]
libsrc/geos/system/setdevice.s [new file with mode: 0644]
libsrc/geos/system/tobasic.s [new file with mode: 0644]
libsrc/pet/Makefile [new file with mode: 0644]
libsrc/pet/break.s [new file with mode: 0644]
libsrc/pet/cgetc.s [new file with mode: 0644]
libsrc/pet/clrscr.s [new file with mode: 0644]
libsrc/pet/color.s [new file with mode: 0644]
libsrc/pet/conio.s [new file with mode: 0644]
libsrc/pet/cputc.s [new file with mode: 0644]
libsrc/pet/crt0.s [new file with mode: 0644]
libsrc/pet/kbhit.s [new file with mode: 0644]
libsrc/pet/pet.inc [new file with mode: 0644]
libsrc/plus4/Makefile [new file with mode: 0644]
libsrc/plus4/break.s [new file with mode: 0644]
libsrc/plus4/cgetc.s [new file with mode: 0644]
libsrc/plus4/clrscr.s [new file with mode: 0644]
libsrc/plus4/color.s [new file with mode: 0644]
libsrc/plus4/conio.s [new file with mode: 0644]
libsrc/plus4/cputc.s [new file with mode: 0644]
libsrc/plus4/crt0.s [new file with mode: 0644]
libsrc/plus4/kbhit.s [new file with mode: 0644]
libsrc/plus4/plus4.inc [new file with mode: 0644]
libsrc/plus4/readjoy.s [new file with mode: 0644]
libsrc/runtime/Makefile [new file with mode: 0644]
libsrc/runtime/add.s [new file with mode: 0644]
libsrc/runtime/addeqsp.s [new file with mode: 0644]
libsrc/runtime/and.s [new file with mode: 0644]
libsrc/runtime/aslax1.s [new file with mode: 0644]
libsrc/runtime/aslax2.s [new file with mode: 0644]
libsrc/runtime/aslax3.s [new file with mode: 0644]
libsrc/runtime/asleax1.s [new file with mode: 0644]
libsrc/runtime/asleax2.s [new file with mode: 0644]
libsrc/runtime/asleax3.s [new file with mode: 0644]
libsrc/runtime/asrax1.s [new file with mode: 0644]
libsrc/runtime/asrax2.s [new file with mode: 0644]
libsrc/runtime/asrax3.s [new file with mode: 0644]
libsrc/runtime/asreax1.s [new file with mode: 0644]
libsrc/runtime/asreax2.s [new file with mode: 0644]
libsrc/runtime/asreax3.s [new file with mode: 0644]
libsrc/runtime/bneg.s [new file with mode: 0644]
libsrc/runtime/bpushbsp.s [new file with mode: 0644]
libsrc/runtime/call.s [new file with mode: 0644]
libsrc/runtime/compl.s [new file with mode: 0644]
libsrc/runtime/dec.s [new file with mode: 0644]
libsrc/runtime/div.s [new file with mode: 0644]
libsrc/runtime/enter.s [new file with mode: 0644]
libsrc/runtime/eq.s [new file with mode: 0644]
libsrc/runtime/ge.s [new file with mode: 0644]
libsrc/runtime/gt.s [new file with mode: 0644]
libsrc/runtime/icmp.s [new file with mode: 0644]
libsrc/runtime/inc.s [new file with mode: 0644]
libsrc/runtime/ladd.s [new file with mode: 0644]
libsrc/runtime/laddeq.s [new file with mode: 0644]
libsrc/runtime/laddeqsp.s [new file with mode: 0644]
libsrc/runtime/land.s [new file with mode: 0644]
libsrc/runtime/lbneg.s [new file with mode: 0644]
libsrc/runtime/lcmp.s [new file with mode: 0644]
libsrc/runtime/lcompl.s [new file with mode: 0644]
libsrc/runtime/lconvert.s [new file with mode: 0644]
libsrc/runtime/ldai.s [new file with mode: 0644]
libsrc/runtime/ldasp.s [new file with mode: 0644]
libsrc/runtime/ldau0sp.s [new file with mode: 0644]
libsrc/runtime/ldaui.s [new file with mode: 0644]
libsrc/runtime/ldauisp.s [new file with mode: 0644]
libsrc/runtime/ldausp.s [new file with mode: 0644]
libsrc/runtime/ldaxi.s [new file with mode: 0644]
libsrc/runtime/ldaxsp.s [new file with mode: 0644]
libsrc/runtime/ldeax.s [new file with mode: 0644]
libsrc/runtime/ldeaxi.s [new file with mode: 0644]
libsrc/runtime/ldec.s [new file with mode: 0644]
libsrc/runtime/ldiv.s [new file with mode: 0644]
libsrc/runtime/le.s [new file with mode: 0644]
libsrc/runtime/leave.s [new file with mode: 0644]
libsrc/runtime/leaysp.s [new file with mode: 0644]
libsrc/runtime/leq.s [new file with mode: 0644]
libsrc/runtime/lge.s [new file with mode: 0644]
libsrc/runtime/lgt.s [new file with mode: 0644]
libsrc/runtime/linc.s [new file with mode: 0644]
libsrc/runtime/lle.s [new file with mode: 0644]
libsrc/runtime/llt.s [new file with mode: 0644]
libsrc/runtime/lmod.s [new file with mode: 0644]
libsrc/runtime/lmul.s [new file with mode: 0644]
libsrc/runtime/lne.s [new file with mode: 0644]
libsrc/runtime/lneg.s [new file with mode: 0644]
libsrc/runtime/lor.s [new file with mode: 0644]
libsrc/runtime/lpop.s [new file with mode: 0644]
libsrc/runtime/lpush.s [new file with mode: 0644]
libsrc/runtime/lrsub.s [new file with mode: 0644]
libsrc/runtime/lruntime.s [new file with mode: 0644]
libsrc/runtime/lsave.s [new file with mode: 0644]
libsrc/runtime/lshelp.s [new file with mode: 0644]
libsrc/runtime/lshl.s [new file with mode: 0644]
libsrc/runtime/lshr.s [new file with mode: 0644]
libsrc/runtime/lsub.s [new file with mode: 0644]
libsrc/runtime/lsubeq.s [new file with mode: 0644]
libsrc/runtime/lsubeqsp.s [new file with mode: 0644]
libsrc/runtime/lswap.s [new file with mode: 0644]
libsrc/runtime/lswitch.s [new file with mode: 0644]
libsrc/runtime/lt.s [new file with mode: 0644]
libsrc/runtime/ltest.s [new file with mode: 0644]
libsrc/runtime/ludiv.s [new file with mode: 0644]
libsrc/runtime/luge.s [new file with mode: 0644]
libsrc/runtime/lugt.s [new file with mode: 0644]
libsrc/runtime/lule.s [new file with mode: 0644]
libsrc/runtime/lult.s [new file with mode: 0644]
libsrc/runtime/lumod.s [new file with mode: 0644]
libsrc/runtime/lxor.s [new file with mode: 0644]
libsrc/runtime/makebool.s [new file with mode: 0644]
libsrc/runtime/mod.s [new file with mode: 0644]
libsrc/runtime/mul.s [new file with mode: 0644]
libsrc/runtime/ne.s [new file with mode: 0644]
libsrc/runtime/neg.s [new file with mode: 0644]
libsrc/runtime/or.s [new file with mode: 0644]
libsrc/runtime/popsreg.s [new file with mode: 0644]
libsrc/runtime/push.s [new file with mode: 0644]
libsrc/runtime/pushb.s [new file with mode: 0644]
libsrc/runtime/pushbsp.s [new file with mode: 0644]
libsrc/runtime/pushw.s [new file with mode: 0644]
libsrc/runtime/pushwsp.s [new file with mode: 0644]
libsrc/runtime/rsub.s [new file with mode: 0644]
libsrc/runtime/runtime.s [new file with mode: 0644]
libsrc/runtime/shelp.s [new file with mode: 0644]
libsrc/runtime/shl.s [new file with mode: 0644]
libsrc/runtime/shr.s [new file with mode: 0644]
libsrc/runtime/shrax1.s [new file with mode: 0644]
libsrc/runtime/shrax2.s [new file with mode: 0644]
libsrc/runtime/shrax3.s [new file with mode: 0644]
libsrc/runtime/shreax1.s [new file with mode: 0644]
libsrc/runtime/shreax2.s [new file with mode: 0644]
libsrc/runtime/shreax3.s [new file with mode: 0644]
libsrc/runtime/staxsp.s [new file with mode: 0644]
libsrc/runtime/steaxsp.s [new file with mode: 0644]
libsrc/runtime/sub.s [new file with mode: 0644]
libsrc/runtime/subeqsp.s [new file with mode: 0644]
libsrc/runtime/swap.s [new file with mode: 0644]
libsrc/runtime/switch.s [new file with mode: 0644]
libsrc/runtime/test.s [new file with mode: 0644]
libsrc/runtime/udiv.s [new file with mode: 0644]
libsrc/runtime/uge.s [new file with mode: 0644]
libsrc/runtime/ugt.s [new file with mode: 0644]
libsrc/runtime/ule.s [new file with mode: 0644]
libsrc/runtime/ult.s [new file with mode: 0644]
libsrc/runtime/umod.s [new file with mode: 0644]
libsrc/runtime/xor.s [new file with mode: 0644]
samples/.cvsignore [new file with mode: 0644]
samples/Makefile [new file with mode: 0644]
samples/c1541.rsp [new file with mode: 0644]
samples/hello.c [new file with mode: 0644]
samples/nachtm.c [new file with mode: 0644]
samples/sieve.c [new file with mode: 0644]
src/.cvsignore [new file with mode: 0644]
src/ar65/.cvsignore [new file with mode: 0644]
src/ar65/add.c [new file with mode: 0644]
src/ar65/add.h [new file with mode: 0644]
src/ar65/del.c [new file with mode: 0644]
src/ar65/del.h [new file with mode: 0644]
src/ar65/error.c [new file with mode: 0644]
src/ar65/error.h [new file with mode: 0644]
src/ar65/exports.c [new file with mode: 0644]
src/ar65/exports.h [new file with mode: 0644]
src/ar65/extract.c [new file with mode: 0644]
src/ar65/extract.h [new file with mode: 0644]
src/ar65/fileio.c [new file with mode: 0644]
src/ar65/fileio.h [new file with mode: 0644]
src/ar65/global.c [new file with mode: 0644]
src/ar65/global.h [new file with mode: 0644]
src/ar65/library.c [new file with mode: 0644]
src/ar65/library.h [new file with mode: 0644]
src/ar65/list.c [new file with mode: 0644]
src/ar65/list.h [new file with mode: 0644]
src/ar65/main.c [new file with mode: 0644]
src/ar65/make/gcc.mak [new file with mode: 0644]
src/ar65/make/watcom.mak [new file with mode: 0644]
src/ar65/mem.c [new file with mode: 0644]
src/ar65/mem.h [new file with mode: 0644]
src/ar65/objdata.c [new file with mode: 0644]
src/ar65/objdata.h [new file with mode: 0644]
src/ar65/objfile.c [new file with mode: 0644]
src/ar65/objfile.h [new file with mode: 0644]
src/ca65/.cvsignore [new file with mode: 0644]
src/ca65/condasm.c [new file with mode: 0644]
src/ca65/condasm.h [new file with mode: 0644]
src/ca65/ea.c [new file with mode: 0644]
src/ca65/ea.h [new file with mode: 0644]
src/ca65/error.c [new file with mode: 0644]
src/ca65/error.h [new file with mode: 0644]
src/ca65/expr.c [new file with mode: 0644]
src/ca65/expr.h [new file with mode: 0644]
src/ca65/fname.c [new file with mode: 0644]
src/ca65/fname.h [new file with mode: 0644]
src/ca65/fragment.c [new file with mode: 0644]
src/ca65/fragment.h [new file with mode: 0644]
src/ca65/global.c [new file with mode: 0644]
src/ca65/global.h [new file with mode: 0644]
src/ca65/instr.c [new file with mode: 0644]
src/ca65/instr.h [new file with mode: 0644]
src/ca65/listing.c [new file with mode: 0644]
src/ca65/listing.h [new file with mode: 0644]
src/ca65/macpack.c [new file with mode: 0644]
src/ca65/macpack.h [new file with mode: 0644]
src/ca65/macro.c [new file with mode: 0644]
src/ca65/macro.h [new file with mode: 0644]
src/ca65/main.c [new file with mode: 0644]
src/ca65/make/gcc.mak [new file with mode: 0644]
src/ca65/make/watcom.mak [new file with mode: 0644]
src/ca65/mem.c [new file with mode: 0644]
src/ca65/mem.h [new file with mode: 0644]
src/ca65/objcode.c [new file with mode: 0644]
src/ca65/objcode.h [new file with mode: 0644]
src/ca65/objfile.c [new file with mode: 0644]
src/ca65/objfile.h [new file with mode: 0644]
src/ca65/options.c [new file with mode: 0644]
src/ca65/options.h [new file with mode: 0644]
src/ca65/pseudo.c [new file with mode: 0644]
src/ca65/pseudo.h [new file with mode: 0644]
src/ca65/scanner.c [new file with mode: 0644]
src/ca65/scanner.h [new file with mode: 0644]
src/ca65/strexpr.c [new file with mode: 0644]
src/ca65/strexpr.h [new file with mode: 0644]
src/ca65/symentry.h [new file with mode: 0644]
src/ca65/symtab.c [new file with mode: 0644]
src/ca65/symtab.h [new file with mode: 0644]
src/ca65/toknode.c [new file with mode: 0644]
src/ca65/toknode.h [new file with mode: 0644]
src/ca65/ulabel.c [new file with mode: 0644]
src/ca65/ulabel.h [new file with mode: 0644]
src/cc65/.cvsignore [new file with mode: 0644]
src/cc65/anonname.c [new file with mode: 0644]
src/cc65/anonname.h [new file with mode: 0644]
src/cc65/asmcode.c [new file with mode: 0644]
src/cc65/asmcode.h [new file with mode: 0644]
src/cc65/asmlabel.c [new file with mode: 0644]
src/cc65/asmlabel.h [new file with mode: 0644]
src/cc65/asmline.c [new file with mode: 0644]
src/cc65/asmline.h [new file with mode: 0644]
src/cc65/check.c [new file with mode: 0644]
src/cc65/check.h [new file with mode: 0644]
src/cc65/codegen.c [new file with mode: 0644]
src/cc65/codegen.h [new file with mode: 0644]
src/cc65/copyleft.jrd [new file with mode: 0644]
src/cc65/ctrans.c [new file with mode: 0644]
src/cc65/ctrans.h [new file with mode: 0644]
src/cc65/datatype.c [new file with mode: 0644]
src/cc65/datatype.h [new file with mode: 0644]
src/cc65/declare.c [new file with mode: 0644]
src/cc65/declare.h [new file with mode: 0644]
src/cc65/error.c [new file with mode: 0644]
src/cc65/error.h [new file with mode: 0644]
src/cc65/expr.c [new file with mode: 0644]
src/cc65/expr.h [new file with mode: 0644]
src/cc65/funcdesc.c [new file with mode: 0644]
src/cc65/funcdesc.h [new file with mode: 0644]
src/cc65/function.c [new file with mode: 0644]
src/cc65/function.h [new file with mode: 0644]
src/cc65/global.c [new file with mode: 0644]
src/cc65/global.h [new file with mode: 0644]
src/cc65/goto.c [new file with mode: 0644]
src/cc65/goto.h [new file with mode: 0644]
src/cc65/hashstr.c [new file with mode: 0644]
src/cc65/hashstr.h [new file with mode: 0644]
src/cc65/ident.c [new file with mode: 0644]
src/cc65/ident.h [new file with mode: 0644]
src/cc65/include.c [new file with mode: 0644]
src/cc65/include.h [new file with mode: 0644]
src/cc65/io.c [new file with mode: 0644]
src/cc65/io.h [new file with mode: 0644]
src/cc65/litpool.c [new file with mode: 0644]
src/cc65/litpool.h [new file with mode: 0644]
src/cc65/locals.c [new file with mode: 0644]
src/cc65/locals.h [new file with mode: 0644]
src/cc65/loop.c [new file with mode: 0644]
src/cc65/loop.h [new file with mode: 0644]
src/cc65/macrotab.c [new file with mode: 0644]
src/cc65/macrotab.h [new file with mode: 0644]
src/cc65/main.c [new file with mode: 0644]
src/cc65/make/cc65.mak [new file with mode: 0644]
src/cc65/make/gcc.mak [new file with mode: 0644]
src/cc65/make/watcom.mak [new file with mode: 0644]
src/cc65/mem.c [new file with mode: 0644]
src/cc65/mem.h [new file with mode: 0644]
src/cc65/optimize.c [new file with mode: 0644]
src/cc65/optimize.h [new file with mode: 0644]
src/cc65/pragma.c [new file with mode: 0644]
src/cc65/pragma.h [new file with mode: 0644]
src/cc65/preproc.c [new file with mode: 0644]
src/cc65/preproc.h [new file with mode: 0644]
src/cc65/scanner.c [new file with mode: 0644]
src/cc65/scanner.h [new file with mode: 0644]
src/cc65/stdfunc.c [new file with mode: 0644]
src/cc65/stdfunc.h [new file with mode: 0644]
src/cc65/stmt.c [new file with mode: 0644]
src/cc65/stmt.h [new file with mode: 0644]
src/cc65/symentry.c [new file with mode: 0644]
src/cc65/symentry.h [new file with mode: 0644]
src/cc65/symtab.c [new file with mode: 0644]
src/cc65/symtab.h [new file with mode: 0644]
src/cc65/util.c [new file with mode: 0644]
src/cc65/util.h [new file with mode: 0644]
src/cl65/.cvsignore [new file with mode: 0644]
src/cl65/error.c [new file with mode: 0644]
src/cl65/error.h [new file with mode: 0644]
src/cl65/global.c [new file with mode: 0644]
src/cl65/global.h [new file with mode: 0644]
src/cl65/main.c [new file with mode: 0644]
src/cl65/make/gcc.mak [new file with mode: 0644]
src/cl65/make/watcom.mak [new file with mode: 0644]
src/cl65/mem.c [new file with mode: 0644]
src/cl65/mem.h [new file with mode: 0644]
src/cl65/spawn.c [new file with mode: 0644]
src/cl65/spawn.h [new file with mode: 0644]
src/common/.cvsignore [new file with mode: 0644]
src/common/bitops.c [new file with mode: 0644]
src/common/bitops.h [new file with mode: 0644]
src/common/exprdefs.h [new file with mode: 0644]
src/common/filepos.h [new file with mode: 0644]
src/common/hashstr.c [new file with mode: 0644]
src/common/hashstr.h [new file with mode: 0644]
src/common/libdefs.h [new file with mode: 0644]
src/common/make/gcc.mak [new file with mode: 0644]
src/common/make/watcom.mak [new file with mode: 0644]
src/common/objdefs.h [new file with mode: 0644]
src/common/optdefs.h [new file with mode: 0644]
src/common/segdefs.h [new file with mode: 0644]
src/common/symdefs.h [new file with mode: 0644]
src/common/version.h [new file with mode: 0644]
src/geos/headergen.sh [new file with mode: 0755]
src/ld65/.cvsignore [new file with mode: 0644]
src/ld65/bin.c [new file with mode: 0644]
src/ld65/bin.h [new file with mode: 0644]
src/ld65/binfmt.c [new file with mode: 0644]
src/ld65/binfmt.h [new file with mode: 0644]
src/ld65/config.c [new file with mode: 0644]
src/ld65/config.h [new file with mode: 0644]
src/ld65/dbgsyms.c [new file with mode: 0644]
src/ld65/dbgsyms.h [new file with mode: 0644]
src/ld65/error.c [new file with mode: 0644]
src/ld65/error.h [new file with mode: 0644]
src/ld65/exports.c [new file with mode: 0644]
src/ld65/exports.h [new file with mode: 0644]
src/ld65/expr.c [new file with mode: 0644]
src/ld65/expr.h [new file with mode: 0644]
src/ld65/extsyms.c [new file with mode: 0644]
src/ld65/extsyms.h [new file with mode: 0644]
src/ld65/fileio.c [new file with mode: 0644]
src/ld65/fileio.h [new file with mode: 0644]
src/ld65/global.c [new file with mode: 0644]
src/ld65/global.h [new file with mode: 0644]
src/ld65/library.c [new file with mode: 0644]
src/ld65/library.h [new file with mode: 0644]
src/ld65/main.c [new file with mode: 0644]
src/ld65/make/gcc.mak [new file with mode: 0644]
src/ld65/make/watcom.mak [new file with mode: 0644]
src/ld65/mapfile.c [new file with mode: 0644]
src/ld65/mapfile.h [new file with mode: 0644]
src/ld65/mem.c [new file with mode: 0644]
src/ld65/mem.h [new file with mode: 0644]
src/ld65/o65.c [new file with mode: 0644]
src/ld65/o65.h [new file with mode: 0644]
src/ld65/objdata.c [new file with mode: 0644]
src/ld65/objdata.h [new file with mode: 0644]
src/ld65/objfile.c [new file with mode: 0644]
src/ld65/objfile.h [new file with mode: 0644]
src/ld65/scanner.c [new file with mode: 0644]
src/ld65/scanner.h [new file with mode: 0644]
src/ld65/segments.c [new file with mode: 0644]
src/ld65/segments.h [new file with mode: 0644]
src/ld65/target.c [new file with mode: 0644]
src/ld65/target.h [new file with mode: 0644]
src/ld65/version.h [new file with mode: 0644]
src/make/gcc.mak [new file with mode: 0644]
src/make/watcom.mak [new file with mode: 0644]
testcode/compiler/pptest1.c [new file with mode: 0644]
testcode/compiler/pptest2.c [new file with mode: 0644]
testcode/compiler/pptest3.c [new file with mode: 0644]
testcode/compiler/pptest4.c [new file with mode: 0644]
util/atari/ataricvt.c [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..ecfc81b
--- /dev/null
@@ -0,0 +1,2 @@
+dist
+test
diff --git a/doc/BUGS b/doc/BUGS
new file mode 100644 (file)
index 0000000..6863749
--- /dev/null
+++ b/doc/BUGS
@@ -0,0 +1,11 @@
+List of known bugs that will not get fixed in the near future:
+
+  * The compiler does not detect if part of an expression evaluated
+    with && or || is constant. Since the expression evaluation is also
+    used for the preprocessor, this defeats the use of
+
+       #if defined(x) && defined(y)
+
+  * Initialization of local variables with compound data types is not
+    possible.
+
diff --git a/doc/CREDITS b/doc/CREDITS
new file mode 100644 (file)
index 0000000..a43ea63
--- /dev/null
@@ -0,0 +1,62 @@
+
+Many special thanks go to the guy who started it all:
+
+                       John R.Dunning.
+
+Without his great work, there would not be a single freeware C crosscompiler
+for the 6502 out there. He built the grounds for this cc65 and some other cc65
+implementations and a lot of his code is still in the current compiler.
+
+
+More special thanks to:
+
+  * Keith W. Gerdes <kwg@freebird.ghofn.org>
+
+    Without his outstanding help, the assembler/compiler wouldn't be, what it
+    is now. He helped with suggestions, bug reports and even kicked me here
+    and then, when I started to get too lazy:-)
+
+  * Tennessee Carmel-Veilleux <veilleux@ameth.org>
+
+    Tennessee worked on the NES port.
+
+  * Kevin Ruland <kevin@rodin.wustl.edu>
+
+    Kevin did the Apple 2 port and found at least one serious error in the
+    C library while doing so.
+
+  * Christian Groessler <cpg@aladdin.de>
+
+    Christian sent me several fixes for 64 bit machines.
+
+  * Sidney Cadot <sidney@ch.twi.tudelft.nl>
+
+    Sidney rewrote the random number generator.
+
+  * Maciej Witkowiak <ytm@friko.onet.pl>
+
+    Maciej is responsible for the GEOS support.
+
+
+
+Thanks to
+
+    Mark Nasgowitz <MNasgowitz@NAZdesign.com>
+    da Blondie <db@tvnet.hu>
+    Jari Tuominen <jer64@kolumbus.fi>
+    MagerValp <magervalp@cling.gu.se>
+    Ingo Korb <unseen@gmx.net>
+    Robert R. Wal <rrw@reptile.eu.org>
+    Jesse Beach <agmorion@erols.com>
+    Chris Ward <chris.ward@freenet.co.uk>
+    Eric Au <eric_au@hotmail.com>
+    Tim Vanderhoek <hoek@FreeBSD.org>
+    Bill Craig <craigw@gusun.georgetown.edu>
+
+for bug reports and suggestions.
+
+
+This list is probably incomplete. So, if you think you should be mentioned
+here, but cannot find yourself, please drop me a mail.
+
+
diff --git a/doc/ar65.txt b/doc/ar65.txt
new file mode 100644 (file)
index 0000000..ee618e9
--- /dev/null
@@ -0,0 +1,152 @@
+
+
+                                  ar65
+
+                     An Archiver for Object Files Generated by ca65
+
+              (C) Copyright 1998-1999 Ullrich von Bassewitz
+                           (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. Usage
+
+  3. Bugs/Feedback
+
+  4. Copyright
+
+
+
+1. Overview
+-----------
+
+ar65 is a replacement for the libr65 archiver that was part of the cc65 C
+compiler suite developed by John R. Dunning. libr65 had some problems and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite
+for the cc65 compiler. ar65 is part of this suite.
+
+
+
+2. Usage
+--------
+
+The archiver is called as follows:
+
+       Usage: ar65 <operation> lib file|module ...
+       Operation is one of:
+               a       Add modules
+               d       Delete modules
+               l       List library contents
+               x       Extract modules
+               X       Print the archiver version
+
+
+You may add modules to a library using the `a' command. If the library
+does not exist, it is created (and a warning message is printed which you
+may ignore if creation of the library was your intention). You may
+specify any number of modules on the command line following the library.
+
+If a module with the same name exists in the library, it is replaced by
+the new one. The archiver prints a warning, if the module in the library
+has a newer timestamp than the one to add.
+
+Here's an example:
+
+       ar65 a mysubs.lib sub1.o sub2.o
+
+This will add two modules to the library `mysubs.lib' creating the
+library if necessary. If the library contains modules named sub1.o or
+sub2.o, they are replaced by the new ones.
+
+Modules names in the library are stored without the path, so, using
+
+       ar65 a mysubs.lib ofiles/sub1.o ofiles/sub2.o
+
+will add two modules named `sub1.o' and `sub2.o' to the library.
+
+
+Deleting modules from a library is done with the `d' command. You may not
+give a path when naming the modules.
+
+Example:
+
+       ar65 d mysubs.lib sub1.o
+
+This will delete the module named `sub1.o' from the library, printing an
+error if the library does not contain that module.
+
+
+The `l' command prints a list of all modules in the library. Any module
+names on the command line are ignored.
+
+Example:
+
+       ar65 l mysubs.lib
+
+
+Using the `x' command, you may extract modules from the library. The
+modules named on the command line are extracted from the library and put
+into the current directory.
+
+Note: Because of the indexing done by the archiver, the modules may have
+a changed binary layout, that is, a binary compare with the old module
+(before importing it into the library) may yield differences. The
+extracted modules are accepted by the linker and archiver, however, so
+this is not a problem.
+
+Example for extracting a module from the library:
+
+       ar65 x mysubs.lib sub1.o
+
+
+The `V' command prints the version number of the assembler. If you send
+any suggestions or bugfixes, please include your version number.
+
+In addition to these operations, the archiver will check for, and warn
+about duplicate external symbols in the library, every time when an
+operation does update the library. This is only a warning, the linker
+will ignore one of the duplicate symbols (which one is unspecified).
+
+
+
+3. Bugs/Feedback
+----------------
+
+If you have problems using the archiver, if you find any bugs, or if
+you're doing something interesting with it, I would be glad to hear from
+you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+4. Copyright
+------------
+
+ar65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
+
+
+
diff --git a/doc/ca65.txt b/doc/ca65.txt
new file mode 100644 (file)
index 0000000..9c50629
--- /dev/null
@@ -0,0 +1,1903 @@
+
+
+                                  ca65
+
+          A Macro Crossassembler for the 6502/65C02/65816 CPUs
+
+             (C) Copyright 1998-1999 Ullrich von Bassewitz
+                           (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. Usage
+
+  3. Input format
+
+  4. Expressions
+
+  5. Symbols and labels
+
+  6. Control commands
+
+  7. Macros
+
+  8. Macro packages
+
+  9. Bugs/Feedback
+
+  10. Copyright
+
+
+
+1. Overview
+-----------
+
+ca65 is a replacement for the ra65 assembler that was part of the cc65 C
+compiler developed by John R. Dunning. I had some problems with ra65 and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite for
+the cc65 compiler. ca65 is part of this suite.
+
+Some parts of the assembler (code generation and some routines for symbol
+table handling) are taken from an older crossassembler named a816 written
+by me a long time ago.
+
+Here's a list of the design criteria, that were important for the
+development:
+
+  * The assembler must support macros. Macros are not essential, but they
+    make some things easier, especially when you use the assembler in the
+    backend of a compiler.
+
+  * The assembler must support the newer 65C02 and 65816 CPUs. I have been
+    thinking about a 65816 backend for the C compiler, and even my old
+    a816 assembler had support for these CPUs, so this wasn't really a
+    problem.
+
+  * The assembler must produce relocatable code. This necessary for the
+    compiler support, and it is more convenient.
+
+  * Conditional assembly must be supported. This is a must for bigger
+    projects written in assembler (like Elite128).
+
+  * The assembler must support segments, and it must support more than
+    three segments (this is the count, most other assemblers support).
+    Having more than one code segments helps developing code for systems
+    with a divided ROM area (like the C64).
+
+  * The linker must be able to resolve arbitrary expressions. Years ago I
+    spent half a day to convince Borlands Turbo Assembler to let me use
+    the size of a structure I had created. So I decided that this is a
+    must. The linker should be able to get things like
+
+       .import S1, S2
+       .export Special
+       Special         = 2*S1 + S2/7
+
+    right.
+
+  * True lexical nesting for symbols. This is very convenient for larger
+    assembly projects.
+
+  * "Cheap" local symbols without lexical nesting for those quick, late
+    night hacks.
+
+  * I liked the idea of "options" as Anre Fachats .o65 format has it, so I
+    introduced the concept into the object file format use by the new cc65
+    binutils.
+
+  * The assembler will be a one pass assembler. There was no real need for
+    this decision, but I've written several multipass assemblers, and it
+    started to get boring. A one pass assembler needs much more elaborated
+    data structures, and because of that it's much more fun:-)
+    There is one drawback with this point: It is nearly impossible to
+    generate a listing when reading the source file only once without
+    storing the source file in memory. Consequently, the assembler is not
+    able to produce a listing. This could be added by reading the source
+    file a second time if a listing was requested, but I didn't see an
+    urgent need for a listing, so this was not a disadvantage for me.
+
+  * Non-GPLed code that may be used in any project without restrictions or
+    fear of "GPL infecting" other code.
+
+
+
+2. Usage
+--------
+
+The assembler accepts the following options:
+
+       -g              Generate debug info
+       -i              Ignore case of symbols
+        -l              Create a listing if assembly was ok
+       -o name         Name the output file
+       -s              Enable smart mode
+       -v              Increase verbosity
+       -D name[=value] Define a symbol
+       -U              Mark unresolved symbols as import
+       -V              Print the assembler version
+       -W n            Set warning level n
+        --cpu type      Set cpu type
+       --pagelength n  Set the page length for the listing
+        --smart         Enable smart mode
+
+When the -g option (or the equivalent control command .DEBUGINFO) is used,
+the assembler will add a section to the object file that contains all
+symbols (including local ones) together with the symbol values and source
+file positions. The linker will put these additional symbols into the
+VICE label file, so even local symbols can be seen in the VICE monitor.
+
+The option -i makes the assembler case insensitive on identifiers and
+labels. This option will override the default, but may itself be overriden
+by the .CASE control command (see section 6).
+
+The default output name is the name of the input file with the extension
+replaced by ".o". If you don't like that, you may give another name with
+the -o option. The output file will be placed in the same directory as the
+source file, or, if -o is given, the full path in this name is used.
+
+In smart mode (enabled by -s or the .SMART pseudo instruction) the
+assembler will track usage of the REP and SEP instructions in 65816 mode
+and update the operand sizes accordingly. If the operand of such an
+instruction cannot be evaluated by the assembler (for example, because the
+operand is an imported symbol), a warning is issued. Beware: Since the
+assembler cannot trace the execution flow this may lead to false results
+in some cases. If in doubt, use the .ixx and .axx instructions to tell the
+assembler about the current settings. Smart mode is off by default.
+
+-v does increase the assembler verbosity and is usually only needed for
+debugging purposes. You may use this option more than one time for even
+more verbose output.
+
+-D allows you to predefine symbols on the command line. Without a value,
+the symbol is defined with the value zero. When giving a value, you may
+use the '$' prefix for hexadecimal symbols. Please note that for some
+operating systems, '$' has a special meaning, so you may have to quote
+the expression.
+
+-U marks symbols that are not defined in the sources as imported symbols.
+This should be used with care since it delays error messages about typos
+and such until the linker is run. The compiler uses the equivalent of
+this switch (.AUTOIMPORT, see control command section below) to enable
+auto imported symbols for the runtime library. However, the compiler is
+supposed to generate code that runs through the assembler without
+problems, something which is not always true for assembler programmers.
+
+-V prints the version number of the assembler. If you send any suggestions
+or bugfixes, please include your version number.
+
+-Wn sets the warning level for the assembler. Using -W2 the assembler will
+even warn about such things like unused imported symbols. The default
+warning level is 1, and it would probably be silly to set it to something
+lower.
+
+--cpu sets the default for the CPU type. The option takes a parameter,
+which may be one of
+
+       6502, 65C02, 65816 and sunplus
+
+(the latter is not available in the freeware version).
+
+--pagelength sets the length of a listing page in lines. See the
+.PAGELENGTH directive for more information.
+
+--smart is identical to -s - see there.
+
+
+
+3. Input format
+---------------
+
+The assembler accepts the standard 6502/65816 assembler syntax. One line
+may contain a label (which is identified by a colon), and, in addition to
+the label, an assembler mnemonic, a macro, or a control command (see
+section 6 for supported control commands). Alternatively, the line may
+contain a symbol definition using the '=' token. Everything after a
+semicolon is handled as a comment (that is, it is ignored).
+
+Here are some examples for valid input lines:
+
+       Label:                          ; A label and a comment
+               lda     #$20            ; A 6502 instruction plus comment
+       L1:     ldx     #$20            ; Same with label
+       L2:     .byte   "Hello world"   ; Label plus control command
+               mymac   $20             ; Macro expansion
+               MySym = 3*L1            ; Symbol definition
+       MaSym   = Label                 ; Another symbol
+
+The assembler accepts all valid 6502 mnemonics when in 6502 mode (the
+default). The assembler accepts all valid 65SC02 mnemonics when in 65SC02
+mode (after a .PC02 command is found). The assembler accepts all valid
+65816 mnemonics with a few exceptions after a .P816 command is found.
+These exceptions are listed below.
+
+In 65816 mode several aliases are accepted in addition to the official
+mnemonics:
+
+       BGE is an alias for BCS
+       BLT is an alias for BCC
+       CPA is an alias for CMP
+       DEA is an alias for DEC A
+        INA is an alias for INC A
+       SWA is an alias for XBA
+       TAD is an alias for TCD
+       TAS is an alias for TCS
+       TDA is an alias for TDC
+       TSA is an alias for TSC
+
+
+Evaluation of banked expressions in 65816 mode differs slightly from the
+official syntax:
+
+Instead of accepting a 24 bit address (something that is difficult for
+the assembler to determine and would have required one more special
+.import command), the bank and the absolute address in that bank are
+separated by a dot:
+
+       jsl     3.$1234         ; Call subroutine at $1234 in bank 3
+
+For literal values, the assembler accepts the widely used number formats:
+A preceeding '$' denotes a hex value, a preceeding '%' denotes a binary
+value, and a bare number is interpeted as a decimal. There are currently
+no octal values and no floats.
+
+
+
+4. Expressions
+--------------
+
+All expressions are evaluated with (at least) 32 bit precision. An
+expression may contain constant values and any combination of internal and
+external symbols. Expressions that cannot be evaluated at assembly time
+are stored inside the object file for evaluation by the linker.
+Expressions referencing imported symbols must always be evaluated by the
+linker.
+
+Sometimes, the assembler must know about the size of the value that is the
+result of an expression. This is usually the case, if a decision has to be
+made, to generate a zero page or an absolute memory references. In this
+case, the assembler has to make some assumptions about the result of an
+expression:
+
+  * If the result of an expression is constant, the actual value is
+    checked to see if it's a byte sized expression or not.
+
+  * If the expression is explicitly casted to a byte sized expression by
+    one of the '>'/'<' operators, it is a byte expression.
+
+  * If this is not the case, and the expression contains a symbol,
+    explicitly declared as zero page symbol (by one of the .importzp or
+    .exportzp instructions), then the whole expression is assumed to be
+    byte sized.
+
+  * If the expression contains symbols that are not defined, and these
+    symbols are local symbols, the enclosing scopes are searched for a
+    symbol with the same name. If one exists and this symbol is defined,
+    it's attributes are used to determine the result size.
+
+  * In all other cases the expression is assumed to be word sized.
+
+Note: If the assembler is not able to evaluate the expression at assembly
+time, the linker will evaluate it and check for range errors as soon as
+the result is known.
+
+
+Boolean expressions:
+
+In the context of a boolean expression, any non zero value is evaluated as
+true, any other value to false. The result of a boolean expression is 1 if
+it's true, and zero if it's false. There are boolean operators with extrem
+low precedence with version 2.x (where x > 0). The .AND and .OR operators
+are shortcut operators. That is, if the result of the expression is
+already known, after evaluating the left hand side, the right hand side is
+not evaluated.
+
+
+Available operators sorted by precedence:
+
+    Op                 Description                             Precedence
+  -------------------------------------------------------------------
+    *          Builtin pseudo variable (r/o)           1
+    .BLANK     Builtin function                        1
+    .CONST     Builtin function                        1
+    .CPU       Builtin pseudo variable (r/o)           1
+    .DEFINED   Builtin function                        1
+    .MATCH     Builtin function                        1
+    .XMATCH    Builtin function                        1
+    .PARAMCOUNT Builtin pseudo variable        (r/o)           1
+    .REFERENCED Builtin function                       1
+    .STRING    Builtin function                        1
+    ::                 Global namespace override               1
+    +                  Unary plus                              1
+    -                  Unary minus                             1
+    ~                  Unary bitwise not                       1
+    .BITNOT    Unary bitwise not                       1
+    <          Low byte operator                       1
+    >          High byte operator                      1
+
+    *                  Multiplication                          2
+    /                  Division                                2
+    .MOD       Modulo operation                        2
+    &                  Bitwise and                             2
+    .BITAND    Bitwise and                             2
+    ^                  Bitwise xor                             2
+    .BITXOR    Bitwise xor                             2
+    <<                 Shift left operator                     2
+    .SHL       Shift left operator                     2
+    >>                 Shift right operator                    2
+    .SHR       Shift right operator                    2
+
+    +                  Binary plus                             3
+    -                  Binary minus                            3
+    |                  Binary or                               3
+    .BITOR     Binary or                               3
+
+    =                  Compare operation (equal)               4
+    <>                 Compare operation (not equal)           4
+    <                  Compare operation (less)                4
+    >                  Compare operation (greater)             4
+    <=          Compare operation (less or equal)      4
+    >=          Compare operation (greater or equal)    4
+
+    &&         Boolean and                             5
+    .AND       Boolean and                             5
+    .XOR       Boolean xor                             5
+
+    ||         Boolean or                              6
+    .OR                Boolean or                              6
+
+    !                  Boolean not                             7
+    .NOT       Boolean not                             7
+
+
+To force a specific order of evaluation, braces may be used as usual.
+
+Some of the pseudo variables mentioned above need some more explanation:
+
+  *            This symbol is replaced by the value of the program
+               counter at start of the current instruction. Note, that
+               '*' yields a rvalue, that means, you cannot assign to it.
+               Use .ORG to set the program counter in sections with
+               absolute code.
+
+
+
+5. Symbols and labels
+---------------------
+
+The assembler allows you to use symbols instead of naked values to make
+the source more readable. There are a lot of different ways to define and
+use symbols and labels, giving a lot of flexibility.
+
+  - Numeric constants
+
+    Numeric constants are defined using the equal sign. After doing
+
+         two = 2
+
+    may use the symbol "two" in every place where a number is expected,
+    and it is evaluated to the value 2 in this context. An example would be
+
+         four = two * two
+
+
+  - Standard labels
+
+    A label is defined by writing the name of the label at the start of
+    the line (before any instruction mnemonic, macro or pseudo
+    directive), followed by a colon. This will declare a symbol with the
+    given name and the value of the current program counter.
+
+
+  - Local labels and symbols
+
+    Using the .PROC directive, it is possible to create regions of code
+    where the names of labels and symbols are local to this region. They
+    are not know outside and cannot be accessed from there. Such regions
+    may be nested like PROCEDUREs in Pascal.
+
+    See the description of the .PROC directive for more information.
+
+  - Cheap local labels
+
+    Cheap local labels are defined like standard labels, but the name of
+    the label must begin with a special symbol (usually '@', but this can
+    be changed by the .LOCALCHAR directive).
+
+    Cheap local labels are visible only between two no cheap labels. As
+    soon as a standard symbol is encountered (this may also be a local
+    symbol if inside a region defined with the .PROC directive), the
+    cheap local symbol goes out of scope.
+
+    You may use cheap local labels as an easy way to reuse common label
+    names like "Loop". Here is an example:
+
+       Clear:  lda     #$00            ; Global label
+               ldy     #$20
+               @Loop:  sta     Mem,y           ; Local label
+               dey
+               bne     @Loop           ; Ok
+               rts
+       Sub:    ...                     ; New global label
+               bne     @Loop           ; ERROR: Unknown identifier!
+
+  - Unnamed labels
+
+    If you really want to write messy code, there are also unnamed
+    labels. These labels do not have a name (you guessed that already,
+    didn't you?). A colon is used to mark the absence of the name.
+
+    Unnamed labels may be accessed by using the colon plus several minus
+    or plus characters as a label designator. Using the '-' characters
+    will create a back reference (use the n'th label backwards), using
+    '+' will create a forward reference (use the n'th label in forward
+    direction. An example will help to understand this:
+
+               :       lda     (ptr1),y        ; #1
+               cmp     (ptr2),y
+               bne     :+              ; -> #2
+               tax
+               beq     :+++            ; -> #4
+               iny
+               bne     :-              ; -> #1
+               inc     ptr1+1
+               inc     ptr2+1
+               bne     :-              ; -> #1
+
+               :       bcs     :+              ; #2 -> #3
+               ldx     #$FF
+               rts
+
+       :       ldx     #$01            ; #3
+       :       rts                     ; #4
+
+    As you can see from the example, unnamed labels will make even short
+    sections of code hard to understand, because you have to count labels
+    to find branch targets (this is the reason why I for my part do
+    prefer the "cheap" local labels). Nevertheless, unnamed labels are
+    convenient in some situations, so it's your decision.
+
+  - Using macros to define labels and constants
+
+    While there are drawbacks with this approach, it may be handy in some
+    situations. Using .DEFINE, it is possible to define symbols or
+    constants that may be used elsewhere. Since the macro facility works
+    on a very low level, there is no scoping. On the other side, you may
+    also define string constants this way (this is not possible with the
+    other symbol types).
+
+    Example:
+
+       .DEFINE two     2
+       .DEFINE version "SOS V2.3"
+
+       four = two * two        ; Ok
+       .byte   version         ; Ok
+
+       .PROC                   ; Start local scope
+       two = 3                 ; Will give "2 = 3" - invalid!
+       .ENDPROC
+
+
+If .DEBUGINFO is enabled (or -g is given on the command line), global,
+local and cheap local labels are written to the object file and will be
+available in the symbol file via the linker. Unnamed labels are not
+written to the object file, because they don't have a name which would
+allow to access them.
+
+
+
+6. Control commands
+-------------------
+
+Here's a list of all control commands and a description, what they do:
+
+
+.A16
+
+  Valid only in 65816 mode. Switch the accumulator to 16 bit.
+
+  Note: This command will not emit any code, it will tell the assembler to
+  create 16 bit operands for immediate accumulator adressing mode.
+
+  See also: .SMART
+
+
+.A8
+
+  Valid only in 65816 mode. Switch the accumulator to 8 bit.
+
+  Note: This command will not emit any code, it will tell the assembler to
+  create 8 bit operands for immediate accu adressing mode.
+
+  See also: .SMART
+
+
+.ADDR
+
+  Define word sized data. In 6502 mode, this is an alias for .WORD and
+  may be used for better readability if the data words are address values.
+  In 65816 mode, the address is forced to be 16 bit wide to fit into the
+  current segment. See also .FARADDR. The command must be followed by a
+  sequence of (not necessarily constant) expressions.
+
+  Example:
+
+       .addr   $0D00, $AF13, _Clear
+
+
+.ALIGN
+
+  Align data to a given boundary. The command expects a constant integer
+  argument that must be a power of two, plus an optional second argument
+  in byte range. If there is a second argument, it is used as fill value,
+  otherwise the value defined in the linker configuration file is used
+  (the default for this value is zero).
+
+  Since alignment depends on the base address of the module, you must
+  give the same (or a greater) alignment for the segment when linking.
+  The linker will give you a warning, if you don't do that.
+
+  Example:
+
+       .align  256
+
+
+.ASCIIZ
+
+  Define a string with a trailing zero.
+
+  Example:
+
+       Msg:    .asciiz "Hello world"
+
+  This will put the string "Hello world" followed by a binary zero into
+  the current segment. There may be more strings separated by commas, but
+  the binary zero is only appended once (after the last one).
+
+
+.AUTOIMPORT
+
+  Is followd by a plus or a minus character. When switched on (using a
+  +), undefined symbols are automatically marked as import instead of
+  giving errors. When switched off (which is the default so this does not
+  make much sense), this does not happen and an error message is
+  displayed. The state of the autoimport flag is evaluated when the
+  complete source was translated, before outputing actual code, so it is
+  *not* possible to switch this feature on or off for separate sections of
+  code. The last setting is used for all symbols.
+
+  You should probably not use this switch because it delays error
+  messages about undefined symbols until the link stage. The cc65
+  compiler (which is supposed to produce correct assembler code in all
+  circumstances, something which is not true for most assembler
+  programmers) will insert this command to avoid importing each and every
+  routine from the runtime library.
+
+  Example:
+
+       .autoimport     +       ; Switch on auto import
+
+
+.BLANK
+
+  Builtin function. The function evaluates its argument in braces and
+  yields "false" if the argument is non blank (there is an argument), and
+  "true" if there is no argument. As an example, the .IFBLANK statement
+  may be replaced by
+
+       .if     .blank(arg)
+
+
+.BSS
+
+  Switch to the BSS segment. The name of the BSS segment is always "BSS",
+  so this is a shortcut for
+
+       .segment  "BSS"
+
+  See also the .SEGMENT command.
+
+
+.BYTE
+
+  Define byte sized data. Must be followed by a sequence of (byte ranged)
+  expressions or strings.
+
+  Example:
+
+       .byte   "Hello world", $0D, $00
+
+
+.CASE
+
+  Switch on or off case sensitivity on identifiers. The default is off
+  (that is, identifiers are case sensitive), but may be changed by the
+  -i switch on the command line.
+  The command must be followed by a '+' or '-' character to switch the
+  option on or off respectively.
+
+  Example:
+
+               .case   -               ; Identifiers are not case sensitive
+
+
+.CODE
+
+  Switch to the CODE segment. The name of the CODE segment is always
+  "CODE", so this is a shortcut for
+
+               .segment  "CODE"
+
+  See also the .SEGMENT command.
+
+
+.CONST
+
+  Builtin function. The function evaluates its argument in braces and
+  yields "true" if the argument is a constant expression (that is, an
+  expression that yields a constant value at assembly time) and "false"
+  otherwise. As an example, the .IFCONST statement may be replaced by
+
+       .if     .const(a + 3)
+
+
+.CPU
+
+  Reading this pseudo variable will give a constant integer value that
+  tells which instruction set is currently enabled. Possible values are:
+
+       0 -->   6502
+       1 -->   65SC02
+       2 -->   65SC816
+       3 -->   SunPlus SPC
+
+  It may be used to replace the .IFPxx pseudo instructions or to construct
+  even more complex expressions.
+
+  Example:
+
+       .if     (.cpu = 0) .or (.cpu = 1)
+               txa
+               pha
+               tya
+               pha
+       .else
+               phx
+               phy
+       .endif
+
+
+.DATA
+
+  Switch to the DATA segment. The name of the DATA segment is always
+  "DATA", so this is a shortcut for
+
+               .segment  "DATA"
+
+  See also the .SEGMENT command.
+
+
+.DBYT
+
+  Define word sized data with the hi and lo bytes swapped (use .WORD to
+  create word sized data in native 65XX format). Must be followed by a
+  sequence of (word ranged) expressions.
+
+  Example:
+
+       .dbyt   $1234, $4512
+
+  This will emit the bytes
+
+       $12 $34 $45 $12
+
+  into the current segment in that order.
+
+
+.DEBUGINFO
+
+  Switch on or off debug info generation. The default is off (that is,
+  the object file will not contain debug infos), but may be changed by the
+  -g switch on the command line.
+  The command must be followed by a '+' or '-' character to switch the
+  option on or off respectively.
+
+  Example:
+
+               .debuginfo      +       ; Generate debug info
+
+
+.DEFINE
+
+  Start a define style macro definition. The command is followed by an
+  identifier (the macro name) and optionally by a list of formal arguments
+  in braces.
+  See separate section about macros.
+
+
+.DEF
+.DEFINED
+
+  Builtin function. The function expects an identifier as argument in
+  braces. The argument is evaluated, and the function yields "true" if the
+  identifier is a symbol that is already defined somewhere in the source
+  file up to the current position. Otherwise the function yields false. As
+  an example, the .IFDEF statement may be replaced by
+
+       .if     .defined(a)
+
+
+.DWORD
+
+  Define dword sized data (4 bytes) Must be followed by a sequence of
+  expressions.
+
+  Example:
+
+               .dword  $12344512, $12FA489
+
+
+.ELSE
+
+  Conditional assembly: Reverse the current condition.
+
+
+.ELSEIF
+
+  Conditional assembly: Reverse current condition and test a new one.
+
+
+.END
+
+  Forced end of assembly. Assembly stops at this point, even if the command
+  is read from an include file.
+
+
+.ENDIF
+
+  Conditional assembly: Close a .IF... or .ELSE branch.
+
+
+.ENDMAC
+.ENDMACRO
+
+  End of macro definition (see separate section).
+
+
+.ENDPROC
+
+  End of local lexical level (see .PROC).
+
+
+.ERROR
+
+  Force an assembly error. The assembler will output an error message
+  preceeded by "User error" and will *not* produce an object file.
+
+  This command may be used to check for initial conditions that must be
+  set before assembling a source file.
+
+  Example:
+
+       .if     foo = 1
+       ...
+       .elseif bar = 1
+       ...
+       .else
+       .error  "Must define foo or bar!"
+       .endif
+
+
+.EXITMAC
+.EXITMACRO
+
+  Abort a macro expansion immidiately. This command is often useful in
+  recursive macros. See separate chapter about macros.
+
+
+.EXPORT
+
+  Make symbols accessible from other modules. Must be followed by a comma
+  separated list of symbols to export.
+
+  Example:
+
+       .export foo, bar
+
+
+.EXPORTZP
+
+  Make symbols accessible from other modules. Must be followed by a comma
+  separated list of symbols to export. The exported symbols are explicitly
+  marked as zero page symols.
+
+  Example:
+
+       .exportzp  foo, bar
+
+
+.FARADDR
+
+  Define far (24 bit) address data. The command must be followed by a
+  sequence of (not necessarily constant) expressions.
+
+  Example:
+
+       .faraddr        DrawCircle, DrawRectangle, DrawHexagon
+
+
+.FEATURE
+
+  This directive may be used to enable one or more compatibility features
+  of the assembler. While the use of .FEATURE should be avoided when
+  possible, it may be useful when porting sources written for other
+  assemblers. There is no way to switch a feature off, once you have
+  enabled it, so using
+
+               .FEATURE        xxx
+
+  will enable the feature until end of assembly is reached.
+
+  The following features are available:
+
+  dollar_is_pc
+
+    The dollar sign may be used as an alias for the star (`*'), which
+    gives the value of the current PC in expressions.
+    Note: Assignment to the pseudo variable is not allowed.
+
+  labels_without_colons
+
+    Allow labels without a trailing colon. These labels are only accepted,
+    if they start at the beginning of a line (no leading white space).
+
+  loose_string_term
+
+    Accept single quotes as well as double quotes as terminators for string
+    constants.
+
+  at_in_identifiers
+
+    Accept the at character (`@') as a valid character in identifiers. The
+    at character is not allowed to start an identifier, even with this
+    feature enabled.
+
+  dollar_in_identifiers
+
+    Accept the dollar sign (`$') as a valid character in identifiers. The
+    at character is not allowed to start an identifier, even with this
+    feature enabled.
+
+
+.FILEOPT
+.FOPT
+
+  Insert an option string into the object file. There are two forms of
+  this command, one specifies the option by a keyword, the second
+  specifies it as a number. Since usage of the second one needs knowledge
+  of the internal encoding, its use is not recommended and I will only
+  describe the first form here.
+
+  The command is followed by one of the keywords
+
+       author
+       comment
+       compiler
+
+  a comma and a string. The option is written into the object file
+  together with the string value. This is currently unidirectional and
+  there is no way to actually use these options once they are in the
+  object file.
+
+  Examples:
+
+       .fileopt        comment, "Code stolen from my brother"
+       .fileopt        compiler, "BASIC 2.0"
+       .fopt           author, "J. R. User"
+
+
+.GLOBAL
+
+  Declare symbols as global. Must be followed by a comma separated list
+  of symbols to declare. Symbols from the list, that are defined somewhere
+  in the source, are exported, all others are imported. An additional
+  explicit .IMPORT or .EXPORT command for the same symbol is allowed.
+
+  Example:
+
+       .global foo, bar
+
+
+.GLOBALZP
+
+  Declare symbols as global. Must be followed by a comma separated list
+  of symbols to declare. Symbols from the list, that are defined
+  somewhere in the source, are exported, all others are imported. An
+  additional explicit .IMPORT or .EXPORT command for the same symbol is
+  explicitly allowed. The symbols in the list are explicitly marked as
+  zero page symols.
+
+  Example:
+
+               .globalzp foo, bar
+
+
+.I16
+
+  Valid only in 65816 mode. Switch the index registers to 16 bit.
+
+  Note: This command will not emit any code, it will tell the assembler to
+  create 16 bit operands for immediate operands.
+
+  See also:
+
+       .SMART
+
+
+.I8
+
+  Valid only in 65816 mode. Switch the index registers to 8 bit.
+
+  Note: This command will not emit any code, it will tell the assembler to
+  create 8 bit operands for immediate operands.
+
+  See also:
+
+       .SMART
+
+
+.IF
+
+  Conditional assembly: Evalute an expression and switch assembler output
+  on or off depending on the expression. The expression must be a constant
+  expression, that is, all operands must be defined.
+
+  A expression value of zero evaluates to FALSE, any other value evaluates
+  to TRUE.
+
+
+.IFBLANK
+
+  Conditional assembly: Check if there are any remaining tokens in this
+  line, and evaluate to FALSE if this is the case, and to TRUE otherwise.
+  If the condition is not true, further lines are not assembled until
+  an .ELSE, .ELSEIF or .ENDIF directive.
+
+  This command is often used to check if a macro parameter was given.
+  Since an empty macro parameter will evaluate to nothing, the condition
+  will evaluate to FALSE if an empty parameter was given.
+
+  Example:
+
+       .macro     arg1, arg2
+       .ifblank   arg2
+                  lda     #arg1
+       .else
+                  lda     #arg2
+       .endif
+       .endmacro
+
+  See also:
+
+       .BLANK
+
+
+.IFCONST
+
+  Conditional assembly: Evaluate an expression and switch assembler output
+  on or off depending on the constness of the expression.
+
+  A const expression evaluates to to TRUE, a non const expression (one
+  containing an imported or currently undefined symbol) evaluates to
+  FALSE.
+
+  See also:
+
+       .CONST
+
+
+.IFDEF
+
+  Conditional assembly: Check if a symbol is defined. Must be followed by
+  a symbol name. The condition is true if the the given symbol is already
+  defined, and false otherwise.
+
+  See also:
+
+       .DEFINED
+
+
+.IFNBLANK
+
+  Conditional assembly: Check if there are any remaining tokens in this
+  line, and evaluate to TRUE if this is the case, and to FALSE otherwise.
+  If the condition is not true, further lines are not assembled until
+  an .ELSE, .ELSEIF or .ENDIF directive.
+
+  This command is often used to check if a macro parameter was given.
+  Since an empty macro parameter will evaluate to nothing, the condition
+  will evaluate to FALSE if an empty parameter was given.
+
+  Example:
+
+       .macro     arg1, arg2
+                  lda     #arg1
+       .ifnblank  arg2
+                  lda     #arg2
+       .endif
+       .endmacro
+
+  See also:
+
+       .BLANK
+
+
+.IFNDEF
+
+  Conditional assembly: Check if a symbol is defined. Must be followed by
+  a symbol name. The condition is true if the the given symbol is not
+  defined, and false otherwise.
+
+  See also:
+
+       .DEFINED
+
+
+.IFNREF
+
+  Conditional assembly: Check if a symbol is referenced. Must be followed
+  by a symbol name. The condition is true if if the the given symbol was
+  not referenced before, and false otherwise.
+
+  See also:
+
+       .REFERENCED
+
+
+.IFP02
+
+  Conditional assembly: Check if the assembler is currently in 6502 mode
+  (see .P02 command).
+
+
+.IFP816
+
+  Conditional assembly: Check if the assembler is currently in 65816 mode
+  (see .P816 command).
+
+
+.IFPC02
+
+  Conditional assembly: Check if the assembler is currently in 65C02 mode
+  (see .PC02 command).
+
+
+.IFREF
+
+  Conditional assembly: Check if a symbol is referenced. Must be followed
+  by a symbol name. The condition is true if if the the given symbol was
+  referenced before, and false otherwise.
+
+  This command may be used to build subroutine libraries in include files
+  (you may use separate object modules for this purpose too).
+
+  Example:
+
+       .ifdef  ToHex                   ; If someone used this subroutine
+       ToHex:  tay                     ; Define subroutine
+               lda     HexTab,y
+               rts
+       .endif
+
+  See also:
+
+       .REFERENCED
+
+
+.IMPORT
+
+  Import a symbol from another module. The command is followed by a comma
+  separated list of symbols to import.
+
+  Example:
+
+       .import foo, bar
+
+
+.IMPORTZP
+
+  Import a symbol from another module. The command is followed by a comma
+  separated list of symbols to import. The symbols are explicitly imported
+  as zero page symbols (that is, symbols with values in byte range).
+
+  Example:
+
+       .includezp  foo, bar
+
+
+.INCBIN
+
+  Include a file as binary data. The command expects a string argument
+  that is the name of a file to include literally in the current segment.
+
+  Example:
+
+       .incbin         "sprites.dat"
+
+
+.INCLUDE
+
+  Include another file. Include files may be nested up to a depth of 16.
+
+  Example:
+
+       .include        "subs.inc"
+
+
+.LINECONT
+
+  Switch on or off line continuations using the backslash character
+  before a newline. The option is off by default.
+  Note: Line continuations do not work in a comment. A backslash at the
+  end of a comment is treated as part of the comment and does not trigger
+  line continuation.
+  The command must be followed by a '+' or '-' character to switch the
+  option on or off respectively.
+
+  Example:
+
+               .linecont       +               ; Allow line continuations
+
+       lda     \
+               #$20                    ; This is legal now
+
+
+.LIST
+
+  Enable output to the listing. The command must be followed by a boolean
+  switch ("on", "off", "+" or "-") and will enable or disable listing
+  output.
+  The option has no effect if the listing is not enabled by the command line
+  switch -l. If -l is used, an internal counter is set to 1. Lines are output
+  to the listing file, if the counter is greater than zero, and suppressed if
+  the counter is zero. Each use of .LIST will increment or decrement the
+  counter.
+
+  Example:
+
+               .list   on              ; Enable listing output
+
+
+.LISTBYTES
+
+  Set, how many bytes are shown in the listing for one source line. The
+  default is 12, so the listing will show only the first 12 bytes for any
+  source line that generates more than 12 bytes of code or data.
+  The directive needs an argument, which is either "unlimited", or an
+  integer constant in the range 4..255.
+
+  Examples:
+
+               .listbytes      unlimited       ; List all bytes
+       .listbytes      12              ; List the first 12 bytes
+       .incbin         "data.bin"      ; Include large binary file
+
+
+.LOCAL
+
+  This command may only be used inside a macro definition. It declares a
+  list of identifiers as local to the macro expansion.
+
+  A problem when using macros are labels: Since they don't change their
+  name, you get a "duplicate symbol" error if the macro is expanded the
+  second time. Labels declared with .LOCAL have their name mapped to an
+  internal unique name (___ABCD__) with each macro invocation.
+
+  Some other assemblers start a new lexical block inside a macro
+  expansion. This has some drawbacks however, since that will not allow
+  *any* symbol to be visible outside a macro, a feature that is sometimes
+  useful. The .LOCAL command is in my eyes a better way to address the
+  problem.
+
+  You get an error when using .LOCAL outside a macro.
+
+
+.LOCALCHAR
+
+  Defines the character that start "cheap" local labels. You may use one
+  of '@' and '?' as start character. The default is '@'.
+
+  Cheap local labels are labels that are visible only between two non
+  cheap labels. This way you can reuse identifiers like "loop" without
+  using explicit lexical nesting.
+
+  Example:
+
+               .localchar      '?'
+
+       Clear:  lda     #$00            ; Global label
+               ?Loop:  sta     Mem,y           ; Local label
+               dey
+               bne     ?Loop           ; Ok
+               rts
+       Sub:    ...                     ; New global label
+               bne     ?Loop           ; ERROR: Unknown identifier!
+
+
+.MACPACK
+
+  Insert a predefined macro package. The command is followed by an
+  identifier specifying the macro package to insert. Available macro
+  packages are:
+
+       generic         Defines generic macros like add and sub.
+       longbranch      Defines conditional long jump macros.
+
+  Including a macro package twice, or including a macro package that
+  redefines already existing macros will lead to an error.
+
+  Example:
+
+               .macpack        longbranch      ; Include macro package
+
+                       cmp     #$20            ; Set condition codes
+                       jne     Label           ; Jump long on condition
+
+  See separate section about macros packages.
+
+
+.MAC
+.MACRO
+
+  Start a classic macro definition. The command is followed by an identifier
+  (the macro name) and optionally by a comma separated list of identifiers
+  that are macro parameters.
+  See separate section about macros.
+
+
+.MATCH
+
+  Builtin function. Matches two token lists against each other. This is
+  most useful within macros, since macros are not stored as strings, but
+  as lists of tokens.
+
+  The syntax is
+
+               .MATCH(<token list #1>, <token list #2>)
+
+  Both token list may contain arbitrary tokens with the exception of the
+  terminator token (comma resp. right parenthesis) and
+
+    * end-of-line
+    * end-of-file
+
+  Often a macro parameter is used for any of the token lists.
+
+  Please note that the function does only compare tokens, not token
+  attributes. So any number is equal to any other number, regardless of
+  the actual value. The same is true for strings.
+
+  Example:
+
+    Assume the macro ASR , that will shift right the accumulator by one,
+    while honoring the sign bit. The builtin processor instructions will
+    allow an optional "A" for accu addressing for instructions like ROL
+    and ROR. We will use the .MATCH function to check for this and print
+    and error for invalid calls.
+
+       .macro  asr     arg
+
+                       .if (.not .blank(arg)) .and (.not .match (arg, a))
+               .error "Syntax error"
+               .endif
+
+               cmp     #$80            ; Bit 7 into carry
+               lsr     a               ; Shit carry into bit 7
+
+       .endmacro
+
+    The macro will only accept no arguments, or one argument that must
+    be the reserved keyword "A".
+
+
+.ORG
+
+  Start a section of absolute code. The command is followed by a constant
+  expression that gives the new PC counter location for which the code is
+  assembled. Use .RELOC to switch back to relocatable code.
+
+  You may not switch segments while inside a section of absolute code.
+
+  Example:
+
+       .org    $7FF            ; Emit code starting at $7FF
+
+
+.OUT
+
+  Output a string to the console without producing an error. This command
+  is similiar to .ERROR, however, it does not force an assembler error
+  that prevents the creation of an object file.
+
+  Example:
+
+       .out    "This code was written by the codebuster(tm)"
+
+
+.P02
+
+  Enable the 6502 instruction set, disable 65C02 and 65816 instructions.
+  This is the default if not overridden by the --cpu command line option.
+
+
+.P816
+
+  Enable the 65816 instruction set. This is a superset of the 65C02 and
+  6502 instruction sets.
+
+
+.PAGELEN
+.PAGELENGTH
+
+  Set the page length for the listing. Must be followed by an integer
+  constant. The value may be "unlimited", or in the range 32 to 127. The
+  statement has no effect if no listing is generated. The default value
+  is -1 but may be overridden by the --pagelength command line option.
+  Beware: Since the listing is generated after assembly is complete, you
+  cannot use multiple line lengths with one source. Instead, the value
+  set with the last .PAGELENGTH is used.
+
+  Examples:
+
+       .pagelength     66              ; Use 66 lines per listing page
+
+       .pagelength     unlimited       ; Unlimited page length
+
+
+.PARAMCOUNT
+
+  This builtin pseudo variable is only available in macros. It is replaced
+  by the actual number of parameters that were given in the macro
+  invocation.
+
+  Example:
+
+       .macro  foo     arg1, arg2, arg3
+       .if     .paramcount <> 3
+       .error  "Too few parameters for macro foo"
+       .endif
+       ...
+       .endmacro
+
+
+.PC02
+
+  Enable the 65C02 instructions set. This instruction set includes all
+  6502 instructions.
+
+
+.PROC
+
+  Start a nested lexical level. All new symbols from now on are in the
+  local lexical level and are not accessible from outside. Symbols defined
+  outside this local level may be accessed as long as their names are not
+  used for new symbols inside the level. Symbols names in other lexical
+  levels do not clash, so you may use the same names for identifiers. The
+  lexical level ends when the .ENDPROC command is read. Lexical levels may
+  be nested up to a depth of 16.
+
+  The command may be followed by an identifier, in this case the
+  identifier is declared in the outer level as a label having the value of
+  the program counter at the start of the lexical level.
+
+  Note: Macro names are always in the global level and in a separate name
+  space. There is no special reason for this, it's just that I've never
+  had any need for local macro definitions.
+
+  Example:
+
+               .proc   Clear           ; Define Clear subroutine, start new level
+               lda     #$00
+       L1:     sta     Mem,y   ; L1 is local and does not cause a
+                                       ; duplicate symbol error if used in other
+                               ; places
+               dey
+               bne     L1      ; Reference local symbol
+               rts
+       .endproc                ; Leave lexical level
+
+
+.REF
+.REFERENCED
+
+  Builtin function. The function expects an identifier as argument in
+  braces. The argument is evaluated, and the function yields "true" if the
+  identifier is a symbol that has already been referenced somewhere in the
+  source file up to the current position. Otherwise the function yields
+  false. As an example, the .IFREF statement may be replaced by
+
+       .if     .referenced(a)
+
+
+.RELOC
+
+  Switch back to relocatable mode. See the .ORG command.
+
+
+.RES
+
+  Reserve storage. The command is followed by one or two constant
+  expressions. The first one is mandatory and defines, how many bytes of
+  storage should be defined. The second, optional expression must by a
+  constant byte value that will be used as value of the data. If there
+  is no fill value given, the linker will use the value defined in the
+  linker configuration file (default: zero).
+
+  Example:
+
+       ; Reserve 12 bytes of memory with value $AA
+       .res    12, $AA
+
+
+.RODATA
+
+  Switch to the RODATA segment. The name of the RODATA segment is always
+  "RODATA", so this is a shortcut for
+
+               .segment  "RODATA"
+
+  The RODATA segment is a segment that is used by the compiler for
+  readonly data like string constants. See also the .SEGMENT command.
+
+
+.SEGMENT
+
+  Switch to another segment. Code and data is always emitted into a
+  segment, that is, a named section of data. The default segment is
+  "CODE". There may be up to 254 different segments per object file
+  (and up to 65534 per executable). There are shortcut commands for
+  the most common segments ("CODE", "DATA" and "BSS").
+
+  The command is followed by a string containing the segment name (there
+  are some constraints for the name - as a rule of thumb use only those
+  segment names that would also be valid identifiers). There may also be
+  an optional attribute separated by a comma. Valid attributes are
+
+       zeropage
+  and  absolute
+
+  When specifying a segment for the first time, "absolute" is the
+  default. For all other uses, the attribute specified the first time
+  is the default.
+
+  "absolute" means that this is a segment with absolute addressing. That
+  is, the segment will reside somewhere in core memory outside the zero
+  page. "zeropage" means the opposite: The segment will be placed in the
+  zero page and direct (short) addressing is possible for data in this
+  segment.
+
+  Beware: Only labels in a segment with the zeropage attribute are marked
+  as reachable by short addressing. The `*' (PC counter) operator will
+  work as in other segments and will create absolute variable values.
+
+  Example:
+
+               .segment "ROM2"                 ; Switch to ROM2 segment
+       .segment "ZP2", zeropage        ; New direct segment
+       .segment "ZP2"                  ; Ok, will use last attribute
+       .segment "ZP2", absolute        ; Error, redecl mismatch
+
+
+.SMART
+
+  Switch on or off smart mode. The command must be followed by a '+' or
+  '-' character to switch the option on or off respectively. The default
+  is off (that is, the assembler doesn't try to be smart), but this
+  default may be changed by the -s switch on the command line.
+
+  In smart mode the assembler will track usage of the REP and SEP
+  instructions in 65816 mode and update the operand sizes accordingly. If
+  the operand of such an instruction cannot be evaluated by the assembler
+  (for example, because the operand is an imported symbol), a warning is
+  issued. Beware: Since the assembler cannot trace the execution flow this
+  may lead to false results in some cases. If in doubt, use the .ixx and
+  .axx instructions to tell the assembler about the current settings.
+
+  Example:
+
+       .smart                          ; Be smart
+       .smart  -                       ; Stop being smart
+
+
+.STRING
+
+  Builtin function. The function accepts an argument in braces and
+  converts this argument into a string constant. The argument may be an
+  identifier, or a constant numeric value.
+  Since you can use a string in the first place, the use of the function
+  may not be obvious. However, it is useful in macros, or more complex
+  setups.
+
+  Example:
+
+       ; Emulate other assemblers:
+       .macro  section name
+               .segment        .string(name)
+       .endmacro
+
+
+.WORD
+
+  Define word sized data. Must be followed by a sequence of (word ranged,
+  but not necessarily constant) expressions.
+
+  Example:
+
+       .word   $0D00, $AF13, _Clear
+
+
+.ZEROPAGE
+
+  Switch to the ZEROPAGE segment and mark it as direct (zeropage) segment.
+  The name of the ZEROPAGE segment is always "ZEROPAGE", so this is a
+  shortcut for
+
+               .segment  "ZEROPAGE", zeropage
+
+  Because of the "zeropage" attribute, labels declared in this segment are
+  addressed using direct addressing mode if possible. You MUST instruct
+  the linker to place this segment somewhere in the address range 0..$FF
+  otherwise you will get errors.
+
+
+
+7. Macros
+---------
+
+Macros may be thought of as "parametrized super instructions". Macros are
+sequences of tokens that have a name. If that name is used in the source
+file, the macro is "expanded", that is, it is replaced by the tokens that
+were specified when the macro was defined.
+
+In it's simplest form, a macro does not have parameters. Here's an
+example:
+
+               .macro  asr             ; Arithmetic shift right
+               cmp     #$80    ; Put bit 7 into carry
+               ror             ; Rotate right with carry
+       .endmacro
+
+The macro above consists of two real instructions, that are inserted into
+the code, whenever the macro is expanded. Macro expansion is simply done
+by using the name, like this:
+
+       lda     $2010
+       asr
+       sta     $2010
+
+
+When using macro parameters, macros can be even more useful:
+
+       .macro  inc16   addr
+               clc
+               lda     addr
+               adc     #$01
+               sta     addr
+               lda     addr+1
+               adc     #$00
+               sta     addr+1
+       .endmacro
+
+When calling the macro, you may give a parameter, and each occurence of
+the name "addr" in the macro definition will be replaced by the given
+parameter. So
+
+       inc16   $1000
+
+will be expanded to
+
+               clc
+               lda     $1000
+               adc     #$01
+               sta     $1000
+               lda     $1000+1
+               adc     #$00
+               sta     $1000+1
+
+A macro may have more than one parameter, in this case, the parameters
+are separated by commas. You are free to give less parameters than the
+macro actually takes in the definition. You may also leave intermediate
+parameters empty. Empty parameters are replaced by empty space (that is,
+they are removed when the macro is exanded). If you have a look at our
+macro definition above, you will see, that replacing the "addr" parameter
+by nothing will lead to wrong code in most lines. To help you, writing
+macros with a variable parameter list, there are some control commands:
+
+.IFBLANK tests the rest of the line and returns true, if there are any
+tokens on the remainder of the line. Since empty parameters are replaced
+by nothing, this may be used to test if a given parameter is empty.
+.IFNBLANK tests the opposite.
+
+Look at this example:
+
+       .macro  ldaxy   a, x, y
+       .ifnblank       a
+               lda     #a
+       .endif
+       .ifnblank       x
+               ldx     #x
+       .endif
+       .ifnblank       y
+               ldy     #y
+       .endif
+       .endmacro
+
+This macro may be called as follows:
+
+       ldaxy   1, 2, 3         ; Load all three registers
+
+       ldaxy   1, , 3          ; Load only a and y
+
+       ldaxy   , , 3           ; Load y only
+
+There's another helper command for determining, which macro parameters are
+valid: .PARAMCOUNT. This command is replaced by the parameter count given,
+*including* intermediate empty macro parameters:
+
+       ldaxy   1               ; .PARAMCOUNT = 1
+       ldaxy   1,,3            ; .PARAMCOUNT = 3
+       ldaxy   1,2             ; .PARAMCOUNT = 2
+       ldaxy   1,              ; .PARAMCOUNT = 2
+       ldaxy   1,2,3           ; .PARAMCOUNT = 3
+
+Macros may be used recursively:
+
+       .macro  push    r1, r2, r3
+               lda     r1
+               pha
+       .if     .paramcount > 1
+               push    r2, r3
+       .endif
+       .endmacro
+
+There's also a special macro to help writing recursive macros: .EXITMACRO.
+This command will stop macro expansion immidiately:
+
+       .macro  push    r1, r2, r3, r4, r5, r6, r7
+       .ifblank        r1
+               ; First parameter is empty
+               .exitmacro
+       .else
+               lda     r1
+               pha
+       .endif
+               push    r2, r3, r4, r5, r6, r7
+       .endmacro
+
+When expanding this macro, the expansion will push all given parameters
+until an empty one is encountered. The macro may be called like this:
+
+       push    $20, $21, $32           ; Push 3 ZP locations
+       push    $21                     ; Push one ZP location
+
+Now, with recursive macros, .IFBLANK and .PARAMCOUNT, what else do you need?
+Have a look at the inc16 macro above. Here is it again:
+
+       .macro  inc16   addr
+               clc
+               lda     addr
+               adc     #$01
+               sta     addr
+               lda     addr+1
+               adc     #$00
+               sta     addr+1
+       .endmacro
+
+If you have a closer look at the code, you will notice, that it could be
+written more efficiently, like this:
+
+       .macro  inc16   addr
+               clc
+               lda     addr
+               adc     #$01
+               sta     addr
+               bcc     Skip
+               inc     addr+1
+       Skip:
+       .endmacro
+
+But imagine what happens, if you use this macro twice? Since the label
+"Skip" has the same name both times, you get a "duplicate symbol" error.
+Without a way to circumvent this problem, macros are not as useful, as
+they could be. One solution is, to start a new lexical block inside the
+macro:
+
+       .macro  inc16   addr
+       .proc
+               clc
+               lda     addr
+               adc     #$01
+               sta     addr
+               bcc     Skip
+               inc     addr+1
+       Skip:
+       .endproc
+       .endmacro
+
+Now the label is local to the block and not visible outside. However,
+sometimes you want a label inside the macro to be visible outside. To make
+that possible, there's a new command that's only usable inside a macro
+definition: .LOCAL. .LOCAL declares one or more symbols as local to the
+macro expansion. The names of local variables are replaced by a unique
+name in each separate macro expansion. So we could also solve the problem
+above by using .LOCAL:
+
+       .macro  inc16   addr
+                       .local  Skip            ; Make Skip a local symbol
+               clc
+               lda     addr
+               adc     #$01
+               sta     addr
+               bcc     Skip
+               inc     addr+1
+       Skip:                           ; Not visible outside
+       .endmacro
+
+Starting with version 2.5 of the assembler, there is a second macro type
+available: C style macros using the .DEFINE directive. These macros are
+similar to the classic macro type speified above, but behaviour is
+sometimes different:
+
+  * Macros defined with .DEFINE may not span more than a line. You may
+    use line continuation (.LINECONT) to spread the definition over more
+    than one line for increased readability, but the macro itself does
+    not contain an end-of-line token.
+
+  * Macros defined with .DEFINE share the name space with classic macros,
+    but they are detected and replaced at the scanner level. While classic
+    macros may be used in every place, where a mnemonic or other directive
+    is allowed, .DEFINE style macros are allowed anywhere in a line. So
+    they are more versatile in some situations.
+
+  * .DEFINE style macros may take parameters. While classic macros may
+    have empty parameters, this is not true for .DEFINE style macros. For
+    this macro type, the number of actual parameters must match exactly
+    the number of formal parameters.
+    To make this possible, formal parameters are enclosed in braces when
+    defining the macro. If there are no parameters, the empty braces may
+    be omitted.
+
+  * Since .DEFINE style macros may not contain end-of-line tokens, there
+    are things that cannot be done. They may not contain several processor
+    instructions for example. So, while some things may be done with both
+    macro types, each type has special usages. The types complement each
+    other.
+
+Let's look at a few examples to make the advantages and disadvantages
+clear.
+
+To emulate assemblers that use "EQU" instead of "=" you may use the
+following .DEFINE:
+
+       .define EQU     =
+
+       foo     EQU     $1234           ; This is accepted now
+
+You may use the directive to define string constants use elsewhere:
+
+       ; Define the version number
+       .define VERSION         "12.3a"
+
+       ; ... and use it
+       .asciiz VERSION
+
+Macros with parameters may also be useful:
+
+       .define DEBUG(message)  .out    message
+
+       DEBUG   "Assembling include file #3"
+
+Note that, while formal parameters have to be placed in braces, this is
+not true for the actual parameters. Beware: Since the assembler cannot
+detect the end of one parameter, only the first token is used. If you
+don't like that, use classic macros instead:
+
+       .macro  message
+               .out    message
+       .endmacro
+
+(This is an example where a problem can be solved with both macro types).
+
+
+
+8. Macro packages
+-----------------
+
+Using the .macpack directive, predefined macro packages may be included
+with just one command. Available macro packages are:
+
+  - generic
+
+    This macro package defines macros that are useful in almost any
+    program. Currently, two macros are defined:
+
+       .macro  add     Arg
+               clc
+               adc     Arg
+       .endmacro
+
+       .macro  sub     Arg
+               sec
+               sbc     Arg
+       .endmacro
+
+
+  - longbranch
+
+    This macro package defines long conditional jumps. They are named like
+    the short counterpart but with the 'b' replaced by a 'j'. Here is a
+    sample definition for the "jeq" macro, the other macros are built using
+    the same scheme:
+
+       .macro  jeq     Target
+               .if     .def(Target) .and ((*+2)-(Target) <= 127)
+               beq     Target
+               .else
+               bne     *+5
+               jmp     Target
+               .endif
+       .endmacro
+
+    All macros expand to a short branch, if the label is already defined
+    (back jump) and is reachable with a short jump. Otherwise the macro
+    expands to a conditional branch with the branch condition inverted,
+    followed by an absolute jump to the actual branch target.
+
+    The package defines the following macros:
+
+       jeq, jne, jmi, jpl, jcs, jcc, jvs, jvc
+
+
+
+9. Bugs/Feedback
+----------------
+
+If you have problems using the assembler, if you find any bugs, or if
+you're doing something interesting with the assembler, I would be glad to
+hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+10. Copyright
+-------------
+
+ca65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
+
+
+
+
diff --git a/doc/cc65.txt b/doc/cc65.txt
new file mode 100644 (file)
index 0000000..e99f262
--- /dev/null
@@ -0,0 +1,600 @@
+
+
+                                  cc65
+
+                      A C Compiler for 6502 Systems
+
+                   (C) Copyright 1989 John R. Dunning
+              (C) Copyright 1998-2000 Ullrich von Bassewitz
+                           (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. Usage
+
+  3. Input and output
+
+  4. Differences to the ISO standard
+
+  5. Extensions
+
+  6. Predefined macros
+
+  7. #pragmas
+
+  8. Bugs/Feedback
+
+  9. Copyright
+
+
+
+1. Overview
+-----------
+
+cc65 was originally a C compiler for the Atari 8-bit machines written by
+John R. Dunning. In prior releases I've described the compiler by listing
+up the changes made by me. I have made many more changes in the meantime
+(and rewritten major parts of the compiler), so I will no longer do that,
+since the list would be too large and of no use to anyone. Instead I will
+describe the compiler in respect to the ANSI/ISO C standard. In fact, I'm
+planning a complete rewrite (that is, a complete new compiler) for the
+next release, since there are too many limitations in the current code,
+and removing these limitations would mean a rewrite of many more parts of
+the compiler.
+
+There is a separate document named "library.txt" that covers the library
+available for the compiler. If you know C and are interested in doing
+actual programming, the library documentation is probably of much more use
+than this document.
+
+If you need some hints for getting the best code out of the compiler, you
+may have a look at "coding.txt" which covers some code generation issues.
+
+
+
+2. Usage
+--------
+
+The compiler translates C files into files containing assembler code that
+may be translated by the ca65 macroassembler (for more information about
+the assembler, have a look at ca65.txt).
+
+The compiler may be called as follows:
+
+Usage: cc65 [options] file
+       -d              Debug mode
+       -g              Add debug info to object files
+       -h              Print this help
+        -j              Default characters are signed
+       -o name         Name the output file
+       -s              Print some statistics
+       -tx             Set target system x
+       -v              Verbose mode
+       -A              Strict ANSI mode
+       -Cl             Make local variables static
+       -Dsym[=defn]    Define a symbol
+       -I path         Set include directory
+       -O              Optimize code
+       -Oi             Optimize code, inline more code
+       -Or             Enable register variables
+       -Os             Inline some known functions
+       -T              Include source as comment
+       -V              Print version number
+       -W              Suppress warnings
+
+The -A option disables any compiler exensions. Have a look at section 5
+for a discussion of compiler extensions. In addition, the macro
+
+               __STRICT_ANSI__
+
+is defined, when compiling with -A.
+
+-d enables debug mode, something that should not be needed for mere
+mortals:-)
+
+-g will cause the compiler to insert a .DEBUGINFO command into the
+generated assembler code. This will cause the assembler to include all
+symbols in a special section in the object file.
+
+-h and -s print some statistics, nothing spectacular.
+
+Using -j you can make the default characters signed. Since the 6502 has
+no provisions for sign extending characters (which is needed on almost
+any load operation), this will make the code larger and slower. A better
+way is to declare characters explicitly as "signed" if needed. You can
+also use "#pragma signedchars" for better control of this option (see
+section 7).
+
+The -t option is used to set the target system. The target system
+determines things like the character set that is used for strings and
+character constants. The following target systems are supported:
+
+       none
+       c64
+       c128
+       ace             (no library support)
+       plus4
+               cbm610
+       pet             (all CBM PET systems except the 2001)
+       nes             (Nintendo Entertainment System)
+       apple2
+       geos
+
+Using -v, the compiler will be somewhat more verbose if errors or warnings
+are encountered.
+
+-Cl will use static storage for local variables instead of storage on the
+stack. Since the stack is emulated in software, this gives shorter and
+usually faster code, but the code is no longer reentrant. The difference
+between -Cl and declaring local variables as static yourself is, that
+initializer code is executed each time, the function is entered. So when
+using
+
+       void f (void)
+       {
+           unsigned a = 1;
+           ...
+       }
+
+the variable a will always have the value 1 when entering the function and
+using -Cl, while in
+
+       void f (void)
+       {
+           static unsigned a = 1;
+           ....
+       }
+
+the variable a will have the value 1 only the first time, the function is
+entered, and will keep the old value from one call of the function to the
+next.
+
+You may also use #pragma staticlocals to change this setting in your
+sources (see section 7).
+
+-I sets the directory where the compiler searches for include files. You
+may use -I multiple times to add more than one directory to the search
+list.
+
+-O will        enable an optimizer run over the produced code. Using -Oi, the
+code generator will inline some code where otherwise a runtime functions
+would have been called, even if the generated code is larger. This will
+not only remove the overhead for a function call, but will make the code
+visible for the optimizer.
+
+-Or will make the compiler honor the "register" keyword. Local variables
+may be placed in registers (which are actually zero page locations).
+There is some overhead involved with register variables, since the old
+contents of the registers must be saved and restored. In addition, the
+current implementation does not make good use of register variables, so
+using -Or may make your program even slower and larger. Use with care!
+
+Using -Os will force the compiler to inline some known functions from the
+C library like strlen. Note: This has two consequences:
+
+  * You may not use names of standard C functions in your own code. If
+    you do that, your program is not standard compliant anyway, but
+    using -Os will actually break things.
+
+  * The inlined string and memory functions will not handle strings or
+    memory areas larger than 255 bytes. Similar, the inlined is..()
+    functions will not work with values outside char range.
+
+It is possible to concatenate the modifiers for -O. For example, to
+enable register variables and inlining of known functions, you may use
+-Ors.
+
+-T will include the source code as comments in the generated code. This is
+normally not needed.
+
+-V prints the version number of the compiler. When submitting a bug
+report, please include the operating system you're using, and the compiler
+version.
+
+The -W switch suppresses any warnings generated by the compiler. Since any
+source file may be written in a manner that it will not produce compiler
+warnings, using this option is usually not a good idea.
+
+
+
+3. Input and output
+-------------------
+
+The compiler will accept one C file per invocation and create a file with
+the same base name, but with the extension replaced by ".s". The output
+file contains assembler code suitable for the use with the ca65 macro
+assembler.
+
+In addition to the paths named in the -I option on the command line, the
+directory named in the environment variable CC65_INC is added to the
+search path for include files on startup.
+
+
+
+4. Differences to the ISO standard
+----------------------------------
+
+Here is a list of differences between the language, the compiler accepts,
+and the one defined by the ISO standard:
+
+
+  * The compiler allows single line comments that start with //. This
+    feature is disabled in strict ANSI mode.
+
+  * The compiler allows unnamed parameters in parameter lists. The
+    compiler will not issue warnings about unused parameters that don't
+    have a name. This feature is disabled in strict ANSI mode.
+
+  * The compiler has some additional keywords:
+
+       asm, __asm__, fastcall, __fastcall__, __AX__, __EAX__, __func__
+
+    The keywords without the underlines are disabled in strict ANSI mode.
+
+  * The "const" modifier is available, but has no effect.
+
+  * The datatypes "float" and "double" are not available.
+
+  * The compiler does not support bit fields.
+
+  * Initialization of local variables is only possible for scalar data
+    types (that is, not for arrays and structs).
+
+  * Because of the "wrong" order of the parameters on the stack, there is
+    an additional macro needed to access parameters in a variable
+    parameter list in a C function.
+
+  * The compiler has only one symbol table. Because of that, it's not
+    possible to use the name of a local variable in a nested block in the
+    same function (global and local names are distinct, however).
+
+  + The preprocessor does not understand the "defined" keyword in
+    expressions evaluated in #if statements.
+
+  * Functions may not return structs, struct assignment is not possible.
+
+  * The size of any struct referenced via a pointer may not exceed 256
+    bytes (this is because the Y register is used as index).
+
+  * In a function, the size of the parameters plus the size of all local
+    variables may not exceed 256 bytes (in fact, the limit may be even less
+    depeding on the complexity of your expressions).
+
+  * Part of the C library is available only with fastcall calling
+    conventions (see below). This means, that you may not mix pointers to
+    those functions with pointers to user written functions.
+
+There may be some more minor differences, I'm currently not aware off. The
+biggest problems are the missing const and float data types. With both
+these things in mind, you should be able to write fairly portable code.
+
+
+
+5. Extensions
+-------------
+
+This cc65 version has some extensions to the ISO C standard.
+
+  * The compiler allows // comments (like in C++ and in the proposed C9x
+    standard). This feature is disabled by -A.
+
+  * The compiler allows to insert assembler statements into the output
+    file. The syntax is
+
+       asm (<string literal>) ;
+
+    or
+
+       __asm__ (<string literal>) ;
+
+    The first form is in the user namespace and is disabled if the -A
+    switch is given.
+
+    The given string is inserted literally into the output file, and a
+    newline is appended. The statements in this string are not checked by
+    the compiler, so be careful!
+
+    The asm statement may be used inside a function and on global file
+    level.
+
+  * There is a special calling convention named "fastcall". This calling
+    convention is currently only usable for functions written in
+    assembler. The syntax for a function declaration using fastcall is
+
+               <return type> fastcall <function name> (<parameter list>)
+
+    or
+
+               <return type> __fastcall__ <function name> (<parameter list>)
+
+    An example would be
+
+       void __fastcall__ f (unsigned char c)
+
+    The first form of the fastcall keyword is in the user namespace and is
+    therefore disabled in strict ANSI mode.
+
+    For functions declared as fastcall, the rightmost parameter is not
+    pushed on the stack but left in the primary register when the function
+    is called. This will reduce the cost when calling assembler functions
+    significantly, especially when the function itself is rather small.
+
+    BEWARE: You must not declare C functions as fastcall! This will not
+    work for now and is not checked by the assembler, so you will get
+    wrong code.
+
+  * There are two pseudo variables named __AX__ and __EAX__. Both refer to
+    the primary register that is used by the compiler to evaluate
+    expressions or return function results. __AX__ is of type unsigned int
+    and __EAX__ of type long unsigned int respectively. The pseudo
+    variables may be used as lvalue and rvalue as every other variable.
+    They are most useful together with short sequences of assembler code.
+    For example, the macro
+
+       #define hi(x) (__AX__=(x),asm("\ttxa\n\tldx\t#$00",__AX__)
+
+    will give the high byte of any unsigned value.
+
+  * Inside a function, the identifier __func__ gives the name of the
+    current function as a string. Outside of functions, __func__ is
+    undefined.
+    Example:
+
+       #define PRINT_DEBUG(s)  printf ("%s: %s\n", __func__, s);
+
+    The macro will print the name of the current function plus a given
+    string.
+
+
+
+6. Predefined macros
+--------------------
+
+The compiler defines several macros at startup:
+
+
+  __CC65__       This macro is always defined. Its value is the version
+                 number of the compiler in hex. Version 2.0.1 of the
+                 compiler will have this macro defined as 0x0201.
+
+  __CBM__        This macro is defined if the target system is one of the
+                 CBM targets.
+
+  __C64__        This macro is defined if the target is the c64 (-t c64).
+
+  __C128__       This macro is defined if the target is the c128 (-t c128).
+
+  __PLUS4__      This macro is defined if the target is the plus/4
+                 (-t plus4).
+
+  __CBM610__     This macro is defined if the target is one of the CBM
+                 600/700 family of computers (called B series in the US).
+
+  __PET__        This macro is defined if the target is the PET family of
+                 computers (-t pet).
+
+  __NES__                This macro is defined if the target is the Nintendo
+                 Entertainment System (-t nes).
+
+  __ATARI__      This macro is defined if the target is one of the Atari
+                 computers (400/800/130XL/800XL). Note that there is no
+                 runtime and C library support for atari systems.
+
+  __ACE__                This macro is defined if the target is Bruce Craigs ACE
+                 operating system. Note that there is no longer runtime
+                 and library support for ACE.
+
+  __APPLE2__     This macro is defined if the target is the Apple ][
+                 (-t apple2).
+
+  __GEOS__       This macro is defined if you are compiling for the GEOS
+                 system (-t geos).
+
+  __FILE__       This macro expands to a string containing the name of
+                 the C source file.
+
+  __LINE__       This macro expands to the current line number.
+
+  __STRICT_ANSI__ This macro is defined to 1 if the -A compiler option was
+                 given, and undefined otherwise.
+
+  __OPT__        Is defined if the compiler was called with the -O command
+                 line option.
+
+  __OPT_i__      Is defined if the compiler was called with the -Oi command
+                 line option.
+
+  __OPT_r__      Is defined if the compiler was called with the -Or command
+                 line option.
+
+  __OPT_s__      Is defined if the compiler was called with the -Os command
+                 line option.
+
+
+
+7. #pragmas
+-----------
+
+The compiler understands some pragmas that may be used to change code
+generation and other stuff.
+
+
+#pragma bssseg (<name>)
+
+  This pragma changes the name used for the BSS segment (the BSS segment
+  is used to store uninitialized data). The argument is a string enclosed
+  in double quotes.
+
+  Note: The default linker configuration file does only map the standard
+  segments. If you use other segments, you have to create a new linker
+  configuration file.
+
+  Beware: The startup code will zero only the default BSS segment. If you
+  use another BSS segment, you have to do that yourself, otherwise
+  uninitialized variables do not have the value zero.
+
+  Example:
+
+       #pragma bssseg ("MyBSS")
+
+
+#pragma codeseg (<name>)
+
+  This pragma changes the name used for the CODE segment (the CODE segment
+  is used to store executable code). The argument is a string enclosed in
+  double quotes.
+
+  Note: The default linker configuration file does only map the standard
+  segments. If you use other segments, you have to create a new linker
+  configuration file.
+
+  Example:
+
+       #pragma bssseg ("MyCODE")
+
+
+#pragma dataseg (<name>)
+
+  This pragma changes the name used for the DATA segment (the DATA segment
+  is used to store initialized data). The argument is a string enclosed in
+  double quotes.
+
+  Note: The default linker configuration file does only map the standard
+  segments. If you use other segments, you have to create a new linker
+  configuration file.
+
+  Example:
+
+       #pragma bssseg ("MyDATA")
+
+
+#pragma rodataseg (<name>)
+
+  This pragma changes the name used for the RODATA segment (the RODATA
+  segment is used to store readonly data). The argument is a string
+  enclosed in double quotes.
+
+  Note: The default linker configuration file does only map the standard
+  segments. If you use other segments, you have to create a new linker
+  configuration file.
+
+  Example:
+
+       #pragma bssseg ("MyRODATA")
+
+
+#pragma regvaraddr (<const int>)
+
+  The compiler does not allow to take the address of register variables.
+  The regvaraddr pragma changes this. Taking the address of a register
+  variable is allowed after using this pragma, if the argument is not
+  zero. Using an argument of zero changes back to the default behaviour.
+
+  Beware: The C standard does not allow taking the address of a variable
+  declared as register. So your programs become non-portable if you use
+  this pragma. In addition, your program may not work. This is usually the
+  case if a subroutine is called with the address of a register variable,
+  and this subroutine (or a subroutine called from there) uses itself
+  register variables. So be careful with this #pragma.
+
+  Example:
+
+       #pragma regvaraddr(1)   /* Allow taking the address
+                                * of register variables
+                                */
+
+
+#pragma signedchars (<const int>)
+
+  Changed the signedness of the default character type. If the argument
+  is not zero, default characters are signed, otherwise characters are
+  unsigned. The compiler default is to make characters unsigned since this
+  creates a lot better code. 
+
+
+#pragma staticlocals (<const int>)
+
+  Use variables in the bss segment instead of variables on the stack. This
+  pragma changes the default set by the compiler option -Cl. If the argument
+  is not zero, local variables are allocated in the BSS segment, leading to
+  shorter and in most cases faster, but non-reentrant code.
+
+
+#pragma zpsym (<name>)
+
+  Tell the compiler that the - previously as external declared - symbol with
+  the given name is a zero page symbol (usually from an assembler file).
+  The compiler will create a matching import declaration for the assembler.
+
+  Example:
+
+       extern int foo;
+       #pragma zpsym ("foo");  /* foo is in the zeropage */
+
+
+
+8. Bugs/Feedback
+----------------
+
+If you have problems using the compiler, if you find any bugs, or if
+you're doing something interesting with the compiler, I would be glad to
+hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+9. Copyright
+------------
+
+This is the original compiler copyright:
+
+--------------------------------------------------------------------------
+  -*- Mode: Text -*-
+
+     This is the copyright notice for RA65, LINK65, LIBR65, and other
+  Atari 8-bit programs.  Said programs are Copyright 1989, by John R.
+  Dunning.  All rights reserved, with the following exceptions:
+
+      Anyone may copy or redistribute these programs, provided that:
+
+  1:  You don't charge anything for the copy.  It is permissable to
+      charge a nominal fee for media, etc.
+
+  2:  All source code and documentation for the programs is made
+      available as part of the distribution.
+
+  3:  This copyright notice is preserved verbatim, and included in
+      the distribution.
+
+      You are allowed to modify these programs, and redistribute the
+  modified versions, provided that the modifications are clearly noted.
+
+      There is NO WARRANTY with this software, it comes as is, and is
+  distributed in the hope that it may be useful.
+
+      This copyright notice applies to any program which contains
+  this text, or the refers to this file.
+
+      This copyright notice is based on the one published by the Free
+  Software Foundation, sometimes known as the GNU project.  The idea
+  is the same as theirs, ie the software is free, and is intended to
+  stay that way.  Everybody has the right to copy, modify, and re-
+  distribute this software.  Nobody has the right to prevent anyone
+  else from copying, modifying or redistributing it.
+
+--------------------------------------------------------------------------
+
+In acknowledgment of this copyright, I will place my own changes to the
+compiler under the same copyright. Please note however, that the library
+and all binutils are covered by another copyright, and that I'm planning
+to do a complete rewrite of the compiler, after which the compiler
+copyright will also change.
+
+For the list of changes requested by this copyright see newvers.txt.
+
+
+
diff --git a/doc/cl65.txt b/doc/cl65.txt
new file mode 100644 (file)
index 0000000..0945b11
--- /dev/null
@@ -0,0 +1,183 @@
+
+
+                                  cl65
+
+                    Compile and link utility for cc65
+
+                (C) Copyright 1999 Ullrich von Bassewitz
+                           (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. Basic Usage
+
+  3. More usage
+
+  4. Examples
+
+  5. Bugs/Feedback
+
+  6. Copyright
+
+
+
+1. Overview
+-----------
+
+cl65 is a frontend for cc65, ca65 and ld65. While you may not use the full
+power of the tools when calling them through cl65, most features are
+available, and the use of cl65 is much simpler.
+
+
+
+2. Usage
+--------
+
+The cl65 compile and link utility may be used to compile, assemble and
+link files. While the separate tools do just one step, cl65 knows how to
+build object files from C files (by calling the compiler, then the
+assembler) and other things.
+
+       Usage: cl65 [options] file
+       Options:
+               -A              Strict ANSI mode
+               -C name         Use linker config file
+               -D sym[=defn]   Define a preprocessor symbol
+               -I path         Set an include directory path
+               -Ln name        Create a VICE label file
+               -O              Optimize code
+               -Oi             Optimize code, inline functions
+               -Or             Optimize code, honour the register keyword
+               -Os             Optimize code, inline known C funtions
+               -S              Compile but don't assemble and link
+               -V              Print the version number
+               -W              Suppress warnings
+               -c              Compiler and assemble but don't link
+               -d              Debug mode
+               -g              Add debug info
+               -h              Help (this text)
+               -m name         Create a map file
+               -o name         Name the output file
+               -t system       Set the target system
+               -v              Verbose mode
+               -vm             Verbose map file
+
+Most of the options have the same meaning than the corresponding compiler,
+assembler or linker option. If an option is available for more than one
+of the tools, it is set for all tools, where it is available. One example
+for this is -v: The compiler, the assembler and the linker are all called
+with the -v switch.
+
+There are a few remaining options that control the behaviour of cl65:
+
+The -S option forces cl65 to stop after the assembly step. This means that
+C files are translated into assembler files, but nothing more is done.
+Assembler files, object files and libraries given on the command line are
+ignored.
+
+The -c options forces cl65 to stop after the assembly step. This means
+that C and assembler files given on the command line are translated into
+object files, but there is no link step, and object files and libraries
+given on the command line are ignored.
+
+The -o option is used for the target name in the final step. This causes
+problems, if the linker will not be called, and there are several input
+files on the command line. In this case, the name given with -o will be
+used for all of them, which makes the option pretty useless. You shouldn't
+use -o when more than one output file is created.
+
+The default for the -t option is different from the compiler and linker in
+the case that the option is missing: While the compiler and linker will
+use the "none" system settings by default, cl65 will use the C64 as a
+target system by default. This was choosen since most people seem to use
+cc65 to develop for the C64.
+
+
+
+3. More usage
+-------------
+
+Since cl65 was created to simplify the use of the cc65 development
+package, it tries to be smart about several things.
+
+  - If you don't give a target system on the command line, cl65
+    defaults to the C64.
+
+  - When linking, cl65 will supply the names of the startup file and
+    library for the target system to the linker, so you don't have to do
+    that.
+
+  - If the final step is the linker, and the name of the output file was
+    not explicitly given, cl65 will use the name of the first input file
+    without the extension, provided that the name of this file has an
+    extension. So you don't need to name the executable name in most
+    cases, just give the name of your "main" file as first input file.
+
+
+
+4. Examples
+-----------
+
+The morse trainer software, which consists of one C file (morse.c) and one
+assembler file (irq.s) will need the following separate steps to compile
+into an executable named morse:
+
+       cc65 -g -Oi -t c64 morse.c
+       ca65 -g morse.s
+       ca65 -g irq.s
+       ld65 -t c64 -o morse c64.o morse.o irq.o c64.lib
+
+When using cl65, this is simplified to
+
+       cl65 -g -Oi morse.c irq.s
+
+
+As a general rule, you may use cl65 instead of cc65 at most times,
+especially in makefiles to build object files directly from C files. Use
+
+       .c.o:
+               cl65 -g -Oi $<
+
+to do this.
+
+
+
+5. Bugs/Feedback
+----------------
+
+If you have problems using the utility, if you find any bugs, or if you're
+doing something interesting with it, I would be glad to hear from you.
+Feel free to contact me by email (uz@musoftware.de).
+
+
+
+6. Copyright
+------------
+
+cl65 is (C) Copyright 1998 Ullrich von Bassewitz. For usage of the
+binaries and/or sources the following conditions do apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
+
+
+
diff --git a/doc/coding.txt b/doc/coding.txt
new file mode 100644 (file)
index 0000000..66e6c17
--- /dev/null
@@ -0,0 +1,340 @@
+
+How to generate the most effective code with cc65.
+
+
+1.  Use prototypes.
+
+    This will not only help to find errors between separate modules, it will
+    also generate better code, since the compiler must not assume that a
+    variable sized parameter list is in place and must not pass the argument
+    count to the called function. This will lead to shorter and faster code.
+
+
+
+2.  Don't declare auto variables in nested function blocks.
+
+    Variable declarations in nested blocks are usually a good thing. But with
+    cc65, there are several drawbacks:
+
+     a. The compiler has only one symbol table (there's no true nesting).
+        This means that your variables must not have the same names as
+        variables in the enclosing block.
+
+     b. Since the compiler generates code in one pass, it must create the
+        the variables on the stack each time the block is entered and destroy
+       them when the block is left. This causes a speed penalty and larger
+        code.
+
+
+
+3.  Remember that the compiler does not optimize.
+
+    The compiler needs hints from you about the code to generate. When
+    accessing indexed data structures, get a pointer to the element and
+    use this pointer instead of calculating the index again and again.
+    If you want to have your loops unrolled, or loop invariant code moved
+    outside the loop, you have to do that yourself.
+
+
+
+4.  Longs are slow!
+
+    While long support is necessary for some things, it's really, really slow
+    on the 6502. Remember that any long variable will use 4 bytes of memory,
+    and any operation works on double the data compared to an int.
+
+
+
+5.  Use unsigned types wherever possible.
+
+    The CPU has no opcodes to handle signed values greater than 8 bit. So
+    sign extension, test of signedness etc. has to be done by hand. The
+    code to handle signed operations is usually a bit slower than the same
+    code for unsigned types.
+
+
+
+6.  Use chars instead of ints if possible.
+
+    While in arithmetic operations, chars are immidiately promoted to ints,
+    they are passed as chars in parameter lists and are accessed as chars
+    in variables. The code generated is usually not much smaller, but it
+    is faster, since accessing chars is faster. For several operations, the
+    generated code may be better if intermediate results that are known not
+    to be larger than 8 bit are casted to chars.
+
+    When doing
+
+       unsigned char a;
+       ...
+       if ((a & 0x0F) == 0)
+
+    the result of the & operator is an int because of the int promotion
+    rules of the language. So the compare is also done with 16 bits. When
+    using
+
+       unsigned char a;
+       ...
+       if ((unsigned char)(a & 0x0F) == 0)
+
+    the generated code is much shorter, since the operation is done with
+    8 bits instead of 16.
+
+
+
+7.  Make the size of your array elements one of 1, 2, 4, 8.
+
+    When indexing into an array, the compiler has to calculate the byte
+    offset into the array, which is the index multiplied by the size of
+    one element. When doing the multiplication, the compiler will do a
+    strength reduction, that is, replace the multiplication by a shift
+    if possible. For the values 2, 4 and 8, there are even more specialized
+    subroutines available. So, array access is fastest when using one of
+    these sizes.
+
+
+
+8.  Expressions are evaluated from left to right.
+
+    Since cc65 is not building an explicit expression tree when parsing an
+    expression, constant subexpressions may not be detected and optimized
+    properly if you don't help. Look at this example:
+
+      #define OFFS   4
+      int  i;
+      i = i + OFFS + 3;
+
+    The expression is parsed from left to right, that means, the compiler sees
+    'i', and puts it contents into the secondary register. Next is OFFS, which
+    is constant. The compiler emits code to add a constant to the secondary
+    register. Same thing again for the constant 3. So the code produced
+    contains a fetch of 'i', two additions of constants, and a store (into
+    'i'). Unfortunately, the compiler does not see, that "OFFS + 3" is a
+    constant for itself, since it does it's evaluation from left to right.
+    There are some ways to help the compiler to recognize expression like
+    this:
+
+     a. Write "i = OFFS + 3 + i;". Since the first and second operand are
+               constant, the compiler will evaluate them at compile time reducing the
+               code to a fetch, one addition (secondary + constant) and one store.
+
+     b. Write "i = i + (OFFS + 3)". When seeing the opening parenthesis, the
+               compiler will start a new expression evaluation for the stuff in the
+               braces, and since all operands in the subexpression are constant, it
+               will detect this and reduce the code to one fetch, one addition and
+               one store.
+
+
+
+9.  Case labels in a switch statments are checked in source order.
+
+    Labels that appear first in a switch statement are tested first. So,
+    if your switch statement contains labels that are selected most of
+    the time, put them first in your source code. This will speed up the
+    code.
+
+
+
+10. Use the preincrement and predecrement operators.
+
+    The compiler is currently not smart enough to figure out, if the rvalue of
+    an increment is used or not. So it has to save and restore that value when
+    producing code for the postincrement and postdecrement operators, even if
+    this value is never used. To avoid the additional overhead, use the
+    preincrement and predecrement operators if you don't need the resulting
+    value. That means, use
+
+               ...
+               ++i;
+               ...
+
+    instead of
+
+       ...
+       i++;
+       ...
+
+
+
+11. Use constants to access absolute memory locations.
+
+    The compiler produces optimized code, if the value of a pointer is a
+    constant. So, to access direct memory locations, use
+
+       #define VDC_DATA   0xD601
+       *(char*)VDC_STATUS = 0x01;
+
+    That will be translated to
+
+       lda     #$01
+       sta     $D600
+
+    The constant value detection works also for struct pointers and arrays,
+    if the subscript is a constant. So
+
+       #define VDC     ((unsigned char*)0xD600)
+       #define STATUS  0x01
+       VDC [STATUS] = 0x01;
+
+    will also work.
+
+    If you first load the constant into a variable and use that variable to
+    access an absolute memory location, the generated code will be much
+    slower, since the compiler does not know anything about the contents of
+    the variable.
+
+
+
+12. Use initialized local variables - but use it with care.
+
+    Initialization of local variables when declaring them gives shorter
+    and faster code. So, use
+
+       int i = 1;
+
+    instead of
+
+       int i;
+       i = 1;
+
+    But beware: To maximize your savings, don't mix uninitialized and
+    initialized variables. Create one block of initialized variables and
+    one of uniniitalized ones. The reason for this is, that the compiler
+    will sum up the space needed for uninitialized variables as long as
+    possible, and then allocate the space once for all these variables.
+    If you mix uninitialized and initialized variables, you force the
+    compiler to allocate space for the uninitialized variables each time,
+    it parses an initialized one. So do this:
+
+       int i, j;
+       int a = 3;
+       int b = 0;
+
+    instead of
+
+       int i;
+       int a = 3;
+       int j;
+       int b = 0;
+
+    The latter will work, but will create larger and slower code.
+
+
+
+13. When using the ?: operator, cast values that are not ints.
+
+    The result type of the ?: operator is a long, if one of the second or
+    third operands is a long. If the second operand has been evaluated and
+    it was of type int, and the compiler detects that the third operand is
+    a long, it has to add an additional int->long conversion for the
+    second operand. However, since the code for the second operand has
+    already been emitted, this gives much worse code.
+
+    Look at this:
+
+       long f (long a)
+       {
+           return (a != 0)? 1 : a;
+       }
+
+    When the compiler sees the literal "1", it does not know, that the
+    result type of the ?: operator is a long, so it will emit code to load
+    a integer constant 1. After parsing "a", which is a long, a int->long
+    conversion has to be applied to the second operand. This creates one
+    additional jump, and an additional code for the conversion.
+
+    A better way would have been to write:
+
+       long f (long a)
+       {
+           return (a != 0)? 1L : a;
+       }
+
+    By forcing the literal "1" to be of type long, the correct code is
+    created in the first place, and no additional conversion code is
+    needed.
+
+
+
+14. Use the array operator [] even for pointers.
+
+    When addressing an array via a pointer, don't use the plus and
+    dereference operators, but the array operator. This will generate
+    better code in some common cases.
+
+    Don't use
+
+       char* a;
+       char b, c;
+       char b = *(a + c);
+
+    Use
+
+       char* a;
+       char b, c;
+       char b = a[c];
+
+    instead.
+
+
+
+15. Use register variables with care.
+
+    Register variables may give faster and shorter code, but they do also
+    have an overhead. Register variables are actually zero page
+    locations, so using them saves roughly one cycle per access. Since
+    the old values have to be saved and restored, there is an overhead of
+    about 70 cycles per 2 byte variable. It is easy to see, that - apart
+    from the additional code that is needed to save and restore the
+    values - you need to make heavy use of a variable to justify the
+    overhead.
+
+    An exception are pointers, especially char pointers. The optimizer
+    has code to detect and transform the most common pointer operations
+    if the pointer variable is a register variable. Declaring heavily
+    used character pointers as register may give significant gains in
+    speed and size.
+
+    And remember: Register variables must be enabled with -Or.
+
+                            
+
+16. Decimal constants greater than 0x7FFF are actually long ints
+
+    The language rules for constant numeric values specify that decimal
+    constants without a type suffix that are not in integer range must be
+    of type long int or unsigned long int. This means that a simple
+    constant like 40000 is of type long int, and may cause an expression
+    to be evaluated with 32 bits.
+
+    An example is:
+
+       unsigned val;
+       ...
+       if (val < 65535) {
+           ...
+       }
+
+    Here, the compare is evaluated using 32 bit precision. This makes the
+    code larger and a lot slower.
+
+    Using
+
+       unsigned val;
+       ...
+       if (val < 0xFFFF) {
+           ...
+       }
+
+    or
+
+       unsigned val;
+       ...
+       if (val < 65535U) {
+           ...
+       }
+
+    instead will give shorter and faster code.
+
+
+
diff --git a/doc/compile.txt b/doc/compile.txt
new file mode 100644 (file)
index 0000000..8067858
--- /dev/null
@@ -0,0 +1,159 @@
+
+
+Instructions for compiling cc65 and the ca65 binutils:
+
+
+Linux (and probably most other Unices)
+--------------------------------------
+
+You need the GNU C compiler. Do a
+
+       make -f make/gcc.mak
+
+twice(!) in each of the directories
+
+       cc65
+       binutils
+
+After that, you need to compile the libraries. Do
+
+       cd lib
+       make clean c64lib
+       make clean c128lib
+       make clean plus4lib
+       make clean cbm610lib
+       make clean petlib
+       make clean apple2lib
+
+Be sure to say "clean" each time, since some of the sources have a
+"#ifdef <target_system>".
+
+
+
+DOS using the DJGPP compiler
+----------------------------
+
+Most information in this section was provided by Keith W. Gerdes
+(kwg@freebird.ghofn.org). Thanks a lot!
+
+The tmpfile() function in DJGPP has a bug and will not open the scratch
+file in binary mode. If you have problems with the archiver (which uses
+the tmpfile() function), you have two choices:
+
+  1. Get a fix from http://www.cartsys.com/eldredge/djgpp-patches.html
+     and apply it. This will solve the problem once and forever.
+
+  2. For a temporary solution, in the file binutils/ar65/main.c, add the
+     following lines:
+
+     At top:
+
+       #include <fcntl.h>
+
+     At start of main:
+
+       _fmode = O_BINARY;
+
+     This will switch the default mode to binary and will work around the
+     bug.
+
+Keith sent me the following notes how to build the tools on a DOS system
+using DJGPP (add your system type to CFLAGS if needed):
+
+-------------------------------------------------------------------------
+
+Here's my current batch file:
+
+cd cc65
+if exist .depend goto ahead1
+make -f make\gcc.mak
+:ahead1
+make -f make\gcc.mak
+move *.exe ..\binutils
+
+cd ..\cl65
+if exist .depend goto ahead2
+make -f make\gcc.mak
+:ahead2
+make -f make\gcc.mak
+move *.exe ..\binutils
+
+cd ..\binutils\common
+if exist .depend goto ahead3
+make -f make\gcc.mak
+:ahead3
+make -f make\gcc.mak
+
+cd ..\ca65
+if exist .depend goto ahead4
+make -f make\gcc.mak
+:ahead4
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\ld65
+if exist .depend goto ahead5
+make -f make\gcc.mak
+:ahead5
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\ar65
+if exist .depend goto ahead6
+make -f make\gcc.mak
+:ahead6
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\..\lib\common
+make 'CFLAGS=-Oi -I../../include/'
+ar65 a common.lib *.o
+move common.lib ..
+
+cd ..\runtime
+make 'CFLAGS=-Oi -I../../include/'
+ar65 a runtime.lib *.o
+move runtime.lib ..
+
+ --
+
+In djgpp.env I use:
+
++LFN=Y
+
+for the .depend file.
+
+ --
+
+And in autoexec.bat I have:
+
+set CC65_INC=E:\djgpp_v2\cc65\include
+set CC65_LIB=E:\djgpp_v2\cc65\lib
+PATH=E:\djgpp_v2\cc65\binutils;%PATH%
+
+-------------------------------------------------------------------------
+
+
+DOS, Windows, OS/2 using the Watcom Compiler
+--------------------------------------------
+
+This is what I'm using. You need the Borland make in addition to the
+Watcom tools, or you have to change the makefile.
+
+1. Copy %WATCOM%\src\startup\wildargv.c from your Watcom directory into
+   binutils\common.
+
+2. Enter
+
+       make -f make\watcom.mak
+
+   in each of the directories
+
+       cc65
+       binutils
+
+3. Use Linux to build the libraries:-) If you don't have Linux, get it
+   now! More serious: There is no makefile to build the libraries. Use a
+   batch file similar to the one above, or rewrite the makefile.
+
+
diff --git a/doc/debugging.txt b/doc/debugging.txt
new file mode 100644 (file)
index 0000000..a7a0eaf
--- /dev/null
@@ -0,0 +1,151 @@
+
+
+                     Debugging your code using VICE
+
+                    Ullrich von Bassewitz, March 1999
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. What is VICE?
+
+  3. How to prepare your sources
+
+  4. How to use the label file
+
+  5. Problems and workarounds
+
+
+
+1. Overview
+-----------
+
+This document describes how to debug your programs using the cc65
+development tools and the VICE CBM emulator.
+
+
+
+2. What is VICE?
+----------------
+
+VICE is an emulator for many of the CBM machines. It runs on Unix, DOS and
+Windows 95. It emulates the Commodore 64, 128, VIC20, PET and the 600/700
+machines. For more information see the VICE home page:
+
+       http://www.cs.cmu.edu/~dsladic/vice/vice.html
+
+VICE has a builtin machine language monitor that may be used for debugging
+your programs. Using an emulator for debugging has some advantages:
+
+  - Since you're using a crossassembler/-compiler anyway, you don't need
+    to transfer the program to the real machine until it is done.
+
+  - An emulator allows many things that are almost impossible one of the
+    original machines. You may set watchpoints (detect read or write
+    access to arbitary addresses), debug interrupt handlers and even debug
+    routines that run inside the 1541 floppy.
+
+  - You may use the label file generated by the linker to make much more
+    use from the monitor.
+
+Please note that you need at least VICE version 0.16 for the label file
+feature to work. This version has still some problems (see section 5 for
+descriptions and some workarounds), but older versions had even more
+problems and do NOT work correctly.
+
+
+
+3. How to prepare your programs
+-------------------------------
+
+VICE support is mostly done via a label file that is generated by the
+linker and that may be read by the VICE monitor, so it knows about your
+program. Source level debugging is *not* available, you have to debug your
+programs in the assembler view.
+
+The first step is to generate object files that contain information about
+ALL labels in your sources, not just the exported ones. This can be done
+by several means:
+
+  - Use the -g switch on the assembler command line.
+
+  - Use the
+
+      .debuginfo +
+
+    command in your source.
+
+  - Use the -g switch when invoking the compiler. The compiler will then
+    put the .debuginfo command into the generated assembler source.
+
+So, if you have just C code, all you need is to invoke the compiler with
+-g. If you're using assembler code, you have to use -g for the assembler,
+or add ".debuginfo +" to your source files. Since the generated debug info
+is not appended to the generated executables, it is a good idea to always
+use -g. It makes the object files and libraries slightly larger (~30%),
+but this is usually not a problem.
+
+The second step is to tell the linker that it should generate a VICE label
+file. This is done by the -L switch followed by the name of the label file
+(I'm usually using a .lbl extension for these files). An example for a
+linker command line would be:
+
+    ld65 -t c64 -L hello.lbl -m hello.map -o hello crt0 hello.o c64.lib
+
+This will generate a file named hello.lbl that contains all symbols used
+in your program.
+
+Note: The runtime libraries and startup files were generated with debug
+info, so you don't have to care about this.
+
+
+
+4. How to use the label file
+----------------------------
+
+Load your program, then enter the monitor and use the "pb" command to load
+your label file like this:
+
+       pb "hello.lbl"
+
+You will get lots of warnings and even a few errors. You may ignore safely
+all these warnings and errors as long as they reference any problems VICE
+thinks it has with the labels.
+
+After loading the labels, they are used by VICE in the disassembler
+listing, and you may use them whereever you need to specify an address.
+Try
+
+       d ._main
+
+as an example (note that VICE needs a leading dot before all labels, and
+that the compiler prepends an underline under most named labels).
+
+
+
+5. Problems and workarounds
+---------------------------
+
+Unfortunately, the VICE monitor has several problems with labels. However,
+it is still tremendously useful, and I think that most problems are gone
+in the next version. So, here is a list of the problems known to me as of
+version 0.16.1:
+
+  * The "ll" command does not work. Worse, it seems that internal memory
+    gets corrupted when using this command, so VICE will crash after use.
+    Be sure to use the "pb" command to load the label file.
+
+  * VICE will crash if you use a label that is undefined. This is probably
+    the worst problem of all, since it needs just one typo to kill VICE.
+    So, watch your steps:-)
+
+  * Cheap labels, that is, labels starting with '@' or '?' are not
+    accepted.
+
+  * The disassembly output is somewhat suboptimal. However, most things are
+    just cosmetical, e.g. labels appended to the right side of the
+    disassembled code.
+
diff --git a/doc/internal.doc b/doc/internal.doc
new file mode 100644 (file)
index 0000000..d7b7f7e
--- /dev/null
@@ -0,0 +1,185 @@
+
+
+                           Internals doc for CC65
+
+
+
+Stacks:
+-------
+
+The program stack used by programs compiled with CC65 is located in high
+memory.  The stack starts there and grows down.  Arguments to functions, local
+data etc are allocated on this stack, and deallocated when functions exit.
+
+The program code and data is located in low memory. The heap is located
+between the program code and the stack. The default size for the parameter
+stack is 2K, you may change this by declaring an externally visible variable
+named named _stksize that holds the new stack size:
+
+    unsigned _stksize = 4*1024;                /* Use 4K stack */
+
+Note: The size of the stack is only needed if you use the heap, or if you
+call the stack checking routine (_stkcheck) from somewhere in your program.
+
+When calling other functions, the return address goes on the normal 6502
+stack, *not* on the parameter stack.
+
+
+
+Registers:
+----------
+
+Since CC65 is a member of the Small-C family of compilers, it uses the notion
+of a 'primary register'.  In the CC65 implementation, I used the AX register
+pair as the primary register.  Just about everything interesting that the
+library code does is done by somehow getting a value into AX, and then calling
+some routine or other.  In places where Small-C would use a secondary
+register, top-of-stack is used, so for instance two argument function like
+integer-multiply work by loading AX, pushing it on the stack, loading the
+second value, and calling the internal function.  The stack is popped, and the
+result comes back in AX.
+
+
+
+Calling sequences:
+------------------
+
+C functions are called by pushing their args on the stack, and JSR'ing to the
+entry point.  (See ex 1, below) If the function returns a value, it comes back
+in AX.  NOTE!!!  A potentially significant difference between the CC65
+environment and other C environments is that the CALLEE pops arguments, not
+the CALLER.  (This is done so as to generate more compact code) In normal use,
+this doesn't cause any problems, as the normal function entry/exit conventions
+take care of popping the right number of things off the stack, but you may
+have to worry about it when doing things like writing hand-coded assembly
+language routines that take variable numbers of arguments.  More about that
+later.
+
+Ex 1:  Function call:  Assuming 'i' declared int and 'c' declared
+       char, the following C code
+
+               i = baz(i, c);
+
+       in absence of a prototype generates this assembler code.  I've added
+       the comments.
+
+               lda     _i              ; get 'i', low byte
+               ldx     _i+1            ; get 'i', hi byte
+               jsr     pushax          ; push it
+               lda     _c              ; get 'c'
+               ldx     #0              ; fill hi byte with 0
+               jsr     pushax          ; push it
+               ldy     #4              ; arg size
+               jsr     _baz            ; call the function
+               sta     _i              ; store the result
+       stx     _i+1
+
+       In presence of a prototype, the picture changes slightly, since the
+       compiler is able to do some optimizations:
+
+               lda     _i              ; get 'i', low byte
+               ldx     _i+1            ; get 'i', hi byte
+               jsr     pushax          ; push it
+               lda     _c              ; get 'c'
+               jsr     pusha           ; push it
+               jsr     _baz            ; call the function
+               sta     _i              ; store the result
+               stx     _i+1
+
+
+Note that the two words of arguments to baz were popped before it exitted.
+The way baz could tell how much to pop was by the argument count in Y at call
+time.  Thus, even if baz had been called with 3 args instead of the 2 it was
+expecting, that would not cause stack corruption.
+
+There's another tricky part about all this, though.  Note that the args to baz
+are pushed in FORWARD order, ie the order they appear in the C statement.
+That means that if you call a function with a different number of args than it
+was expecting, they wont end up in the right places, ie if you call baz, as
+above, with 3 args, it'll operate on the LAST two, not the first two.
+
+
+
+Symbols:
+--------
+
+CC65 does the usual trick of prepending an underbar ('_') to symbol names when
+compiling them into assembler.  Therefore if you have a C function named
+'bar', CC65 will define and refer to it as '_bar'.
+
+
+
+Systems:
+--------
+
+Supported systems at this time are: C64, C128, Plus/4, CBM 600/700, the newer 
+PET machines (not 2001), and the Apple ][ (thanks to Kevin Ruland, who did the
+port).
+
+C64:   The program runs in a memory configuration, where only the kernal ROM
+       is enabled. The text screen is expected at the usual place ($400), so
+       54K of memory are available to the program.
+
+C128:  The startup code will reprogram the MMU, so that only the kernal ROM
+       is enabled. This means, there are 41K of memory available to the
+       program.
+
+Plus/4:        Unfortunately, the Plus/4 is not able to disable only part of it's
+       ROM, it's an all or nothing approach. So, on the Plus/4, the program
+               has only 28K available (16K machines are detected and the amount of
+       free memory is reduced to 12K).
+
+CBM 600/700:
+       The C program runs in a separate segment and has almost full 64K of
+       memory available.
+
+PET:   The startup code will adjust the upper memory limit to the installed
+       memory. However, only linear memory is used, this limits the top to
+       $8000, so on a 8032 or similar machine, 31K of memory are available to
+       the program.
+
+APPLE2:        The program starts at $800, and of RAM is $8E00, so 33.5K of memory
+       (including stack) are available.
+
+Note: The above numbers do not mean that the remaining memory is unusable.
+However, it is not linear memory and must be accessed by other, nonportable
+methods. I'm thinking about a library extension that allows access to the
+additional memory as a far heap, but these routines do not exist until now.
+
+
+
+Inline Assembly:
+----------------
+
+CC65 allows inline assembly by a special keyword named "asm". Inline assembly
+looks like a function call. The string in parenthesis is output in the
+assembler file.
+
+Example, insert a break instruction into the code:
+
+               asm ("\t.byte\t$00")
+
+Note: The \t in the string is replaced by the tab character, as in all other
+strings.
+
+
+
+Pseudo variables:
+-----------------
+
+There are two special variables available named __AX__ and __EAX__. These
+variables must never be declared (this gives an error), but may be used as any
+other variable. However, accessing these variables will access the primary
+register that is used by the compiler to evaluate expressions, return
+functions results and pass parameters.
+
+This feature is useful with inline assembly and macros. For example, a macro
+that reads a CRTC register may be written like this:
+
+#define wr(idx) (__AX__=(idx),asm("\tsta\t$2000\n\tlda\t$2000\n\tldx\t#$00"),__AX__)
+
+An obvious problem here is that macro definitions may not use more than one
+line.
+
+
+
diff --git a/doc/intro.txt b/doc/intro.txt
new file mode 100644 (file)
index 0000000..58b881e
--- /dev/null
@@ -0,0 +1,206 @@
+
+
+                     How to use the cc65 C compiler
+
+                    Ullrich von Bassewitz, 1998/1999
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. The compiler
+
+  3. The assembler
+
+  4. The linker
+
+  5. The easy way (using the cl65 utility)
+
+
+
+1. Overview
+-----------
+
+This is a short intro, how to use the compiler and the binutils. It
+contains a step-by-step example, how to build a complete application from
+one C and one assembler module. This file does *NOT* contain a complete
+reference for the tools used in the process. There are separate files
+describing these tools in detail.
+
+Note: There is a much simpler way to compile this example using the cl65
+compiler and link utility. However, it makes sense to understand how the
+separate steps work. How to do the example with the cl65 utility is
+described in section 5.
+
+To explain the development flow, I will use the following example modules:
+
+
+hello.c:
+
+       #include <stdio.h>
+       #include <stdlib.h>
+
+               extern const char text[];       /* In text.s */
+
+       int main (void)
+       {
+           printf ("%s\n", text);
+           return EXIT_SUCCESS;
+       }
+
+
+text.s:
+
+       .export _text
+       _text:  .asciiz "Hello world!"
+
+
+We assume that the target file should be named "hello", and the target
+system is the C64.
+
+
+    +---------+
+    | hello.c |
+    +---------+
+                |
+        cc65
+                \/
+    +---------+              +---------+
+    | hello.s |       | text.s  |
+    +---------+              +---------+
+                |                 |
+        ca65              ca65
+         \/                \/
+    +---------+       +---------+              +----------+       +---------+
+    | hello.o |       | text.o  |       |  c64.o   |       | c64.lib |
+    +---------+       +---------+              +----------+       +---------+
+        |                     \         /                      |
+        |                      \       /                       |
+        |                       \     /                        |
+        +----------------------->ld65<-------------------------+
+                                  \/
+                                 hello
+
+
+c64.o (the startup code) and c64.lib (the c64 version of the runtime and C
+library) are provided in binary form in the cc65 package.
+
+
+
+2. The compiler
+---------------
+
+The compiler translates one C source into one assembler source for each
+invocation. It does *NOT* create object files directly, and it is *NOT*
+able to translate more than one file per run.
+
+In the example above, we would use the following command line, to
+translate hello.c into hello.s:
+
+       cc65 -O -I ../include -t c64 hello.c
+
+The -O switch tells the compiler to do an additional optimizer run, which
+is usually a good idea, since it makes the code smaller. If you don't care
+about the size, but want to have slightly faster code, use -Oi to inline
+some runtime functions.
+
+The -I switch gives a search path for the include files. You may also set
+the environment variable CC65_INC to the search path.
+
+The -t switch is followed by the target system.
+
+If the compiler does not complain about errors in our hello world, we will
+have a file named "hello.s" in our directory that contains the assembler
+source for the hello module.
+
+For more information about the compiler see cc65.txt.
+
+
+
+3. The assembler
+----------------
+
+The assembler translates one assembler source into an object file for each
+invocation. The assembler is *NOT* able to translate more than one source
+file per run.
+
+Let's translate the hello.s and text.s files from our example:
+
+       ca65 hello.s
+       ca65 text.s
+
+If the assembler does not complain, we should now have two object files
+(named hello.o and text.o) in the current directory.
+
+For more information about the assembler see ca65.txt.
+
+
+
+4. The linker
+-------------
+
+The linker combines several object and library file into one output file.
+ld65 is very configurable, but fortunately has a builtin configuration for
+the C64, so we don't need to mess with configuration files here.
+
+The compiler uses small functions to do things that cannot be done inline
+without big impact on code size. These runtime functions, together with
+the C library are in an object file archive named after the system, in
+this case "c64.lib". We have to specify this file on the command line so
+that the linker can resolve these functions.
+
+A second file (this time an object file) needed, is the startup code that
+prepares the grounds for the C program to run. The startup file must be
+executed first, so it must be the first file on the linker command line.
+
+Let's link our files to get the final executable:
+
+               ld65 -t c64 -o hello c64.o hello.o text.o c64.lib
+
+The argument after -o specifies the name of the output file, the argument
+after -t gives the target system. As discussed, the startup file must be the
+first file on the command line (you may have to add a path here, if c64.o is
+not in your current directory). Since the library resolves imports in hello.o
+and text.o, it must be specified *after* these files.
+
+After a successful linker run, we have a file named "hello", ready for our
+C64!
+
+For more information about the linker see ld65.txt.
+
+
+
+5. The easy way (using the cl65 utility)
+----------------------------------------
+
+The cl65 utility is able to do all of the steps described above in just
+one call, and it has defaults for some options that are very well suited
+for our example.
+
+To compile both files into one executable enter
+
+       cl65 -O -I ../include hello.c test.s
+
+(The -I switch is not needed if you are working under Linux with the
+include files in the default path, or the CC65_INC environment variable is
+set correctly).
+
+The cl65 utility knows, how to translate C files into object files (it
+will call the compiler and then the assembler). It does also know how to
+create object files from assembler files (it will call the assember for
+that). It knows how to build an executable (it will pass all object files
+to the linker). And, finally, it has the C64 as a default target and will
+supply the correct startup file and runtime library names to the linker,
+so you don't have to care about that.
+
+The one-liner above should give you a C64 executable named "hello" in the
+current directory.
+
+For more information about the compile & link utility see cl65.txt.
+
+
+
+                         
diff --git a/doc/ld65.txt b/doc/ld65.txt
new file mode 100644 (file)
index 0000000..e211eeb
--- /dev/null
@@ -0,0 +1,655 @@
+
+
+                                  ld65
+
+                            A Linker for ca65 Object modules
+
+             (C) Copyright 1998-1999 Ullrich von Bassewitz
+                                   (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. Usage
+
+  3. Detailed workings
+
+  4. Output configuration files
+  4.1 Introduction
+  4.2 Reference
+  4.3 Builtin configurations
+
+  5. Bugs/Feedback
+
+  6. Copyright
+
+
+
+1. Overview
+-----------
+
+ld65 is a replacement for the link65 linker that was part of the cc65 C
+compiler suite developed by John R. Dunning. link65 had some problems and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite
+for the cc65 compiler. ld65 is part of this suite.
+
+The ld65 linker combines several object modules, producing an executable
+file. The object modules may be read from a library created by the ar65
+archiver (this is somewhat faster and more convenient). The linker was
+designed to be as flexible as possible. It complements the features that
+are built into the ca65 macroassembler:
+
+  * Accept any number of segments to form an executable module.
+
+  * Resolve arbitrary expressions stored in the object files.
+
+  * In case of errors, use the meta information stored in the object
+    files to produce helpful error messages. In case of undefined
+    symbols, expression range errors, or symbol type mismatches, ld65 is
+    able to tell you the exact location in the source, where the symbol
+    was referenced.
+
+  * Flexible output. The output of ld65 is highly configurable by a
+    config file. More common platforms are supported by builtin
+    configurations that may be activated by naming the target system.
+    The output generation was designed with different output formats in
+    mind, so adding other formats shouldn't be a great problem.
+
+
+
+2. Usage
+--------
+
+The linker is called as follows:
+
+       Usage: ld65 [options] module ...
+       Options are:
+                       -m name     Create a map file
+                       -o name     Name the default output file
+                       -t type     Type of target system
+                       -v          Verbose mode
+                       -vm         Verbose map file
+                       -C name     Use linker config file
+                       -Ln name    Create a VICE label file
+                       -Lp         Mark write protected segments as such (VICE)
+                       -S addr     Set the default start address
+                       -V          Print linker version
+
+The -m switch (which needs an argument that will used as a filename for
+the generated map file) will cause the linker to generate a map file. The
+map file does contain a detailed overview over the modules used, the
+sizes for the different segments, and a table containing exported
+symbols.
+
+The -o switch is used to give the name of the default output file.
+Depending on your output configuration, this name may NOT be used as name
+for the output file. However, for the builtin configurations, this name
+is used for the output file name.
+
+The argument for the -t switch is the name of the target system. Since
+this switch will activate a builtin configuration, it may not be used
+together with the -C option.
+The following target systems are defined (* = currently unsupported):
+
+       none
+       atari
+       c64
+       c128
+       ace
+       plus4
+       cbm610
+       pet
+       nes
+       apple2
+
+See section 4.3 for more information about the builtin configurations.
+
+Using the -v option, you may enable more output that may help you to
+locate problems. If an undefined symbol is encountered, -v causes the
+linker to print a detailed list of the references (that is, source file
+and line) for this symbol.
+
+-C gives the name of an output config file to use. See section 4 for more
+information about config files. -C may not be used together with -t.
+
+-L allows you to create a file that contains all global labels and may be
+loaded into VICE emulator using the pb (playback) command. You may use
+this to debug your code with VICE. Note: The label feature is very new in
+VICE and has some bugs. If you have problems, please get the latest VICE
+version.
+
+Using -S you may define the default starting address. If and how this
+address is used depends on the config file in use. For the builtin
+configurations, only the "none" system honors an explicit start address,
+all other builtin config provide their own.
+
+-V prints the version number of the linker. If you send any suggestions or
+bugfixes, please include this number.
+
+
+If one of the modules is not found in the current directory, and the
+module name does not have a path component, the value of the environment
+variable CC65_LIB is prepended to the name, and the linker tries to open
+the module with this new name.
+
+
+
+3. Detailed workings
+--------------------
+
+The linker does several things when combining object modules:
+
+First, the command line is parsed from left to right. For each object file
+encountered (object files are recognized by a magic word in the header, so
+the linker does not care about the name), imported and exported
+identifiers are read from the file and inserted in a table. If a library
+name is given (libraries are also recognized by a magic word, there are no
+special naming conventions), all modules in the library are checked if an
+export from this module would satisfy an import from other modules. All
+modules where this is the case are marked. If duplicate identifiers are
+found, the linker issues a warning.
+
+This procedure (parsing and reading from left to right) does mean, that a
+library may only satisfy references for object modules (given directly or
+from a library) named BEFORE that library. With the command line
+
+       ld65 crt0.o clib.lib test.o
+
+the module test.o may not contain references to modules in the library
+clib.lib. If this is the case, you have to change the order of the modules
+on the command line:
+
+       ld65 crt0.o test.o clib.lib
+
+Step two is, to read the configuration file, and assign start addresses
+for the segments and define any linker symbols (see section 4).
+
+After that, the linker is ready to produce an output file. Before doing
+that, it checks it's data for consistency. That is, it checks for
+unresolved externals (if the output format is not relocatable) and for
+symbol type mismatches (for example a zero page symbol is imported by a
+module as absolute symbol).
+
+Step four is, to write the actual target files. In this step, the linker
+will resolve any expressions contained in the segment data. Circular
+references are also detected in this step (a symbol may have a circular
+reference that goes unnoticed if the symbol is not used).
+
+Step five is to output a map file with a detailed list of all modules,
+segments and symbols encountered.
+
+And, last step, if you give the -v switch twice, you get a dump of the
+segment data. However, this may be quite unreadable if you're not a
+developer:-)
+
+
+
+4. Output configuration files
+-----------------------------
+
+Configuration files are used to describe the layout of the output file(s).
+Two major topics are covered in a config file: The memory layout of the
+target architecture, and the assignment of segments to memory areas. In
+addition, several other attributes may be specified.
+
+Case is ignored for keywords, that is, section or attribute names, but it
+is NOT ignored for names and strings.
+
+
+
+4.1 Introduction
+----------------
+
+Memory areas are specified in a "MEMORY" section. Lets have a look at an
+example (this one describes the usable memory layout of the C64):
+
+       MEMORY {
+           RAM1:  start = $0800, size = $9800;
+           ROM1:  start = $A000, size = $2000;
+           RAM2:  start = $C000, size = $1000;
+           ROM2:  start = $E000, size = $2000;
+       }
+
+As you can see, there are two ram areas and two rom areas. The names
+(before the colon) are arbitrary names that must start with a letter, with
+the remaining characters being letters or digits. The names of the memory
+areas are used when assigning segments. As mentioned above, case is
+significant for these names.
+
+The syntax above is used in all sections of the config file. The name
+("ROM1" etc.) is said to be an identifier, the remaining tokens up to the
+semicolon specify attributes for this identifier. You may use the equal
+sign to assign values to attributes, and you may use a comma to separate
+attributes, you may also leave both out. But you MUST use a semicolon to
+mark the end of the attributes for one identifier. The section above may
+also have looked like this:
+
+       # Start of memory section
+       MEMORY
+       {
+           RAM1:
+               start $0800
+               size $9800;
+           ROM1:
+               start $A000
+               size $2000;
+           RAM2:
+               start $C000
+               size $1000;
+           ROM2:
+               start $E000
+               size $2000;
+       }
+
+There are of course more attributes for a memory section than just start
+and size. Start and size are mandatory attributes, that means, each memory
+area defined MUST have these attributes given (the linker will check
+that). I will cover other attributes later. As you may have noticed, I've
+used a comment in the example above. Comments start with a hash mark
+(`#'), the remainder of the line is ignored if this character is found.
+
+Let's assume you have written a program for your trusty old C64, and you
+would like to run it. For testing purposes, it should run in the RAM area.
+So we will start to assign segments to memory sections in the SEGMENTS
+section:
+
+       SEGMENTS {
+           CODE:   load = RAM1, type = ro;
+           RODATA: load = RAM1, type = ro;
+           DATA:   load = RAM1, type = rw;
+           BSS:    load = RAM1, type = bss, define = yes;
+       }
+
+What we are doing here is telling the linker, that all segments go into
+the RAM1 memory area in the order specified in the SEGMENTS section. So
+the linker will first write the CODE segment, then the RODATA segment,
+then the DATA segment - but it will not write the BSS segment. Why? Enter
+the segment type: For each segment specified, you may also specify a
+segment attribute. There are five possible segment attributes:
+
+       ro      means readonly
+       wprot   same as ro but will be marked as write protected in
+               the VICE label file if -Lp is given
+       rw      means read/write
+       bss     means that this is an uninitialized segment
+       empty   will not go in any output file
+
+So, because we specified that the segment with the name BSS is of type
+bss, the linker knows that this is uninitialized data, and will not write
+it to an output file. This is an important point: For the assembler, the
+BSS segment has no special meaning. You specify, which segments have the
+bss attribute when linking. This approach is much more flexible than
+having one fixed bss segment, and is a result of the design decision to
+supporting an arbitrary segment count.
+
+If you specify "type = bss" for a segment, the linker will make sure that
+this segment does only contain uninitialized data (that is, zeroes), and
+issue a warning if this is not the case.
+
+For a bss type segment to be useful, it must be cleared somehow by your
+program (this happens usually in the startup code - for example the
+startup code for cc65 generated programs takes care about that). But how
+does your code know, where the segment starts, and how big it is? The
+linker is able to give that information, but you must request it. This is,
+what we're doing with the "define = yes" attribute in the BSS definitions.
+For each segment, where this attribute is true, the linker will export
+three symbols.
+
+       __NAME_LOAD__   This is set to the address where the segment is
+                       loaded.
+       __NAME_RUN__    This is set to the run address of the segment.
+                       We will cover run addresses later.
+       __NAME_SIZE__   This is set to the segment size.
+
+Replace "NAME" by the name of the segment, in the example above, this
+would be "BSS". These symbols may be accessed by your code.
+
+Now, as we've configured the linker to write the first three segments and
+create symbols for the last one, there's only one question left: Where
+does the linker put the data? It would be very convenient to have the data
+in a file, wouldn't it?
+
+We don't have any files specified above, and indeed, this is not needed in
+a simple configuration like the one above. There is an additional
+attribute "file" that may be specified for a memory area, that gives a
+file name to write the area data into. If there is no file name given, the
+linker will assign the default file name. This is "a.out" or the one given
+with the -o option on the command line. Since the default behaviour is ok
+for our purposes, I did not use the attribute in the example above. Let's
+have a look at it now.
+
+The "file" attribute (the keyword may also be written as "FILE" if you
+like that better) takes a string enclosed in double quotes (`"') that
+specifies the file, where the data is written. You may specifiy the same
+file several times, in that case the data for all memory areas having this
+file name is written into this file, in the order of the memory areas
+defined in the MEMORY section. Let's specify some file names in the MEMORY
+section used above:
+
+       MEMORY {
+           RAM1:  start = $0800, size = $9800, file = %O;
+           ROM1:  start = $A000, size = $2000, file = "rom1.bin";
+           RAM2:  start = $C000, size = $1000, file = %O;
+           ROM2:  start = $E000, size = $2000, file = "rom2.bin";
+       }
+
+The %O used here is a way to specify the default behaviour explicitly: %O
+is replaced by a string (including the quotes) that contains the default
+output name, that is, "a.out" or the name specified with the -o option on
+the command line. Into this file, the linker will first write any segments
+that go into RAM1, and will append then the segments for RAM2, because the
+memory areas are given in this order. So, for the RAM areas, nothing has
+really changed.
+
+We've not used the ROM areas, but we will do that below, so we give the
+file names here. Segments that go into ROM1 will be written to a file
+named "rom1.bin", and segments that go into ROM2 will be written to a file
+named "rom2.bin". The name given on the command line is ignored in both
+cases.
+
+Let us look now at a more complex example. Say, you've successfully tested
+your new "Super Operating System" (SOS for short) for the C64, and you
+will now go and replace the ROMs by your own code. When doing that, you
+face a new problem: If the code runs in RAM, we need not to care about
+read/write data. But now, if the code is in ROM, we must care about it.
+Remember the default segments (you may of course specify your own):
+
+       CODE            read only code
+       RODATA          read only data
+       DATA            read/write data
+       BSS             uninitialized data, read/write
+
+Since the BSS is not initialized, we must not care about it now, but what
+about DATA? DATA contains initialized data, that is, data that was
+explicitly assigned a value. And your program will rely on these values on
+startup. Since there's no other way to remember the contents of the data
+segment, than storing it into one of the ROMs, we have to put it there.
+But unfortunately, ROM is not writeable, so we have to copy it into RAM
+before running the actual code.
+
+The linker cannot help you copying the data from ROM into RAM (this must
+be done by the startup code of your program), but it has some features
+that will help you in this process.
+
+First, you may not only specify a "load" attribute for a segment, but also
+a "run" attribute. The "load" attribute is mandatory, and, if you don't
+specify a "run" attribute, the linker assumes that load area and run area
+are the same. We will use this feature for our data area:
+
+       SEGMENTS {
+           CODE:   load = ROM1, type = ro;
+           RODATA: load = ROM2, type = ro;
+           DATA:   load = ROM2, run = RAM2, type = rw, define = yes;
+           BSS:    load = RAM2, type = bss, define = yes;
+       }
+
+Let's have a closer look at this SEGMENTS section. We specify that the
+CODE segment goes into ROM1 (the one at $A000). The readonly data goes
+into ROM2. Read/write data will be loaded into ROM2 but is run in RAM2.
+That means that all references to labels in the DATA segment are relocated
+to be in RAM2, but the segment is written to ROM2. All your startup code
+has to do is, to copy the data from it's location in ROM2 to the final
+location in RAM2.
+
+So, how do you know, where the data is located? This is the second point,
+where you get help from the linker. Remember the "define" attribute? Since
+we have set this attribute to true, the linker will define three external
+symbols for the data segment that may be accessed from your code:
+
+               __DATA_LOAD__   This is set to the address where the segment is
+                       loaded, in this case, it is an address in ROM2.
+       __DATA_RUN__    This is set to the run address of the segment, in
+                       this case, it is an address in RAM2.
+       __DATA_SIZE__   This is set to the segment size.
+
+So, what your startup code must do, is to copy __DATA_SIZE__ bytes from
+__DATA_LOAD__ to __DATA_RUN__ before any other routines are called. All
+references to labels in the DATA segment are relocated to RAM2 by the
+linker, so things will work properly.
+
+There are some other attributes not covered above. Before starting the
+reference section, I will discuss the remaining things here.
+
+You may request symbols definitions also for memory areas. This may be
+useful for things like a software stack, or an i/o area.
+
+       MEMORY {
+           STACK:  start = $C000, size = $1000, define = yes;
+       }
+
+This will define three external symbols that may be used in your code:
+
+               __STACK_START__         This is set to the start of the memory
+                               area, $C000 in this example.
+
+       __STACK_SIZE__          The size of the area, here $1000.
+
+
+        __STACK_LAST__         This is NOT the same as START+SIZE.
+                               Instead, it it defined as the first
+                               address that is not used by data. If we
+                               don't define any segments for this area,
+                               the value will be the same as START.
+
+A memory section may also have a type. Valid types are
+
+       ro      for readonly memory
+and    rw      for read/write memory.
+
+The linker will assure, that no segment marked as read/write or bss is put
+into a memory area that is marked as readonly.
+
+Unused memory in a memory area may be filled. Use the "fill = yes"
+attribute to request this. The default value to fill unused space is zero.
+If you don't like this, you may specify a byte value that is used to fill
+these areas with the "fillval" attribute. This value is also used to fill
+unfilled areas generated by the assemblers .ALIGN and .RES directives.
+
+Segments may be aligned to some memory boundary. Specify "align = num" to
+request this feature. Num must be a power of two. To align all segments on
+a page boundary, use
+
+       SEGMENTS {
+           CODE:   load = ROM1, type = ro, align = $100;
+           RODATA: load = ROM2, type = ro, align = $100;
+           DATA:   load = ROM2, run = RAM2, type = rw, define = yes,
+                   align = $100;
+           BSS:    load = RAM2, type = bss, define = yes, align = $100;
+       }
+
+If an alignment is requested, the linker will add enough space to the
+output file, so that the new segment starts at an address that is
+divideable by the given number without a remainder. All addresses are
+adjusted accordingly. To fill the unused space, bytes of zero are used,
+or, if the memory area has a "fillval" attribute, that value. Alignment is
+always needed, if you have the used the .ALIGN command in the assembler.
+The alignment of a segment must be equal or greater than the alignment
+used in the .ALIGN command. The linker will check that, and issue a
+warning, if the alignment of a segment is lower than the alignment
+requested in a .ALIGN command of one of the modules making up this
+segment.
+
+For a given segment you may also specify a fixed offset into a memory area or
+a fixed start address. Use this if you want the code to run at a specific
+address (a prominent case is the interrupt vector table which must go at
+address $FFFA). Only one of ALIGN or OFFSET or START may be specified. If the
+directive creates empty space, it will be filled with zero, of with the value
+specified with the "fillval" attribute if one is given. The linker will warn
+you if it is not possible to put the code at the specified offset (this may
+happen if other segments in this area are too large). Here's an example:
+
+       SEGMENTS {
+           VECTORS: load = ROM2, type = ro, start = $FFFA;
+       }
+
+or (for the segment definitions from above)
+
+       SEGMENTS {
+           VECTORS: load = ROM2, type = ro, offset = $1FFA;
+       }
+
+File names may be empty, data from segments assigned to a memory area with
+an empty file name is discarded. This is useful, if the a memory area has
+segments assigned that are empty (for example because they are of type
+bss). In that case, the linker will create an empty output file. This may
+be suppressed by assigning an empty file name to that memory area.
+
+The symbol %S may be used to access the default start address (that is,
+$200 or the value given on the command line with the -S option).
+
+
+
+4.2 Reference
+-------------
+
+
+
+4.3 Builtin configurations
+--------------------------
+
+Here is a list of the builin configurations for the different target
+types:
+
+none:
+               MEMORY {
+           RAM: start = %S, size = $10000, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = rw;
+           RODATA: load = RAM, type = rw;
+           DATA:   load = RAM, type = rw;
+           BSS:    load = RAM, type = bss, define = yes;
+       }
+
+atari:
+       (non-existent)
+
+c64:
+       MEMORY {
+           RAM: start = $7FF, size = $c801, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = ro;
+           RODATA: load = RAM, type = ro;
+           DATA:   load = RAM, type = rw;
+           BSS:    load = RAM, type = bss, define = yes;
+       }
+
+c128:
+       MEMORY {
+           RAM: start = $1bff, size = $a401, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = ro;
+           RODATA: load = RAM, type = ro;
+           DATA:   load = RAM, type = rw;
+           BSS:    load = RAM, type = bss, define = yes;
+       }
+
+ace:
+       (non-existent)
+
+plus4:
+       MEMORY {
+           RAM: start = $0fff, size = $7001, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = ro;
+           RODATA: load = RAM, type = ro;
+           DATA:   load = RAM, type = rw;
+                   BSS:    load = RAM, type = bss, define = yes;
+       }
+
+cbm610:
+       MEMORY {
+           RAM: start = $0001, size = $FFF0, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = ro;
+           RODATA: load = RAM, type = ro;
+           DATA:   load = RAM, type = rw;
+           BSS:    load = RAM, type = bss, define = yes;
+       }
+
+pet:
+       MEMORY {
+           RAM: start = $03FF, size = $7BFF, file = %O;
+       }
+       SEGMENTS {
+           CODE:   load = RAM, type = ro;
+           RODATA: load = RAM, type = ro;
+           DATA:   load = RAM, type = rw;
+           BSS:    load = RAM, type = bss, define = yes;
+       }
+
+nes:
+       MEMORY {
+           RAM: start = $0200, size = $0600, file = "";
+           ROM: start = $8000, size = $8000, file = %O;
+       }
+       SEGMENTS {
+           CODE:    load = ROM, type = ro;
+           RODATA:  load = ROM, type = ro;
+           DATA:    load = ROM, run = RAM, type = rw, define = yes;
+           BSS:     load = RAM, type = bss, define = yes;
+           VECTORS: load = ROM, type = ro, start = $FFFA;
+       }
+
+apple2:
+       MEMORY {
+           RAM: start = $800, size = $8E00, file = %O;
+       }
+       SEGMENTS {
+            CODE: load = RAM, type = ro;
+            RODATA: load = RAM, type = ro;
+            DATA: load = RAM, type = rw;
+            BSS: load = RAM, type = bss, define = yes;
+       }
+
+The "start" attribute for the RAM memory area of the CBM systems is two
+less than the actual start of the basic RAM to account for the two bytes
+load address that is needed on disk and supplied by the startup code.
+
+
+
+5. Bugs/Feedback
+----------------
+
+If you have problems using the linker, if you find any bugs, or if you're
+doing something interesting with it, I would be glad to hear from you.
+Feel free to contact me by email (uz@musoftware.de).
+
+
+
+6. Copyright
+------------
+
+ld65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
+
+
+
+
diff --git a/doc/library.txt b/doc/library.txt
new file mode 100644 (file)
index 0000000..da5d993
--- /dev/null
@@ -0,0 +1,235 @@
+
+
+          Description of the C library for the cc65 C compiler
+
+             (C) Copyright 1998-1999 Ullrich von Bassewitz
+                           (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+  1. Overview
+
+  2. ISO C compatible library
+
+  3. CPU specific stuff - 6502.h
+
+  4. System specific stuff
+
+  5. Direct console I/O - conio.h
+
+  6. Using the joystick - joystick.h
+
+  7. Bugs/Feedback
+
+  8. Copyright
+
+
+
+1. Overview
+-----------
+
+This file contains a description of the library routines available for the
+cc65 C compiler. It is not complete in some areas, so if you miss
+something, have a look into the header files. All functions, that are not
+defined by the ISO C standard have a short comment in the headers,
+explaining their use.
+
+
+
+2. ISO C compatible library
+---------------------------
+
+The C library contains a large subset of the ISO C library. Functions are
+usually missing in areas, where there is no support on typical 6502
+systems. Wide character sets are an example for this.
+
+I will not go into detail about the ISO functions. If a function is not
+mentioned here explicitly, expect it to be available and to behave as
+defined in the C standard.
+
+
+Functions that are NOT available:
+
+  * ftell/fseek/fgetpos/fsetpos
+
+  * tmpfile/tmpnam
+
+  * The scanf family of functions
+
+  * time/asctime/ctime/difftime/asctime/gmtime/localtime/mktime/strftime
+
+  * system
+
+  * All functions that handle floating point numbers in some manner.
+
+  * The div and ldiv functions (because cc65 is not able to return
+    structs).
+
+  * All functions handling wide character strings.
+
+  * Signals and all related functions (having SIGSEGV would be cool:-)
+
+  * rename/remove/rewind
+
+  * setbuf/setvbuf/ungetc
+
+
+
+Functions that are limited in any way:
+
+  * fopen/fread/fwrite/fclose/fputs/fgets/fscanf....
+
+    These functions are built on open/read/write/close. Neither of these
+    low level functions is currently available for the supported systems,
+    and so, fopen and friends do not work. However, the functions exist
+    and are tested to some degree under the ACE operating systems (which
+    is no longer supported).
+
+
+  * The va_... family of macros
+
+    The macros do not work completely as defined by the standard. Since cc65
+    has the wrong calling order, the (non-standard) va_fix macro must be used
+    to access fixed parameters in functions with a variable parameter size.
+    See newvers.txt for a discussion of the problem.
+
+
+  * The character classification functions (is...)
+
+    These functions have unexpected results when called with arguments that
+    are not really chars (are outside the 0..255 range).
+
+
+  * The strerror function
+
+    The function will return "error #n" where n is the error number.
+
+
+  * strcspn/strpbrk/strspn
+
+    These functions have a length limitation of 256 for the second string
+    argument. Since this string gives a character set, and there are only 256
+    distinct characters, this shouldn't be a problem.
+
+
+  * Since there is no such thing as an environment on all supported
+    systems, the getenv function will always return a NULL pointer.
+
+
+  * There is no other locale than the "C" locale. The native locale is
+    identical to the "C" locale.
+
+
+
+3. CPU specific stuff - 6502.h
+------------------------------
+
+The header file 6502.h contains some functions that make only sense with
+the 6502 CPU. Examples are macros to insert more or less useful
+instructions into your C code, or a function to call arbitrary machine
+language subroutines, passing registers in and out.
+
+
+
+4. System specific stuff
+------------------------
+
+For each supported system there's a header file that contains calls or
+defines specific for this system. So, when programming for the C64,
+include c64.h, for the C128, include c128.h and so on. To make the task
+for the Commodore systems easier, there is also a header file named cbm.h
+that will define stuff common for all CBM systems, and include the header
+file for the specific target system.
+
+The header files contain
+
+  * Defines for special keys (like function keys)
+
+  * Defines for special characters (like the graphics characters)
+
+  * Variables with a fixed address in memory that may be used to access
+    special hardware. For the C64 and C128 there is a variable struct
+    named "sid". Writing to the fields of this struct will write to the
+    SID device instead. Using these variables will make your program more
+    readable and more portable. Don't fear ineffective code when using
+    these variables, the compiler will translate reads and writes to these
+    structs into direct memory accesses.
+
+  * Other routines that make only sense for a specific system. One example
+    are routines to write memory locations in the system bank for the CBM
+    600/700 family (called B128/B256 in the US).
+
+
+
+5. Direct console I/O - conio.h
+-------------------------------
+
+The conio header file contains a large set of functions that do screen and
+keyboard I/O. The functions will write directly to the screen or poll the
+keyboard directly with no more help from the operating system than needed.
+This has some disadvantages, but on the other side it's fast and
+reasonably portable. conio implementations exist for the following
+targets:
+
+       c64
+       c128
+       plus/4
+       cbm610          (that is, the complete 600/700 series)
+       pet             (all PETs except the 2001)
+       apple 2
+
+The conio.h header file does also include the system specific header files
+which define constants for special characters and keys.
+
+
+
+6. Using the joystick - joystick.h
+----------------------------------
+
+For systems that have a joystick, joystick.h will define a subroutine to
+read the current value, including constants to evaluate the result of this
+function. To help in writing portable code, the header file will define
+the symbol __JOYSTICK__ on systems that have a joystick.
+
+
+
+7. Bugs/Feedback
+----------------
+
+If you have problems using the library, if you find any bugs, or if you've
+written some extensions or otherwise interesting programs, I would be glad
+to hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+8. Copyright
+------------
+
+This C runtime library implementation for the cc65 compiler is (C)
+Copyright 1998-1999 Ullrich von Bassewitz. For usage of the binaries
+and/or sources the following conditions do apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
+
+
+
+
+              
diff --git a/doc/newvers.txt b/doc/newvers.txt
new file mode 100644 (file)
index 0000000..d93cfe2
--- /dev/null
@@ -0,0 +1,511 @@
+
+This document is slightly outdated! See cc65.txt and library.txt for a more
+up-to-date discussion.
+
+
+
+Discussion of some of the features/non features of the current cc65 version
+---------------------------------------------------------------------------
+
+  1. Copyright
+
+  2. Differences to the original version
+
+  3. Known bugs and limitations
+
+  4. Library
+
+  5. Bugs
+
+
+
+
+1. Copyright
+-----------
+
+This is the original compiler copyright:
+
+--------------------------------------------------------------------------
+  -*- Mode: Text -*-
+
+     This is the copyright notice for RA65, LINK65, LIBR65, and other
+  Atari 8-bit programs.  Said programs are Copyright 1989, by John R.
+  Dunning.  All rights reserved, with the following exceptions:
+
+      Anyone may copy or redistribute these programs, provided that:
+
+  1:  You don't charge anything for the copy.  It is permissable to
+      charge a nominal fee for media, etc.
+
+  2:  All source code and documentation for the programs is made
+      available as part of the distribution.
+
+  3:  This copyright notice is preserved verbatim, and included in
+      the distribution.
+
+      You are allowed to modify these programs, and redistribute the
+  modified versions, provided that the modifications are clearly noted.
+
+      There is NO WARRANTY with this software, it comes as is, and is
+  distributed in the hope that it may be useful.
+
+      This copyright notice applies to any program which contains
+  this text, or the refers to this file.
+
+      This copyright notice is based on the one published by the Free
+  Software Foundation, sometimes known as the GNU project.  The idea
+  is the same as theirs, ie the software is free, and is intended to
+  stay that way.  Everybody has the right to copy, modify, and re-
+  distribute this software.  Nobody has the right to prevent anyone
+  else from copying, modifying or redistributing it.
+
+--------------------------------------------------------------------------
+
+In acknowledgment of this copyright, I will place my own changes to the
+compiler under the same copyright.
+
+However, since the library and all binutils (assembler, archiver, linker)
+are a complete rewrite, they are covered by another copyright:
+
+
+--------------------------------------------------------------------------
+
+                      CC65 C Library and Binutils
+
+                       (C) Copyright 1998 Ullrich von Bassewitz
+
+                           COPYING CONDITIONS
+
+
+  This software is provided 'as-is', without any expressed or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not
+     be misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source
+     distribution
+
+
+--------------------------------------------------------------------------
+
+I will try to contact John, maybe he is also willing to place his sources
+under a less restrictive copyright, after all these years:-)
+
+
+
+
+2. Differences to the original version
+--------------------------------------
+
+This is a list of changes against the cc65 archives. I got the originals
+from:
+
+  http://www.umich.edu/~archive/atari/8bit/Languages/Cc65/
+
+
+
+  * Removed all assembler code from the compiler. It was unportable because
+    it made assumptions about the character set (ATASCII) and made the
+    sources hard to read and to debug.
+
+  * All programs do return an error code, so they may be used by make. All
+    programs try to remove the target file, if there were errors.
+
+  * The assembler now checks several error conditions (others still go
+    undetected - see "known bugs").
+
+  * Removed many bugs from the compiler. One error was invalid code
+    produced by the compiler that went through the assembler since the
+    assembler did not check for ranges itself.
+
+  * Removed many non-portable constructs from the compiler. Code cleanups,
+    rewrite of the function headers and more.
+
+  * New style function prototypes supported instead of the old K&R syntax.
+    The new syntax is a must, that is, the old style syntax is no longer
+    understood. As an extension, unnamed parameters may be used to avoid
+    warnings about unused parameters.
+
+  * New void type. May also be used as a function return type.
+
+  * Changed the memory management in the compiler. Use malloc/free instead
+    of the old homebrew (and unportable) stuff.
+
+  * Default character type is unsigned. This is much more what you want in
+    small systems environments, since a char is often used to represent a
+    small numerical value, and the integer promotion does the wrong thing
+    in those cases. Look at the follwing piece of code:
+
+       char c = read_char ();
+       switch (c) {
+           case 0x80: printf ("c is 0x80\n"); break;
+           default:   printf ("c is something else\n"); break;
+       }
+
+    With signed chars, the code above, will *always* run into the default
+    selector. c is promoted to int, and since it is signed, 0x80 will get
+    promoted to 0xFF80 - which will select the default label. With unsigned
+    chars, the code works as intended (but note: the code works for cc65
+    but it is non portable anyway, since many other compilers have signed
+    chars by default, so be careful! Having unsigned chars is just a
+    convenience thing).
+
+  * Shorter code when using the builtin operators and the lhs of an expr
+    is a constant (e.g. expressions like "c == 0x80" are encoded two
+    bytes shorter).
+
+  * Some optimizations when pushing constants.
+
+  * Character set translation by the compiler. A new -t option was added
+    to set the target system type. Use
+
+       -t0     For no spefic target system (default)
+        -t1     For the atari (does not work completely, since I did not
+                have an ATASCII translation table).
+        -t2     Target system is C64.
+        -t3     Target system is C128.
+        -t4     Target system is ACE.
+       -t5     Target system is Plus/5.
+
+  * Dito for the linker: Allow an option to set the target system and add
+    code to the linker to produce different headers and set the correct
+    start address.
+
+  * Complete rewrite of the C library. See extra chapter.
+
+  * Many changes in the runtime library. Splitted it into more than one
+    file to allow for smaller executables if not all of the code is needed.
+
+  * Allow longer names. Now the first 12 characters are sigificant at the
+    expense of some more memory used at runtime.
+
+  * String constants are now concatenated in all places. This allows
+    things like:
+
+       fputs ("Options:\n"
+              "    -b  bomb computer\n"
+               "    -f  format hard disk\n"
+              "    -k  kill init\n",
+               stderr);
+
+    saving code for more than one call to the function.
+
+  * Several new macros are defined:
+
+      M6502       This one is old - don't use!
+      __CC65__    Use this instead. Defined when compiling with cc65.
+      __ATARI__   Defined when the target system is atari.
+      __CBM__     Defined when compiling for a CBM system as target.
+      __C64__     Defined when the C64 is the target system.
+      __C128__    Defined when compiling for the 128.
+      __ACE__     Defined when compiling for ACE.
+      __PLUS4__          Defined when compiling for the Plus/4.
+
+    The __CC65__ macro has the compiler version as its value, version
+    1.0 of the compiler will define this macro as 0x100.
+
+  * The -a option is gone.
+
+  * The compiler will generate external references (via .globl) only if a
+    function is defined as extern in a module, or not defined but called
+    from a module. The old behaviour was to generate a reference for every
+    function prototype ever seen, which meant that using a header file like
+    stdio.h got most of the C library linked in, even if it was never used.
+
+  * Many new warnings added (about unused parameters, unused variables,
+    compares of unsigneds against zero, function call without prototype
+    and much more).
+
+  * Added a new compiler option (-W) to suppress all warnings.
+
+  * New internal variable __fixargs__ that gives the size of fixed
+    arguments, a function takes. This allows to work (somehow) around the
+    problem, that cc65 has the "wrong" (that is, pascal) calling order. See
+    below ("Known problems") for a discussion.
+
+  * The "empty" preprocessor directive ("#" on a line) is now ignored.
+
+  * Added a "#error" directive to force user errors.
+
+  * Optimization of the code generation. Constant parts of expressions are
+    now detected in many places where the old compiler evaluated the
+    constants at runtime.
+
+  * Allow local static variables (there was code in the original compiler for
+    that, but it did not work). Allow also initialization in this case (no
+    code for that in the original). Local static variables in the top level
+    function block have no penalty, for static variables in nested blocks, the
+    compiler generates a jump around the variable space. To eliminate this,
+    an assembler/linker with support for segments is needed.
+
+  * You cannot return a value from a void function, and must return a value
+    in a non-void function. Violations are flagged as an error.
+
+  * Typedefs added.
+
+  * The nonstandard evaluation of the NOARGC and FIXARGC macros has been
+    replaced by a smart algorithm that does the same thing automagically
+    and without user help (provided there are function prototypes).
+
+  * Function pointers may now be used to call a function without
+    dereferencing. Given a function
+
+       void f1 (void (*f2) ())
+
+    the following was valid before:
+
+         (*f2) ();
+
+    The ANSI standard allows a second form (because there's no ambiguity)
+    which is now also allowed:
+
+         f2 ();
+
+  * Pointer subtraction was completely messed up and did not work (that is,
+    subtraction of a pointer from a pointer produced wrong results).
+
+  * Local struct definitions are allowed.
+
+  * Check types in assignments, parameters for function calls and more.
+
+  * A new long type (32 bit) is available. The integer promotion rules
+    are applied if needed. This includes much more type checking and a
+    better handling of chars (they are handled as chars, not as ints, in
+    all places where this is possible).
+
+  * Integer constants now have an associated type, 'U' and 'L' modifers
+    may be used.
+
+  * The old #asm statement is gone. Instead, there's now a asm ("xxx")
+    statement that has the syntax that is defined by the C++ standard
+    (the C standard does not define an ASM statement). The string literal
+    in parenthesis is inserted in the assembler output. You may also
+    use __asm__ instead of asm (see below).
+
+  * Allow // comments.
+
+  * New compiler option -A (ANSI) that disables several extensions (asm
+    directive, // comments, unnamed function parameters) and also defines
+    a macro named __STRICT_ANSI__. The header files will exclude some
+    non-ANSI functions if __STRICT_ANSI__ is defined (that is, -A is given
+    on the command line).
+    -A will not disable the __asm__ directive (identifiers starting with
+    __ are in the namespace of the implementation).
+
+  * Create optimized code if the address of a variable is a constant. This
+    may be achieved by constructs like "*(char*)0x200 = 0x01" and is used
+    to access absolute memory locations. The compiler detects this case
+    also if structs or arrays are involved and generates direct stores and
+    fetches.
+
+
+
+3. Known problems
+-----------------
+
+  * No floats.
+
+  * Only simple automatic variables may be initialized (no arrays).
+
+  * "Wrong" order of arguments on the stack. The arguments are pushed in
+    the order, the arguments are parsed. That means that the va_xxx macros
+    in stdarg.h are ok (they work as expected), but the fixed parameters of
+    a function with a variable argument list do not match and must be
+    determined with the (non-standard) va_fix macro.
+
+    Using the __fixargs__ kludge, it is possible to write standard conform
+    va_xxx macros to work with variable sized argument lists. However, the
+    fixed parameters in the function itself usually have the wrong values,
+    because the order of the arguments on the stack is reversed compared to
+    a stock C compiler. Pushing the args the other way round requires much
+    work and a more elaborated intermediate code than cc65 has.
+
+    To understand the problem, have a look at this (non working!) sprintf
+    function:
+
+               int sprintf (char* buf, char* format, ...)
+       /* Non working version */
+       {
+           int count;
+           va_list ap;
+           va_start (ap, format);
+                   count = vsprintf (buf, format, ap);
+           va_end (ap);
+           return count;
+       }
+
+    The problem here is in the "format" and "buf" parameters. They do (in
+    most cases) not contain, what the caller gave us as arguments. To
+    access the "real" arguments, use the va_fix macro. It is only valid
+    before the first call to va_arg, and takes the va_list and the number
+    of the fixed argument as parameters. So the right way would be
+
+       int sprintf (char* buf, char* format, ...)
+       /* Working version */
+       {
+           int count;
+           va_list ap;
+           va_start (ap, format);
+                   count = vsprintf (va_fix (ap, 1), va_fix (ap, 2), ap);
+           va_end (ap);
+           return count;
+       }
+
+    The fixed parameter are obtained by using the va_fix macro with the
+    number of the parameter given as second argument. Beware: Since the
+    fixed arguments declared are usually one of the additional parameters,
+    the following code, which tries to be somewhat portable, does *not*
+    work. The assignment will overwrite the other parameters instead,
+    causing unexpected results:
+
+       int sprintf (char* buf, char* format, ...)
+       /* Non working version */
+       {
+           int count;
+           va_list ap;
+           va_start (ap, format);
+        #ifdef __CC65__
+           buf    = va_fix (ap, 1);
+           format = va_fix (ap, 2);
+       #endif
+                   count = vsprintf (buf, format, ap);
+           va_end (ap);
+           return count;
+       }
+
+    To write a portable version of sprintf, use code like this instead:
+
+       int sprintf (char* buf, char* format, ...)
+       /* Working version */
+       {
+           int count;
+           va_list ap;
+           va_start (ap, format);
+       #ifdef __CC65__
+                   count = vsprintf (va_fix (ap, 1), va_fix (ap, 2), ap);
+       #else
+           count = vsprintf (buf, format, ap);
+       #endif
+           va_end (ap);
+           return count;
+       }
+
+    I know, va_fix is a kludge, but at least it *is* possible to write
+    functions with variable sized argument lists in a comfortable manner.
+
+  * The assembler still accepts lots of illegal stuff without an error (and
+    creates wrong code). Be careful!
+
+  * When starting a compiled program twice on the C64 (or 128), you may get
+    other results or the program may even crash. This is because static
+    variables do not have their startup values, they were changed in the
+    first run.
+
+  * There's only *one* symbol table level. It is - via a flag - used for both,
+    locals and global symbols. However, if you have variables in nested
+    blocks, the names may collide with the ones in the upper block. I will
+    probably add real symbol tables some time to remove this problem.
+
+  * Variables in nested blocks are handled inefficiently, especially in loops.
+    The frame on the stack is allocated and deallocated for each loop
+    iteration. There's no way around this, since the compiler has not enough
+    memory to hold a complete function body in memory (it would be able to
+    backpatch the frame generating code on function entry).
+
+
+
+
+4. Library
+----------
+
+The C library is a complete rewrite and has nothing in common with the old
+Atari stuff. When rewriting the library, I was guided by the following
+rules:
+
+  * Use standard conform functions as far as possible. In addition, if
+    there's a ANSI-C compatible function, it should act as defined in the
+    ANSI standard. If if does not act as defined, this is an error.
+
+  * Do not use non-standard functions if the functionality of those
+    functions is covered by a standard function. Use exceptions only, if
+    there is a non-ANSI function that is very popular (example: itoa).
+
+  * Use new style prototpyes and header files.
+
+  * Make the library portable. For example, the complete stdio stuff is
+    based on only four system dependent functions:
+
+       open, read, write, close
+
+    So, if you rewrite these functions for a new system, all others
+    (printf, fprintf, fgets, fputc ...) will work, too.
+
+  * Do not expect a common character set. Unfortunately, I was not able to
+    be completely consequent in this respect. C sources are no problem
+    since the compiler does character translation, but the assembler
+    sources make assumptions about the following characters:
+
+       0       --> code $30
+       +       --> code $2B
+       -       --> code $2D
+
+    All other functions (especially the isxxx ones) are table driven, so
+    only the classification table is system dependent.
+
+
+The first port was for the ACE operating system. The current version has also
+support for the C64, the C128 and the Plus/4 in native mode. The ACE port has
+disk support but no conio module, all others don't have disk support but
+direct console I/O.
+
+Currently the following limitations the are known:
+
+  * getwd (ace) does not work. I get an error (carry flag) with an error
+    code of zero (aceErrStopped). Maybe my code is wrong...
+
+  * The error codes are currently system error codes. They should be
+    translated to something system independent. The ace codes are a good
+    starting point. However, I don't like the idea, that zero is a valid
+    error code, and some other codes are missing ("invalid parameter" and
+    more). As soon as this is done, it is also possible to write a
+    strerror() function to give more descriptive error messages to the
+    user.
+
+  * Many functions not very good tested.
+
+  * The printf and heap functions are way too big. Rewritting _printf
+    and malloc/free in assembler will probably squeeze 2K out of the
+    code.
+
+  * The isxxx functions do not handle EOF correctly. This is probably
+    a permanent restriction, even if it is non-standard. It would require
+    extra code in each of the isxxx functions, since EOF is defined as -1
+    and cannot be handled effectively with the table approach and 8 bit
+    index registers.
+
+  * The strcspn, strpbrk and strspn functions have a string length limitation
+    of 256 for the second argument. This is usually not a problem since the
+    second argument gives a character set, and a character set cannot be
+    larger than 256 chars for all known 6502 systems.
+
+
+
+
+5. Bugs
+-------
+
+Please note that the compiler and the libraries are beta! Send bug reports to
+uz@musoftware.de.
+
+
+
+
diff --git a/doc/readme.1st b/doc/readme.1st
new file mode 100644 (file)
index 0000000..fa1d56b
--- /dev/null
@@ -0,0 +1,34 @@
+
+If you have got the source package, see
+
+       doc/compile.txt
+
+for instructions how to compile the stuff for the different systems.
+
+
+If you have a binary package: Have a look in the doc directory for
+information on how to use the tools. If you are new to cc65, the file
+intro.txt may be of interest to you.
+
+To avoid having to mess with paths, you may want to set the environment
+variables
+
+               CC65_LIB
+       and     CC65_INC
+
+to the directory containing the libraries and the system include files
+respectively. If you have installed cc65 in C:\cc65 (assuming a DOS or
+Windows system), you should use
+
+               set CC65_LIB=c:\cc65\lib
+       and     set CC65_INC=c:\cc65\include
+
+Unix people probably know, how to translate these lines into the
+appropriate Unix commands:-)
+
+Have fun!
+
+
+       Uz
+
+
diff --git a/doc/readme.txt b/doc/readme.txt
new file mode 100644 (file)
index 0000000..b19d0a3
--- /dev/null
@@ -0,0 +1,31 @@
+
+Documentation overview:
+
+
+  ar65.txt     - Describes the ar65 archiver.
+
+  debugging.txt        - Debug programs using the VICE emulator.
+
+  ca65.txt     - Describes the ca65 macro assembler.
+
+  cc65.txt     - Describes the cc65 C compiler.
+
+  cl65.txt     - Describes the cl65 compile & link utility.
+
+  coding.txt   - Containes hints on creating the most effective code
+                 with cc65.
+
+  intro.txt    - Describes the use of the tools by a short "hello world"
+                 example.
+
+  ld65.txt     - Describes the ld65 linker.
+
+  library.txt  - Describes the cc65 runtime and C libraries.
+
+  newvers.txt  - Somewhat outdated. Lists the differences between the
+                 current cc65 release and the original atari version
+                 created by J.R Dunning.
+
+  readme.txt   - This file.
+
+
diff --git a/include/6502.h b/include/6502.h
new file mode 100644 (file)
index 0000000..752fe5d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 6502.h
+ *
+ * Ullrich von Bassewitz, 20.09.1998
+ */
+
+
+
+#ifndef _6502_H
+#define _6502_H
+
+
+
+/* Possible returns of getcpu() */
+#define CPU_6502       0
+#define CPU_65C02      1
+#define CPU_65816      2
+
+unsigned char getcpu (void);
+/* Detect the CPU the program is running on */
+
+
+
+/* Macros for CPU instructions */
+#define        BRK()   __asm__ ("\tbrk")
+#define CLI()  __asm__ ("\tcli")
+#define SEI()  __asm__ ("\tsei")
+#define JAM()  __asm__ ("\t.byte\t$02")
+
+
+
+/* Struct that holds the registers for the sys function */
+struct regs {
+    unsigned char a;           /* A register value */
+    unsigned char x;           /* X register value */
+    unsigned char y;           /* Y register value */
+    unsigned char flags;       /* Flags value */
+    unsigned      pc;          /* Program counter */
+};
+
+/* Defines for the flags in the regs structure */
+#define F_NEG          0x80    /* N flag */
+#define F_OVF          0x40    /* V flag */
+#define F_BRK          0x10    /* B flag */
+#define F_DEC          0x08    /* D flag */
+#define F_IEN                  0x04    /* I flag */
+#define F_ZERO         0x02    /* Z flag */
+#define F_CARRY                0x01    /* C flag */
+
+/* Function to call any machine language subroutine. All registers in the
+ * regs structure are passed into the routine and the results are passed
+ * out. Some of the flags are ignored on input. The called routine must
+ * end with an RTS.
+ */
+void __fastcall__ _sys (struct regs* r);
+
+
+
+/* Set and reset the break vector. The given user function is called if
+ * a break occurs. The values of the registers may be read from the brk_...
+ * variables. The value in brk_pc will point to the address that contains
+ * the brk instruction.
+ * The set_brk function will install an exit handler that will reset the
+ * vector if the program ends.
+ */
+
+extern unsigned char brk_a;    /* A register value */
+extern unsigned char brk_x;    /* X register value */
+extern unsigned char brk_y;    /* Y register value */
+extern unsigned char brk_sr;   /* Status register */
+extern unsigned brk_pc;                /* PC value */
+
+typedef void (*brk_handler) (void);
+/* Type of the break handler */
+
+void __fastcall__ set_brk (brk_handler f);
+/* Set the break vector to the given address, return the old address */
+
+void reset_brk (void);
+/* Reset the break vector to the original value */
+
+
+
+/* End of 6502.h */
+#endif
+
+
+
diff --git a/include/_6525.h b/include/_6525.h
new file mode 100644 (file)
index 0000000..6a29252
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * _6525.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6525_H
+#define __6525_H
+
+
+
+/* Define a structure with the 6525 register offsets. The shadow registers
+ * (if port C is unused) are currently not implemented, we would need a
+ * union to do that, however that would introduce an additional name.
+ */
+struct __6525 {
+    unsigned char      pra;            /* Port register A */
+    unsigned char      prb;            /* Port register B */
+    unsigned char              prc;            /* Port register C */
+    unsigned char      ddra;           /* Data direction register A */
+    unsigned char      ddrb;           /* Data direction register B */
+    unsigned char      ddrc;           /* Data direction register C */
+    unsigned char      cr;             /* Control register */
+    unsigned char      air;            /* Active interrupt register */
+};
+
+
+
+/* End of _6525.h */
+#endif
+
+
+
diff --git a/include/_6526.h b/include/_6526.h
new file mode 100644 (file)
index 0000000..41aecf3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * _6526.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6526_H
+#define __6526_H
+
+
+
+/* Define a structure with the 6526 register offsets */
+struct __6526 {
+    unsigned char      pra;            /* Port register A */
+    unsigned char      prb;            /* Port register B */
+    unsigned char      ddra;           /* Data direction register A */
+    unsigned char      ddrb;           /* Data direction register B */
+    unsigned char      ta_lo;          /* Timer A, low byte */
+    unsigned char      ta_hi;          /* Timer A, high byte */
+    unsigned char              tb_lo;          /* Timer B, low byte */
+    unsigned char      tb_hi;          /* Timer B, high byte */
+    unsigned char              tod_10;         /* TOD, 1/10 sec. */
+    unsigned char      tod_sec;        /* TOD, seconds */
+    unsigned char      tod_min;        /* TOD, minutes */
+    unsigned char      tod_hour;       /* TOD, hours */
+    unsigned char      sdr;            /* Serial data register */
+    unsigned char      icr;            /* Interrupt control register */
+    unsigned char      cra;            /* Control register A */
+    unsigned char      crb;            /* Control register B */
+};
+
+
+
+/* End of _6526.h */
+#endif
+
+
+
diff --git a/include/_6545.h b/include/_6545.h
new file mode 100644 (file)
index 0000000..4b46cfa
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * _6545.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6545_H
+#define __6545_H
+
+
+
+/* Define a structure with the 6545 register offsets */
+struct __6545 {
+    unsigned char              ctrl;           /* Control register */
+    unsigned char      data;           /* Data register */
+};
+
+
+
+/* End of _6545.h */
+#endif
+
+
+
diff --git a/include/_6551.h b/include/_6551.h
new file mode 100644 (file)
index 0000000..4618880
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * _6551.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6551_H
+#define __6551_H
+
+
+
+/* Define a structure with the 6551 register offsets */
+struct __6551 {
+    unsigned char              data;           /* Data register */
+    unsigned char              status;         /* Status register */
+    unsigned char              cmd;            /* Command register */
+    unsigned char      ctrl;           /* Control register */
+};
+
+
+
+/* End of _6551.h */
+#endif
+
+
+
diff --git a/include/_antic.h b/include/_antic.h
new file mode 100644 (file)
index 0000000..110fd2a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * _antic.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __ANTIC_H
+#define __ANTIC_H
+
+
+/* Define a structure with the antic register offsets */
+struct __antic {
+    unsigned char   dmactl; /* direct memory access control */
+    unsigned char   chactl; /* character mode control */
+    unsigned char   dlistl; /* display list pointer low-byte */
+    unsigned char   dlisth; /* display list pointer high-byte */
+    unsigned char   hscrol; /* horizontal scroll enable */
+    unsigned char   vscrol; /* vertical scroll enable */
+    unsigned char   unuse0; /* unused */
+    unsigned char   pmbase; /* msb of p/m base address */
+    unsigned char   unuse1; /* unused */
+    unsigned char   chbase; /* character base address */
+    unsigned char   wsync;  /* wait for horizontal synchronization */
+    unsigned char   vcount; /* vertical line counter */
+    unsigned char   penh;   /* light pen horizontal position */
+    unsigned char   penv;   /* light pen vertical position */
+    unsigned char   nmien;  /* non-maskable interrupt enable */
+    unsigned char   nmires; /* nmi reset/status */
+};
+
+/* End of _antic.h */
+#endif
+
diff --git a/include/_gtia.h b/include/_gtia.h
new file mode 100644 (file)
index 0000000..b188e62
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * _gtia.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __GTIA_H
+#define __GTIA_H
+
+
+/* Define a structure with the gtia register offsets */
+struct __gtia_write {
+    unsigned char   hposp0; /* horizontal position player 0 */
+    unsigned char   hposp1; /* horizontal position player 1 */
+    unsigned char   hposp2; /* horizontal position player 2 */
+    unsigned char   hposp3; /* horizontal position player 3 */
+    unsigned char   hposm0; /* horizontal position missile 0 */
+    unsigned char   hposm1; /* horizontal position missile 1 */
+    unsigned char   hposm2; /* horizontal position missile 2 */
+    unsigned char   hposm3; /* horizontal position missile 3 */
+    unsigned char   sizep0; /* size of player 0 */
+    unsigned char   sizep1; /* size of player 1 */
+    unsigned char   sizep2; /* size of player 2 */
+    unsigned char   sizep3; /* size of player 3 */
+    unsigned char   sizem;  /* size of missiles */
+    unsigned char   grafp0; /* graphics shape player 0 */
+    unsigned char   grafp1; /* graphics shape player 1 */
+    unsigned char   grafp2; /* graphics shape player 2 */
+    unsigned char   grafp3; /* graphics shape player 3 */
+    unsigned char   grafm;  /* graphics shape missiles */
+    unsigned char   colpm0; /* color player and missile 0 */
+    unsigned char   colpm1; /* color player and missile 1 */
+    unsigned char   colpm2; /* color player and missile 2 */
+    unsigned char   colpm3; /* color player and missile 3 */
+    unsigned char   colpf0; /* color playfield 0 */
+    unsigned char   colpf1; /* color playfield 1 */
+    unsigned char   colpf2; /* color playfield 2 */
+    unsigned char   colpf3; /* color playfield 3 */
+    unsigned char   colbk;  /* color background */
+    unsigned char   prior;  /* priority selection */
+    unsigned char   vdelay; /* vertical delay */
+    unsigned char   gractl; /* stick/paddle latch, p/m control */
+    unsigned char   hitclr; /* clear p/m collision */
+    unsigned char   consol; /* console buttons */
+};
+
+/* Define a structure with the gtia register offsets */
+struct __gtia_read {
+    unsigned char   m0pf;   /* missile 0 to playfield collision */
+    unsigned char   m1pf;   /* missile 1 to playfield collision */
+    unsigned char   m2pf;   /* missile 2 to playfield collision */
+    unsigned char   m3pf;   /* missile 3 to playfield collision */
+    unsigned char   p0pf;   /* player 0 to playfield collision */
+    unsigned char   p1pf;   /* player 1 to playfield collision */
+    unsigned char   p2pf;   /* player 2 to playfield collision */
+    unsigned char   p3pf;   /* player 3 to playfield collision */
+    unsigned char   m0pl;   /* missile 0 to player collision */
+    unsigned char   m1pl;   /* missile 1 to player collision */
+    unsigned char   m2pl;   /* missile 2 to player collision */
+    unsigned char   m3pl;   /* missile 3 to player collision */
+    unsigned char   p0pl;   /* player 0 to player collision */
+    unsigned char   p1pl;   /* player 1 to player collision */
+    unsigned char   p2pl;   /* player 2 to player collision */
+    unsigned char   p3pl;   /* player 3 to player collision */
+    unsigned char   trig0;  /* joystick trigger 0 */
+    unsigned char   trig1;  /* joystick trigger 1 */
+    unsigned char   trig2;  /* joystick trigger 2 */
+    unsigned char   trig3;  /* joystick trigger 3 */
+    unsigned char   pal;    /* pal/ntsc flag */
+};
+
+/* End of _gtia.h */
+#endif
+
diff --git a/include/_pbi.h b/include/_pbi.h
new file mode 100644 (file)
index 0000000..435df7c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * _pbi.h
+ *
+ * Freddy Offenga, 4/25/2000
+ *
+ * Internal include file, do not use directly.
+ * Atari parallel bus definitions
+ *
+ */
+
+
+#ifndef __PBI_H
+#define __PBI_H
+
+/* parallel bus interface area */
+#define PBI            ((unsigned char*)0xD100)
+
+/* parallel device IRQ status */
+#define PDVI           ((unsigned char*)0xD1FF)
+
+/* parallel device select */
+#define PDVS           ((unsigned char*)0xD1FF)
+
+/* parallel bus interface RAM area */
+#define PBIRAM         ((unsigned char*)0xD600)
+
+/* parallel device ID 1 */
+#define PDID1          ((unsigned char*)0xD803)
+
+/* parallel device I/O vector */
+#define PDIDV          ((unsigned char*)0xD805)
+
+/* parallel device IRQ vector */
+#define PDIRQV         ((unsigned char*)0xD808)
+
+/* parallel device ID 2 */
+#define PDID2          ((unsigned char*)0xD80B)
+
+/* parallel device vector table */
+#define PDVV           ((unsigned char*)0xD80D)
+
+/* End of _pbi.h */
+#endif
+
diff --git a/include/_pia.h b/include/_pia.h
new file mode 100644 (file)
index 0000000..d102e8a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * _pia.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __PIA_H
+#define __PIA_H
+
+
+/* Define a structure with the pia register offsets */
+struct __pia {
+    unsigned char   porta;  /* port A data r/w */
+    unsigned char   portb;  /* port B data r/w */
+    unsigned char   pactl;  /* port A control */
+    unsigned char   pbctl;  /* port B control */
+};
+
+/* End of _pia.h */
+#endif
+
diff --git a/include/_pokey.h b/include/_pokey.h
new file mode 100644 (file)
index 0000000..424b5c6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * _pokey.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __POKEY_H
+#define __POKEY_H
+
+
+/* Define a structure with the pokey register offsets */
+struct __pokey_write {
+    unsigned char   audf1;  /* audio channel #1 frequency */
+    unsigned char   audc1;  /* audio channel #1 control */
+    unsigned char   audf2;  /* audio channel #2 frequency */
+    unsigned char   audc2;  /* audio channel #2 control */
+    unsigned char   audf3;  /* audio channel #3 frequency */
+    unsigned char   audc3;  /* audio channel #3 control */
+    unsigned char   audf4;  /* audio channel #4 frequency */
+    unsigned char   audc4;  /* audio channel #4 control */
+    unsigned char   audctl; /* audio control */
+    unsigned char   stimer; /* start pokey timers */
+    unsigned char   skrest; /* reset serial port status reg. */
+    unsigned char   potgo;  /* start paddle scan sequence */
+    unsigned char   unuse1; /* unused */
+    unsigned char   serout; /* serial port data output */
+    unsigned char   irqen;  /* interrupt request enable */
+    unsigned char   skctl;  /* serial port control */
+};
+struct __pokey_read {
+    unsigned char   pot0;   /* paddle 0 value */
+    unsigned char   pot1;   /* paddle 1 value */
+    unsigned char   pot2;   /* paddle 2 value */
+    unsigned char   pot3;   /* paddle 3 value */
+    unsigned char   pot4;   /* paddle 4 value */
+    unsigned char   pot5;   /* paddle 5 value */
+    unsigned char   pot6;   /* paddle 6 value */
+    unsigned char   pot7;   /* paddle 7 value */
+    unsigned char   allpot; /* eight paddle port status */
+    unsigned char   kbcode; /* keyboard code */
+    unsigned char   random; /* random number generator */
+    unsigned char   unuse2; /* unused */
+    unsigned char   unuse3; /* unused */
+    unsigned char   serin;  /* serial port input */
+    unsigned char   irqst;  /* interrupt request status */
+    unsigned char   skstat; /* serial port status */
+};
+
+/* End of _pokey.h */
+#endif
+
diff --git a/include/_sid.h b/include/_sid.h
new file mode 100644 (file)
index 0000000..0524d1f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * _sid.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __SID_H
+#define __SID_H
+
+
+
+/* Define a structure with the sid register offsets */
+struct __sid_voice {
+    unsigned                   freq;           /* Frequency */
+    unsigned           pw;             /* Pulse width */
+    unsigned char      ctrl;           /* Control register */
+    unsigned char      ad;             /* Attack/decay */
+    unsigned char      sr;             /* Sustain/release */
+};
+struct __sid {
+    struct __sid_voice v1;             /* Voice 1 */
+    struct __sid_voice         v2;             /* Voice 2 */
+    struct __sid_voice v3;             /* Voice 3 */
+    unsigned           flt_freq;       /* Filter frequency */
+    unsigned char      flt_ctrl;       /* Filter control register */
+    unsigned char      amp;            /* Amplitude */
+    unsigned char      ad1;            /* A/D converter 1 */
+    unsigned char      noise;          /* Noise generator */
+    unsigned char      read3;          /* Value of voice 3 */
+};
+
+
+
+/* End of _sid.h */
+#endif
+
+
+
diff --git a/include/_vdc.h b/include/_vdc.h
new file mode 100644 (file)
index 0000000..4d75386
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * _vdc.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __VDC_H
+#define __VDC_H
+
+
+
+/* Define a structure with the vdc register offsets */
+struct __vdc {
+    unsigned char              ctrl;           /* Control register */
+    unsigned char      data;           /* Data register */
+};
+
+
+
+/* End of _vdc.h */
+#endif
+
+
+
diff --git a/include/_vic.h b/include/_vic.h
new file mode 100644 (file)
index 0000000..91ea80c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * _vic.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __VIC_H
+#define __VIC_H
+
+
+
+/* Define a structure with the vic register offsets */
+struct __vic {
+    unsigned char      spr0_x;         /* Sprite 0, X coordinate */
+    unsigned char      spr0_y;         /* Sprite 0, Y coordinate */
+    unsigned char              spr1_x;         /* Sprite 1, X coordinate */
+    unsigned char      spr1_y;         /* Sprite 1, Y coordinate */
+    unsigned char      spr2_x;         /* Sprite 2, X coordinate */
+    unsigned char      spr2_y;         /* Sprite 2, Y coordinate */
+    unsigned char      spr3_x;         /* Sprite 3, X coordinate */
+    unsigned char      spr3_y;         /* Sprite 3, Y coordinate */
+    unsigned char      spr4_x;         /* Sprite 4, X coordinate */
+    unsigned char      spr4_y;         /* Sprite 4, Y coordinate */
+    unsigned char      spr5_x;         /* Sprite 5, X coordinate */
+    unsigned char      spr5_y;         /* Sprite 5, Y coordinate */
+    unsigned char      spr6_x;         /* Sprite 6, X coordinate */
+    unsigned char      spr6_y;         /* Sprite 6, Y coordinate */
+    unsigned char      spr7_x;         /* Sprite 7, X coordinate */
+    unsigned char      spr7_y;         /* Sprite 7, Y coordinate */
+    unsigned char      spr_hi_x;       /* High bits of X coordinate */
+    unsigned char      ctrl1;          /* Control register 1 */
+    unsigned char      rasterline;     /* Current raster line */
+    unsigned char      strobe_x;       /* Light pen, X position */
+    unsigned char      strobe_y;       /* Light pen, Y position */
+    unsigned char      spr_ena;        /* Enable sprites */
+    unsigned char      ctrl2;          /* Control register 2 */
+    unsigned char      spr_exp_x;      /* Expand sprites in X dir */
+    unsigned char      addr;           /* Address of chargen and video ram */
+    unsigned char      irr;            /* Interrupt request register */
+    unsigned char      imr;            /* Interrupt mask register */
+    unsigned char      spr_bg_prio;    /* Priority to background */
+    unsigned char      spr_mcolor;     /* Sprite multicolor bits */
+    unsigned char      spr_exp_y;      /* Expand sprites in Y dir */
+    unsigned char      spr_coll;       /* Sprite/sprite collision reg */
+    unsigned char      spr_bg_coll;    /* Sprite/background collision reg */
+    unsigned char              bordercolor;    /* Border color */
+    unsigned char      bgcolor0;       /* Background color 0 */
+    unsigned char      bgcolor1;       /* Background color 1 */
+    unsigned char      bgcolor2;       /* Background color 2 */
+    unsigned char      bgcolor3;       /* Background color 3 */
+    unsigned char      spr_mcolor0;    /* Color 0 for multicolor sprites */
+    unsigned char              spr_mcolor1;    /* Color 1 for multicolor sprites */
+    unsigned char      spr0_color;     /* Color sprite 0 */
+    unsigned char              spr1_color;     /* Color sprite 1 */
+    unsigned char      spr2_color;     /* Color sprite 2 */
+    unsigned char      spr3_color;     /* Color sprite 3 */
+    unsigned char      spr4_color;     /* Color sprite 4 */
+    unsigned char      spr5_color;     /* Color sprite 5 */
+    unsigned char      spr6_color;     /* Color sprite 6 */
+    unsigned char      spr7_color;     /* Color sprite 7 */
+
+    /* The following ones are only valid in the C128: */
+    unsigned char      x_kbd;          /* Additional keyboard lines */
+    unsigned char      clock;          /* Clock switch bit */
+};
+
+
+
+/* End of _vic.h */
+#endif
+
+
+
diff --git a/include/ace.h b/include/ace.h
new file mode 100644 (file)
index 0000000..4b7e211
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * ace.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _ACE_H
+#define _ACE_H
+
+
+
+#ifndef _STDDEF_H
+#include <stddef.h>
+#endif
+
+
+
+struct aceDirentBuf {
+    unsigned long   ad_size;                   /* Size in bytes */
+    unsigned char   ad_date [8];       /* YY:YY:MM:DD:HH:MM:SS:TW */
+    char            ad_type [4];       /* File type as ASCIIZ string */
+    unsigned char   ad_flags;          /* File flags */
+    unsigned char   ad_usage;           /* More flags */
+    unsigned char   ad_namelen;         /* Length of name */
+    char            ad_name [17];       /* Name itself, ASCIIZ */
+};
+
+int aceDirOpen (char* dir);
+int aceDirClose (int handle);
+int aceDirRead (int handle, struct aceDirentBuf* buf);
+
+/* Type of an ACE key. Key in low byte, shift mask in high byte */
+typedef unsigned int aceKey;
+
+/* #defines for the shift mask returned by aceConGetKey */
+#define aceSH_KEY              0x00FF  /* Mask key itself */
+#define aceSH_MASK             0xFF00  /* Mask shift mask */
+#define aceSH_EXT              0x2000  /* Extended key */
+#define aceSH_CAPS             0x1000  /* Caps lock key */
+#define aceSH_ALT              0x0800  /* Alternate key */
+#define aceSH_CTRL             0x0400  /* Ctrl key */
+#define aceSH_CBM              0x0200  /* Commodore key */
+#define aceSH_SHIFT            0x0100  /* Shift key */
+
+/* #defines for the options in aceConSetOpt/aceConGetOpt */
+#define aceOP_PUTMASK          1       /* Console put mask */
+#define        aceOP_CHARCOLOR         2       /* Character color */
+#define aceOP_CHARATTR         3       /* Character attribute */
+#define aceOP_FILLCOLOR                4       /* Fill color */
+#define aceOP_FILLATTR         5       /* Fill attribute */
+#define aceOP_CRSCOLOR         6       /* Cursor color */
+#define aceOP_CRSWRAP          7       /* Force cursor wrap */
+#define aceOP_SHSCROLL         8       /* Shift keys for scrolling */
+#define aceOP_MOUSCALE         9       /* Mouse scaling */
+#define aceOP_RPTDELAY         10      /* Key repeat delay */
+#define aceOP_RPTRATE          11      /* Key repeat rate */
+
+/* Console functions */
+void aceConWrite (char* buf, size_t count);
+void aceConPutLit (int c);
+void aceConPos (unsigned x, unsigned y);
+void aceConGetPos (unsigned* x, unsigned* y);
+unsigned aceConGetX (void);
+unsigned aceConGetY (void);
+char* aceConInput (char* buf, unsigned initial);
+int aceConStopKey (void);
+aceKey aceConGetKey (void);
+int aceConKeyAvail (aceKey* key);
+void aceConKeyMat (char* matrix);
+void aceConSetOpt (unsigned char opt, unsigned char val);
+int aceConGetOpt (unsigned char opt);
+
+/* Misc stuff */
+int aceMiscIoPeek (unsigned addr);
+void aceMiscIoPoke (unsigned addr, unsigned char val);
+
+
+
+/* End of ace.h */
+#endif
+
+
+
diff --git a/include/apple2.h b/include/apple2.h
new file mode 100644 (file)
index 0000000..a89052d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * apple2.h
+ *
+ * Written by Kevin Ruland.
+ */
+
+
+
+#ifndef _APPLE2_H
+#define _APPLE2_H
+
+
+
+/* Color Defines
+ * Since Apple2 does not support color text these defines are only
+ * used to get the library to compile correctly.  They should not be used
+ * in user code
+ */
+#define COLOR_BLACK    0x00
+#define COLOR_WHITE    0x01
+
+
+
+/* Characters codes */
+#define CH_DEL                 0x7F
+#define CH_ESC                 0x1B
+#define CH_CURS_UP     0x0B
+#define CH_CURS_DOWN   0x0A
+
+/* These are defined to be OpenApple + NumberKey */
+#define CH_F1          0xB1
+#define CH_F2          0xB2
+#define CH_F3          0xB3
+#define CH_F4          0xB4
+#define CH_F5          0xB5
+#define CH_F6          0xB6
+#define CH_F7          0xB7
+#define CH_F8          0xB8
+#define CH_F9          0xB9
+#define CH_F10                 0xB0
+
+#define CH_ULCORNER    '+'
+#define CH_URCORNER    '+'
+#define CH_LLCORNER    '+'
+#define CH_LRCORNER    '+'
+#define CH_TTEE        '+'
+#define CH_BTEE        '+'
+#define CH_LTEE        '+'
+#define CH_RTEE        '+'
+#define CH_CROSS       '+'
+
+
+
+/* End of apple2.h */
+#endif
+
+
+
diff --git a/include/assert.h b/include/assert.h
new file mode 100644 (file)
index 0000000..15f0bc6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * assert.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+
+
+#undef assert
+#ifdef NDEBUG
+#  define assert(expr)
+#else
+extern void _afailed (const char*, unsigned);
+#  define assert(expr) if ((expr) == 0) _afailed (__FILE__, __LINE__)
+#endif
+
+
+
+/* End of assert.h */
+#endif
+
+
+
diff --git a/include/atari.h b/include/atari.h
new file mode 100644 (file)
index 0000000..da4e012
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * atari.h
+ *
+ * Contributing authors:
+ *     Mark Keates
+ *     Freddy Offenga
+ *     Christian Groessler
+ */
+
+#ifndef _ATARI_H
+#define _ATARI_H
+
+/* Color Defines */
+#define COLOR_BLACK    0x00
+#define COLOR_WHITE    0x0E
+
+/* Characters codes */
+#define CH_DEL                 0xFE
+#define CH_ESC                 0x1B
+#define CH_CURS_UP     28
+#define CH_CURS_DOWN   29
+#define CH_CURS_LEFT    30
+#define CH_CURS_RIGHT   31
+
+#define CH_TAB          0x7F   /* tabulator */
+#define CH_EOL          0x0B   /* end-of-line marker */
+#define CH_CLR          0x7D   /* clear screen */
+#define CH_BEL          0xFD   /* bell */
+#define CH_RUBOUT       0x7E   /* back space (rubout) */
+#define CH_DELLINE      0x9C   /* delete line */
+#define CH_INSLINE      0x9D   /* insert line */
+
+/* These are defined to be Atari + NumberKey */
+#define CH_F1          177
+#define CH_F2          178
+#define CH_F3          179
+#define CH_F4          180
+#define CH_F5          181
+#define CH_F6          182
+#define CH_F7          183
+#define CH_F8          184
+#define CH_F9          185
+#define CH_F10                 176
+
+#define CH_ULCORNER    0x11
+#define CH_URCORNER    0x05
+#define CH_LLCORNER    0x1A
+#define CH_LRCORNER    0x03
+#define CH_TTEE        0x17
+#define CH_BTEE        0x18
+#define CH_LTEE        0x01
+#define CH_RTEE        0x04
+#define CH_CROSS       0x19
+#define CH_HLINE        0x12
+#define CH_VLINE        0x16
+
+/* Define hardware */
+#include <_gtia.h>
+#define GTIA (*(struct __gtia_write*)0xD000)
+#define GTIA (*(struct __gtia_read*)0xD000)
+
+#include <_pbi.h>
+
+#include <_pokey.h>
+#define POKEY (*(struct __pokey_write*)0xD200)
+#define POKEY (*(struct __pokey_read*)0xD200)
+
+#include <_pia.h>
+#define PIA (*(struct __pia*)0xD300)
+
+#include <_antic.h>
+#define ANTIC (*(struct __antic*)0xD400)
+
+/* End of atari.h */
+#endif
diff --git a/include/c128.h b/include/c128.h
new file mode 100644 (file)
index 0000000..a8bd86c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * c128.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _C128_H
+#define _C128_H
+
+
+
+/* Additional key defines */
+#define CH_F1                  133
+#define CH_F2                  137
+#define CH_F3                  134
+#define CH_F4                  138
+#define CH_F5                  135
+#define CH_F6                  139
+#define CH_F7                  136
+#define CH_F8                  140
+
+
+
+/* Color defines */
+#define COLOR_BLACK            0x00
+#define COLOR_WHITE            0x01
+#define COLOR_RED              0x02
+#define COLOR_CYAN             0x03
+#define COLOR_VIOLET           0x04
+#define COLOR_GREEN            0x05
+#define COLOR_BLUE             0x06
+#define COLOR_YELLOW           0x07
+#define COLOR_ORANGE           0x08
+#define COLOR_BROWN            0x09
+#define COLOR_LIGHTRED         0x0A
+#define COLOR_GRAY1            0x0B
+#define COLOR_GRAY2            0x0C
+#define COLOR_LIGHTGREEN       0x0D
+#define COLOR_LIGHTBLUE        0x0E
+#define COLOR_GRAY3            0x0F
+
+
+
+/* Define hardware */
+#include <_vic.h>
+#define VIC    (*(struct __vic*)0xD000)
+
+#include <_sid.h>
+#define        SID     (*(struct __sid*)0xD400)
+
+#include <_6526.h>
+#define CIA1   (*(struct __6526*)0xDC00)
+#define CIA2   (*(struct __6526*)0xDD00)
+
+
+
+/* Define special memory areas */
+#define COLOR_RAM      ((unsigned char*)0xD800)
+
+
+
+/* End of c128.h */
+#endif
+
+
+
diff --git a/include/c64.h b/include/c64.h
new file mode 100644 (file)
index 0000000..bb5db28
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * c64.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _C64_H
+#define _C64_H
+
+
+
+/* Additional key defines */
+#define CH_F1                  133
+#define CH_F2                  137
+#define CH_F3                  134
+#define CH_F4                  138
+#define CH_F5                  135
+#define CH_F6                  139
+#define CH_F7                  136
+#define CH_F8                  140
+
+
+
+/* Color defines */
+#define COLOR_BLACK            0x00
+#define COLOR_WHITE            0x01
+#define COLOR_RED              0x02
+#define COLOR_CYAN             0x03
+#define COLOR_VIOLET           0x04
+#define COLOR_GREEN            0x05
+#define COLOR_BLUE             0x06
+#define COLOR_YELLOW           0x07
+#define COLOR_ORANGE           0x08
+#define COLOR_BROWN            0x09
+#define COLOR_LIGHTRED         0x0A
+#define COLOR_GRAY1            0x0B
+#define COLOR_GRAY2            0x0C
+#define COLOR_LIGHTGREEN       0x0D
+#define COLOR_LIGHTBLUE        0x0E
+#define COLOR_GRAY3            0x0F
+
+
+
+/* Define hardware */
+#include <_vic.h>
+#define VIC    (*(struct __vic*)0xD000)
+
+#include <_sid.h>
+#define        SID     (*(struct __sid*)0xD400)
+
+#include <_6526.h>
+#define CIA1   (*(struct __6526*)0xDC00)
+#define CIA2   (*(struct __6526*)0xDD00)
+
+
+
+/* Define special memory areas */
+#define COLOR_RAM      ((unsigned char*)0xD800)
+
+
+
+/* End of c64.h */
+#endif
+
+
+
diff --git a/include/cbm.h b/include/cbm.h
new file mode 100644 (file)
index 0000000..d3b62a1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * cbm.h
+ *
+ * Ullrich von Bassewitz, 07.08.1998
+ */
+
+
+
+#ifndef _CBM_H
+#define _CBM_H
+
+
+
+/* Load the system specific files here, if needed */
+#ifdef __C64__
+#ifndef _C64_H
+#include <c64.h>
+#endif
+#endif
+
+#ifdef __C128__
+#ifndef _C128_H
+#include <c128.h>
+#endif
+#endif
+
+#ifdef __PLUS4__
+#ifndef _PLUS4_H
+#include <plus4.h>
+#endif
+#endif
+
+#ifdef __CBM610__
+#ifndef _CBM610_H
+#include <cbm610.h>
+#endif
+#endif
+
+#ifdef __PET__
+#ifndef _PET_H
+#include <pet.h>
+#endif
+#endif
+
+
+
+/* Characters codes (CBM charset) */
+#define CH_HLINE                96
+#define CH_VLINE               125
+#define        CH_ULCORNER             176
+#define CH_URCORNER            174
+#define CH_LLCORNER            173
+#define CH_LRCORNER            189
+#define CH_TTEE                        178
+#define CH_RTEE                        179
+#define CH_BTEE                        177
+#define CH_LTEE                        171
+#define CH_CROSS               123
+#define CH_CURS_UP             145
+#define CH_CURS_DOWN            17
+#define CH_CURS_LEFT           157
+#define CH_CURS_RIGHT           29
+#define CH_PI                  126
+#define CH_DEL                  20
+#define CH_INS                 148
+#define CH_ESC                  95
+
+
+
+/* End of cbm.h */
+#endif
+
+
+
diff --git a/include/cbm610.h b/include/cbm610.h
new file mode 100644 (file)
index 0000000..14c7b50
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * cbm610.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _CBM610_H
+#define _CBM610_H
+
+
+
+/* Additional key defines */
+#define CH_F1                  224
+#define CH_F2                  225
+#define CH_F3                  226
+#define CH_F4                  227
+#define CH_F5                  228
+#define CH_F6                  229
+#define CH_F7                  230
+#define CH_F8                  231
+#define CH_F9                  232
+#define CH_F10                 233
+#define CH_F11                 234
+#define CH_F12                 235
+#define CH_F13                 236
+#define CH_F14                 237
+#define CH_F15                 238
+#define CH_F16                 239
+#define CH_F17                 240
+#define CH_F18                 241
+#define CH_F19                 242
+#define CH_F20                 243
+
+
+
+/* Color defines */
+#define COLOR_BLACK            0x00
+#define COLOR_WHITE            0x01
+
+
+
+/* Special routines to write bytes and words in the system bank */
+void __fastcall__ pokebsys (unsigned addr, unsigned char val);
+void __fastcall__ pokewsys (unsigned addr, unsigned val);
+
+
+
+/* Define hardware */
+#include <_6545.h>
+#define CRTC   (*(struct __6545)0xD800)
+
+#include <_sid.h>
+#define        SID     (*(struct __sid*)0xDA00)
+
+#include <_6526.h>
+#define CIA    (*(struct __cia*)0xDC00)
+
+#include <_6551.h>
+#define ACIA   (*(struct __6551*)0xDD00)
+
+#include <_6525.h>
+#define TPI1   (*(struct __6525*)0xDE00)
+#define TPI2   (*(struct __6525*)0xDF00)
+
+
+
+/* End of cbm610.h */
+#endif
+
+
+
diff --git a/include/conio.h b/include/conio.h
new file mode 100644 (file)
index 0000000..552b8d5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * conio.h
+ *
+ * Ullrich von Bassewitz, 06.08.1998
+ *
+ *
+ * This is the direct console interface for cc65. I do not like the function
+ * names very much, but the first version started as a rewrite of Borlands
+ * conio, and, even if the interface has changed, the names did not.
+ *
+ * The interface does direct screen I/O, so it is fast enough for most
+ * programs. I did not implement text windows, since many applications do
+ * not need them and should not pay for the additional overhead. It should
+ * be easy to add text windows on a higher level if needed,
+ *
+ * Most routines do not check the parameters. This may be unfortunate but is
+ * also related to speed. The coordinates are always 0/0 based.
+ *
+ */
+
+
+
+#ifndef _CONIO_H
+#define _CONIO_H
+
+
+
+#ifndef _STDARG_H
+#  include <stdarg.h>
+#endif
+
+/* Read the CBM file if we're compiling for a CBM machine */
+#ifdef __CBM__
+#  ifndef _CBM_H
+#    include <cbm.h>
+#  endif
+#endif
+
+#ifdef __APPLE2__
+#  ifndef _APPLE2_H
+#    include <apple2.h>
+#  endif
+#endif
+
+#ifdef __ATARI__
+#  ifndef _ATARI_H
+#    include <atari.h>
+#  endif
+#endif
+
+
+
+/*****************************************************************************/
+/*                                Functions                                 */
+/*****************************************************************************/
+
+
+
+void clrscr (void);
+/* Clear the whole screen and put the cursor into the top left corner */
+
+unsigned char kbhit (void);
+/* Return true if there's a key waiting, return false if not */
+
+void __fastcall__ gotox (unsigned char x);
+/* Set the cursor to the specified X position, leave the Y position untouched */
+
+void __fastcall__ gotoy (unsigned char y);
+/* Set the cursor to the specified Y position, leave the X position untouched */
+
+void __fastcall__ gotoxy (unsigned char x, unsigned char y);
+/* Set the cursor to the specified position */
+
+unsigned char wherex (void);
+/* Return the X position of the cursor */
+
+unsigned char wherey (void);
+/* Return the Y position of the cursor */
+
+void __fastcall__ cputc (char c);
+/* Output one character at the current cursor position */
+
+void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
+/* Same as "gotoxy (x, y); cputc (c);" */
+
+void __fastcall__ cputs (const char* s);
+/* Output a NUL terminated string at the current cursor position */
+
+void __fastcall__ cputsxy (unsigned char x, unsigned char y, const char* s);
+/* Same as "gotoxy (x, y); puts (s);" */
+
+int cprintf (const char* format, ...);
+/* Like printf, but uses direct screen I/O */
+
+int vcprintf (const char* format, va_list ap);
+/* Like vprintf, but uses direct screen I/O */
+
+char cgetc (void);
+/* Return a character from the keyboard. If there is no character available,
+ * the functions waits until the user does press a key. If cursor is set to
+ * 1 (see below), a blinking cursor is displayed while waiting.
+ */
+
+unsigned char __fastcall__ cursor (unsigned char onoff);
+/* If onoff is 1, a cursor is display when waiting for keyboard input. If
+ * onoff is 0, the cursor is hidden when waiting for keyboard input. The
+ * function returns the old cursor setting.
+ */
+
+unsigned char __fastcall__ revers (unsigned char onoff);
+/* Enable/disable reverse character display. This may not be supported by
+ * the output device. Return the old setting.
+ */
+
+unsigned char __fastcall__ textcolor (unsigned char color);
+/* Set the color for text output. The old color setting is returned. */
+
+unsigned char __fastcall__ bgcolor (unsigned char color);
+/* Set the color for the background. The old color setting is returned. */
+
+unsigned char __fastcall__ bordercolor (unsigned char color);
+/* Set the color for the border. The old color setting is returned. */
+
+void __fastcall__ chline (unsigned char length);
+/* Output a horizontal line with the given length starting at the current
+ * cursor position.
+ */
+
+void __fastcall__ chlinexy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); chline (length);" */
+
+void __fastcall__ cvline (unsigned char length);
+/* Output a vertical line with the given length at the current cursor
+ * position.
+ */
+
+void __fastcall__ cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); cvline (length);" */
+
+void __fastcall__ cclear (unsigned char length);
+/* Clear part of a line (write length spaces). */
+
+void __fastcall__ cclearxy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); cclear (length);" */
+
+void __fastcall__ screensize (unsigned char* x, unsigned char* y);
+/* Return the current screen size. */
+
+void __fastcall__ cputhex8 (unsigned char val);
+void __fastcall__ cputhex16 (unsigned val);
+/* These shouldn't be here... */
+
+
+/* End of conio.h */
+#endif
+
+
+
diff --git a/include/ctype.h b/include/ctype.h
new file mode 100644 (file)
index 0000000..3a1e637
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ctype.h
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ *
+ */
+
+
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+
+
+int __fastcall__ isalnum (int c);
+int __fastcall__ isalpha (int c);
+int __fastcall__ iscntrl (int c);
+int __fastcall__ isdigit (int c);
+int __fastcall__ isgraph (int c);
+int __fastcall__ islower (int c);
+int __fastcall__ isprint (int c);
+int __fastcall__ ispunct (int c);
+int __fastcall__ isspace (int c);
+int __fastcall__ isupper (int c);
+int __fastcall__ isxdigit (int c);
+#ifndef __STRICT_ANSI__
+int __fastcall__ isblank (int c);      /* cc65 (and GNU) extension */
+#endif
+
+int __fastcall__ toupper (int c);      /* Always external */
+int __fastcall__ tolower (int c);      /* Always external */
+
+
+
+/* When inlining of known function is enabled, overload most of the above
+ * functions by macros. The function prototypes are again available after
+ * #undef'ing the macros.
+*/
+#ifdef __OPT_s__
+
+
+extern unsigned char _ctype[256];
+
+#define isalnum(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$07"), __AX__)
+#define isalpha(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$03"), __AX__)
+#define iscntrl(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$10"), __AX__)
+#define isdigit(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$04"), __AX__)
+#define isgraph(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$30\n\tand\t#$30"), __AX__)
+#define islower(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$01"), __AX__)
+#define isprint(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$10\n\tand\t#$10"), __AX__)
+#define ispunct(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$37\n\tand\t#$37"), __AX__)
+#define isspace(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$60"), __AX__)
+#define isupper(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$02"), __AX__)
+#define isxdigit(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$08"), __AX__)
+
+#ifndef __STRICT_ANSI__
+/* cc65 and GNU extension */
+#define isblank(c)  (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$80"), __AX__)
+#endif
+
+
+#endif
+
+
+
+/* End of ctype.h */
+#endif
+
+
+
diff --git a/include/dbg.h b/include/dbg.h
new file mode 100644 (file)
index 0000000..7aa565b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * dbg.h
+ *
+ * Ullrich von Bassewitz, 08.08.1998
+ *
+ *
+ * This is the interface to the cc65 debugger. Since many of the functions
+ * used for the debugger are quite usable even in another context, they
+ * are declared here.
+ *
+ * To use the debugger, just call DbgStart in your application. This will
+ * clear the screen and startup the debugger with the program counter
+ * pointing to the next instruction after the call to DbgStart. Once DbgStart
+ * has been executed, the debugger will also catch any BRK opcode. Use the
+ * BREAK function declared below to insert additional breakpoints into your
+ * code.
+ *
+ * There are currently a lot of things that cannot be debugged, graphical
+ * applications are an example. The debugger does not save your screen
+ * contents, so even your text screen gets destroyed. However, you can
+ * debug the C and runtime library, even if the debugger is using this
+ * stuff itself.
+ *
+ * Note: When using the debugger, there are some other identifiers with
+ * external linkage, that start with Dbg. Avoid those names if you use the
+ * module.
+ */
+
+
+
+#ifndef _DBG_H
+#define _DBG_H
+
+
+
+/*****************************************************************************/
+/*                           Utuility functions                             */
+/*****************************************************************************/
+
+
+
+unsigned __fastcall__ DbgDisAsm (unsigned Addr, char* Buf, unsigned char Len);
+/* Disassemble one instruction at address addr into the given buffer.
+ * The resulting line has the format, "AAAA__BB_BB_BB___OPC_OPERAND",
+ * where AAAA is the hexadecimal representation of addr, BB are the
+ * bytes (in hex) that make the instruction, OPC is the mnemonic, and
+ * OPERAND is an operand for the instruction.
+ * The buffer is filled with spaces up to the given length and terminated as
+ * a usual C string. NOTE: Buf must be able to hold Len+1 characters.
+ * The function returns the length of the disassembled instruction, so,
+ * to disassemble the next instruction, add the return value to addr
+ * and call the function again.
+ */
+
+unsigned __fastcall__ DbgDisAsmLen (unsigned Addr);
+/* Disassemble one instruction, but do only return the length, do not
+ * create a visible representation. This function is useful when
+ * disassembling backwards, it is much faster than DbgDisAsm.
+ */
+
+int __fastcall__ DbgIsRAM (unsigned Addr);
+/* Return true if we can read and write the given address */
+
+char* DbgMemDump (unsigned Addr, char* Buf, unsigned char Len);
+/* Create a line of a memory dump in the given buffer. The buffer contains
+ * the starting address (4 digits hex), then Len bytes in this format:
+ * "AAAA__XX_YY_ZZ_...". The passed char buffer must hold Len*3+5 bytes
+ * plus a terminator byte.
+ * The function does not work correctly if the created string is longer
+ * than 255 bytes.
+ * The return value is Buf.
+ */
+
+
+
+/*****************************************************************************/
+/*                        High level user interface                         */
+/*****************************************************************************/
+
+
+
+void __fastcall__ DbgInit (unsigned unused);
+/* Initialize the debugger. Use 0 as parameter. The debugger will popup on
+ * next brk encountered.
+ */
+
+#define BREAK()                __asm__ ("\tbrk")
+/* Use this to insert breakpoints into your code */
+
+
+
+/* End of dbg.h */
+#endif
+
+
+
diff --git a/include/errno.h b/include/errno.h
new file mode 100644 (file)
index 0000000..a69baf8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * errno.h
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ *
+ */
+
+
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+
+
+/* Operating system specific error codes */
+extern unsigned char _oserror;
+
+/* Mapper function, don't call directly */
+void _maperrno (void);
+
+/* This one is called under the hood. User callable. */
+int __fastcall__ _osmaperrno (unsigned char oserror);
+
+/* System error codes go here */
+extern int _errno;
+
+/* errno must be a macro, here the mapper is called */
+#define errno          (_maperrno(), _errno)
+
+
+
+/* Possible error codes */
+#define        ENOENT          1       /* No such file or directory */
+#define ENOMEM         2       /* Out of memory */
+#define EACCES         3       /* Permission denied */
+#define ENODEV         4       /* No such device */
+#define EMFILE         5       /* Too many open files */
+#define EBUSY          6       /* Device or resource busy */
+#define EINVAL         7       /* Invalid argument */
+#define ENOSPC         8       /* No space left on device */
+#define EEXIST         9       /* File exists */
+#define EAGAIN         10      /* Try again */
+#define EIO            11      /* I/O error */
+#define EINTR          12      /* Interrupted system call */
+#define ENOSYS         13      /* Function not implemented */
+#define ESPIPE         14      /* Illegal seek */
+#define EUNKNOWN               15      /* Unknown OS specific error */
+
+
+
+#endif
+
+
+
diff --git a/include/fcntl.h b/include/fcntl.h
new file mode 100644 (file)
index 0000000..416ed2f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * fcntl.h
+ *
+ * Ullrich von Bassewitz, 30.05.1998
+ *
+ */
+
+
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+
+
+/* Flag values for the open() call */
+#define O_RDONLY        0x01
+#define O_WRONLY        0x02
+#define O_RDWR          0x03
+#define O_CREAT         0x10
+#define O_TRUNC         0x20
+#define O_APPEND        0x40
+
+
+
+/* Functions */
+int open (const char* name, int flags, ...);   /* May take a mode argument */
+int close (int fd);
+int write (int fd, const void* buf, unsigned count);
+int read (int fd, void* buf, unsigned count);
+int mkdir (const char* name, ...);             /* May take a mode argument */
+int rmdir (const char* name);
+
+
+
+/* End of fcntl.h */
+#endif
+
+
+
diff --git a/include/geos.h b/include/geos.h
new file mode 100644 (file)
index 0000000..671a4ae
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+   Supreme GEOS header file
+   includes all other headers
+
+   Maciej 'YTM/Alliance' Witkowiak, 27.10.1999
+*/
+
+
+
+#ifndef _GEOS_H
+#define _GEOS_H
+
+
+
+#ifndef _GCONST_H
+#include <geos/gconst.h>
+#endif
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+#ifndef _GSYM_H
+#include <geos/gsym.h>
+#endif
+
+#ifndef _GDISK_H
+#include <geos/gdisk.h>
+#endif
+
+#ifndef _GFILE_H
+#include <geos/gfile.h>
+#endif
+
+#ifndef _GPROCESS_H
+#include <geos/gprocess.h>
+#endif
+
+#ifndef _GGRAPH_H
+#include <geos/ggraph.h>
+#endif
+
+#ifndef _GMENU_H
+#include <geos/gmenu.h>
+#endif
+
+#ifndef _GSPRITE_H
+#include <geos/gsprite.h>
+#endif
+
+#ifndef _GMEMORY_H
+#include <geos/gmemory.h>
+#endif
+
+#ifndef _GSYS_H
+#include <geos/gsys.h>
+#endif
+
+#ifndef _GDLGBOX_H
+#include <geos/gdlgbox.h>
+#endif
+
+
+
+/* End of geos.h */
+#endif
+
+
+
diff --git a/include/geos/gconst.h b/include/geos/gconst.h
new file mode 100644 (file)
index 0000000..517ee37
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+  GEOS constants, 4-2-99, 18-3-99
+
+  small C version: 25-27.10.99
+  reassembled by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+/* Here are constants which didn't fit into any other cathegory... */
+
+#ifndef _GCONST_H
+#define _GCONST_H
+
+#define        NULL            0
+#define        FALSE           NULL
+#define        TRUE            0xff
+#define        MOUSE_SPRNUM    0
+#define        DISK_DRV_LGH    0x0d80
+
+/* drivetypes */
+#define        DRV_NULL        0
+#define        DRV_1541        1
+#define        DRV_1571        2
+#define        DRV_1581        3
+#define        DRV_NETWORK     15
+
+/* various disk constants */
+#define        REL_FILE_NUM    9
+#define        CMND_FILE_NUM   15
+#define        MAX_CMND_STR    32
+#define        DIR_1581_TRACK  40
+#define        DIR_ACC_CHAN    13
+#define        DIR_TRACK       18
+#define        N_TRACKS        35
+#define        DK_NM_ID_LEN    18
+#define        TRACK           9
+#define        SECTOR          12
+#define        TOTAL_BLOCKS    664
+
+/* offset to something */
+#define        OFF_INDEX_PTR   1
+
+/* values for MMU config - C128 */
+#define        CIOIN           0x7E
+#define        CRAM64K         0x7F
+#define        CKRNLBASIOIN    0x40
+#define        CKRNLIOIN       0x4E
+
+/* alarmSetFlag */
+#define        ALARMMASK       4
+
+#define        CLR_SAVE        0x40
+#define        CONSTRAINED     0x40
+#define        UN_CONSTRAINED  0
+#define        FG_SAVE         0x80
+
+#define        FUTURE1         7
+#define        FUTURE2         8
+#define        FUTURE3         9
+#define        FUTURE4         10
+#define        USELAST         127
+#define        SHORTCUT        128
+
+#endif
diff --git a/include/geos/gdisk.h b/include/geos/gdisk.h
new file mode 100644 (file)
index 0000000..9fac464
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  GEOS functions from disk driver
+
+  ported to small C on 21.12.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GDISK_H
+#define _GDISK_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+char __fastcall__ ReadBuff(struct tr_se *myTrSe);
+char __fastcall__ WriteBuff(struct tr_se *myTrSe);
+
+char __fastcall__ GetBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ PutBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ ReadBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ WriteBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ VerWriteBlock(struct tr_se *myTrSe, char *buffer);
+
+int __fastcall__ CalcBlksFree(void);
+char __fastcall__ ChkDkGEOS(void);
+char __fastcall__ SetGEOSDisk(void);
+char __fastcall__ NewDisk(void);
+char __fastcall__ OpenDisk(void);
+
+char __fastcall__ FindBAMBit(struct tr_se *myTrSe);
+char __fastcall__ BlkAlloc(struct tr_se output[], int length);
+char __fastcall__ NxtBlkAlloc(struct tr_se *startTrSe,
+                             struct tr_se output[], int length);
+char __fastcall__ FreeBlock(struct tr_se *myTrSe);
+struct tr_se __fastcall__ SetNextFree(struct tr_se *myTrSe);
+// above needs (int) casts on both sides of '='
+
+char __fastcall__ GetDirHead(void);
+char __fastcall__ PutDirHead(void);
+void __fastcall__ GetPtrCurDkNm(char *name);
+
+void __fastcall__ EnterTurbo(void);
+void __fastcall__ ExitTurbo(void);
+void __fastcall__ PurgeTurbo(void);
+
+char __fastcall__ ChangeDiskDevice(char newdev);
+
+/* disk header offsets */
+#define        OFF_TO_BAM      4
+#define        OFF_DISK_NAME   144
+#define        OFF_GS_DTYPE    189
+#define        OFF_OP_TR_SC    171
+#define        OFF_GS_ID       173
+/* disk errors */
+#define        ANY_FAULT       0xf0
+#define        NO_BLOCKS       1
+#define        INV_TRACK       2
+#define        INSUFF_SPACE    3
+#define        FULL_DIRECTORY  4
+#define        FILE_NOT_FOUND  5
+#define        BAD_BAM         6
+#define        UNOPENED_VLIR   7
+#define        INV_RECORD      8
+#define        OUT_OF_RECORDS  9
+#define        STRUCT_MISMAT   10
+#define        BFR_OVERFLOW    11
+#define        CANCEL_ERR      12
+#define        DEV_NOT_FOUND   13
+#define        INCOMPATIBLE    14
+#define        HDR_NOT_THERE   0x20
+#define        NO_SYNC         0x21
+#define        DBLK_NOT_THERE  0x22
+#define        DAT_CHKSUM_ERR  0x23
+#define        WR_VER_ERR      0x25
+#define        WR_PR_ON        0x26
+#define        HDR_CHKSUM_ERR  0x27
+#define        DSK_ID_MISMAT   0x29
+#define        BYTE_DEC_ERR    0x2e
+#define        DOS_MISMATCH    0x73
+
+#endif
diff --git a/include/geos/gdlgbox.h b/include/geos/gdlgbox.h
new file mode 100644 (file)
index 0000000..91744c7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+  GEOS dialog box functions
+
+  ported to small C on 26.12.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+  10.03.2000 - update
+*/
+
+#ifndef        _GDLGBOX_H
+#define _GDLGBOX_H
+
+char __fastcall__ DoDlgBox(char *dboxstring);
+char __fastcall__ RstrFrmDialogue(void);
+
+/* These are custom, predefined dialog boxes, I'm sure you'll find them usable
+   Most of them show 2 lines of text                                           */
+
+char __fastcall__ DlgBoxYesNo(char *line1, char *line2);
+char __fastcall__ DlgBoxOkCancel(char *line1, char *line2);
+void __fastcall__ DlgBoxOk(char *line1, char *line2);
+char __fastcall__ DlgBoxGetString(char *myString, char strLength,
+                                 char *line1, char *line2);
+char __fastcall__ DlgBoxFileSelect(char *classtxt, char ftype,
+                                  char *fname);
+
+/* Now the command string type */
+
+typedef void dlgBoxStr;
+
+/* and command string commands - macros */
+
+#define DB_DEFPOS(pattern) (char)(DEF_DB_POS | (pattern))
+#define DB_SETPOS(pattern,top,bot,left,right) \
+       (char)(SET_DB_POS | (pattern)), (char)(top), (char)(bot), \
+       (unsigned)(left), (unsigned)(right)
+#define DB_ICON(i,x,y)  (char)(i), (char)(x), (char)(y)
+#define DB_TXTSTR(x,y,text) (char)DBTXTSTR, (char)(x), (char)(y), (text)
+#define DB_VARSTR(x,y,ptr) (char)DBVARSTR, (char)(x), (char)(y), (char)(ptr)
+#define DB_GETSTR(x,y,ptr,length) (char)DBGETSTRING, (char)(x), (char)(y), (char)(ptr), (char)(length)
+#define DB_SYSOPV(ptr) (char)DBSYSOPV, (unsigned)(ptr)
+#define DB_GRPHSTR(ptr) (char)DBGRPHSTR, (unsigned)(ptr)
+#define DB_GETFILES(x,y) (char)DBGETFILES, (char)(x), (char)(y)
+#define DB_OPVEC(ptr) (char)DBOPVEC, (unsigned)(ptr)
+#define DB_USRICON(x,y,ptr) (char)DBUSRICON, (char)(x), (char)(y), (unsigned)(ptr)
+#define DB_USRROUT(ptr) (char)DB_USR_ROUT, (unsigned)(ptr)
+#define DB_END (char)NULL
+
+/*
+  part of constants below is used internally, but some are useful for macros above
+*/
+
+/* icons for DB_ICON */
+#define        OK              1
+#define        CANCEL          2
+#define        YES             3
+#define        NO              4
+#define        OPEN            5
+#define        DISK            6
+/* commands - internally used by command macros */
+#define        DBTXTSTR        11
+#define        DBVARSTR        12
+#define        DBGETSTRING     13
+#define        DBSYSOPV        14
+#define        DBGRPHSTR       15
+#define        DBGETFILES      16
+#define        DBOPVEC         17
+#define        DBUSRICON       18
+#define        DB_USR_ROUT     19
+/* icons tabulation in standard window */
+#define        DBI_X_0         1
+#define        DBI_X_1         9
+#define        DBI_X_2         17
+#define        DBI_Y_0         8
+#define        DBI_Y_1         40
+#define        DBI_Y_2         72
+/* standard window size defaults */
+#define        SET_DB_POS      0
+#define        DEF_DB_POS      0x80
+#define        DEF_DB_TOP      32
+#define        DEF_DB_BOT      127
+#define        DEF_DB_LEFT     64
+#define        DEF_DB_RIGHT    255
+/* text tabulation in standard window */
+#define        TXT_LN_1_Y      16
+#define        TXT_LN_2_Y      32
+#define        TXT_LN_3_Y      48
+#define        TXT_LN_4_Y      64
+#define        TXT_LN_5_Y      80
+#define        TXT_LN_X        16
+/* system icons size */
+#define        SYSDBI_HEIGHT   16
+#define        SYSDBI_WIDTH    6
+/* dialogbox string offsets */
+#define        OFF_DB_FORM     0
+#define        OFF_DB_TOP      1
+#define        OFF_DB_BOT      2
+#define        OFF_DB_LEFT     3
+#define        OFF_DB_RIGHT    5
+#define        OFF_DB_1STCMD   7
+
+#endif
+                 
diff --git a/include/geos/gfile.h b/include/geos/gfile.h
new file mode 100644 (file)
index 0000000..6e3174f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+  GEOS filesystem functions
+
+  ported to small C on 25.12.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GFILE_H
+#define _GFILE_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+struct filehandle *__fastcall__ Get1stDirEntry(void);
+struct filehandle *__fastcall__ GetNxtDirEntry(void);
+
+char __fastcall__ FindFTypes(char *buffer, char ftype, char fmaxnum, char *classtxt);
+
+char __fastcall__ FindFile(char *fname);
+char __fastcall__ ReadFile(struct tr_se *myTrSe, char *buffer, int flength);
+char __fastcall__ SaveFile(struct fileheader *myHeader);
+char __fastcall__ FreeFile(struct tr_se myTable[]);
+char __fastcall__ DeleteFile(char *fname);
+char __fastcall__ RenameFile(char *source, char *target);
+
+char __fastcall__ ReadByte(void);
+
+char __fastcall__ FollowChain(struct tr_se *startTrSe, char *buffer);
+char __fastcall__ GetFHdrInfo(struct filehandle *myFile);
+
+char __fastcall__ OpenRecordFile(char *fname);
+char __fastcall__ CloseRecordFile(void);
+char __fastcall__ NextRecord(void);
+char __fastcall__ PreviousRecord(void);
+char __fastcall__ PointRecord(char);
+char __fastcall__ DeleteRecord(void);
+char __fastcall__ InsertRecord(void);
+char __fastcall__ AppendRecord(void);
+char __fastcall__ ReadRecord(char *buffer, int flength);
+char __fastcall__ WriteRecord(char *buffer, int flength);
+char __fastcall__ UpdateRecordFile(void);
+
+/* GEOS filetypes */
+#define        NOT_GEOS        0
+#define        BASIC           1
+#define        ASSEMBLY        2
+#define        DATA            3
+#define        SYSTEM          4
+#define        DESK_ACC        5
+#define        APPLICATION     6
+#define        APPL_DATA       7
+#define        FONT            8
+#define        PRINTER         9
+#define        INPUT_DEVICE    10
+#define        DISK_DEVICE     11
+#define        SYSTEM_BOOT     12
+#define        TEMPORARY       13
+#define        AUTO_EXEC       14
+#define        INPUT_128       15
+#define        NUMFILETYPES    16
+/* supported structures */
+#define        SEQUENTIAL      0
+#define        VLIR            1
+/* DOS filetypes */
+#define        DEL             0
+#define        SEQ             1
+#define        PRG             2
+#define        USR             3
+#define        REL             4
+#define        CBM             5
+/* directory offsets */
+/* offsets in dir entry */
+#define        FRST_FILE_ENTRY 2
+#define        OFF_CFILE_TYPE  0
+#define        OFF_DE_TR_SC    1
+#define        OFF_FNAME       3
+#define        OFF_GHDR_PTR    19
+#define        OFF_GSTRUC_TYPE 21
+#define        OFF_GFILE_TYPE  22
+#define        OFF_YEAR        23
+#define        OFF_SIZE        28
+#define        OFF_NXT_FILE    32
+/* offsets in file header */
+#define        O_GHIC_WIDTH    2
+#define        O_GHIC_HEIGHT   3
+#define        O_GHIC_PIC      4
+#define        O_GHCMDR_TYPE   68
+#define        O_GHGEOS_TYPE   69
+#define        O_GHSTR_TYPE    70
+#define        O_GHST_ADDR     71
+#define        O_GHEND_ADDR    73
+#define        O_GHST_VEC      75
+#define        O_GHFNAME       77
+#define        O_128_FLAGS     96
+#define        O_GH_AUTHOR     97
+#define        O_GHP_DISK      97
+#define        O_GHP_FNAME     117
+#define        O_GHINFO_TXT    0xa0
+
+#endif
diff --git a/include/geos/ggraph.h b/include/geos/ggraph.h
new file mode 100644 (file)
index 0000000..51caad7
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+  GEOS graphic (non icon/menu/sprite) functions
+
+  ported to small C on 29.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+  10,11.03.2000 - updates
+*/
+
+#ifndef        _GGRAPH_H
+#define _GGRAPH_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ SetPattern(char newpattern);
+
+void __fastcall__ HorizontalLine(char pattern, char y, int xstart, int xend);
+void __fastcall__ InvertLine(char y, int xstart, int xend);
+void __fastcall__ RecoverLine(char y, int xstart, int xend);
+void __fastcall__ VerticalLine(char pattern, char ystart, char yend, int x);
+
+void __fastcall__ InitDrawWindow(struct window *myRectangle);
+void __fastcall__ Rectangle(void);
+void __fastcall__ FrameRectangle(char pattern);
+void __fastcall__ InvertRectangle(void);
+void __fastcall__ ImprintRectangle(void);
+void __fastcall__ RecoverRectangle(void);
+
+void __fastcall__ DrawLine(struct window *topBotCoords);
+
+void __fastcall__ DrawPoint(struct pixel *myPixel);
+char __fastcall__ TestPoint(struct pixel *myPixel);
+
+void __fastcall__ PutChar(char character, char y, int x);
+void __fastcall__ PutString(char *myString, char y, int x);
+void __fastcall__ PutDecimal(char style, int value, char y, int x);
+
+char __fastcall__ GetCharWidth(char character);
+void __fastcall__ LoadCharSet(struct fontdesc *myFont);
+void __fastcall__ UseSystemFont(void);
+
+void __fastcall__ BitmapUp(struct iconpic *myIcon);
+void __fastcall__ BitmapClip(char skipl, char skipr, int skiptop,
+                            struct iconpic *myIcon);
+void __fastcall__ BitOtherClip(void *proc1, void *proc2, char skipl,
+                              char skipr, int skiptop,
+                              struct iconpic *myIcon);
+
+void __fastcall__ GraphicsString(char *myGfxString);
+
+/* VIC colour constants */
+#define        BLACK           0
+#define        WHITE           1
+#define        RED             2
+#define        CYAN            3
+#define        PURPLE          4
+#define        GREEN           5
+#define        BLUE            6
+#define        YELLOW          7
+#define        ORANGE          8
+#define        BROWN           9
+#define        LTRED           10
+#define        DKGREY          11
+#define        GREY            12
+#define        MEDGREY         12
+#define        LTGREEN         13
+#define        LTBLUE          14
+#define        LTGREY          15
+/* VIC memory banks */
+#define        GRBANK0         3
+#define        GRBANK1         2
+#define        GRBANK2         1
+#define        GRBANK3         0
+/* VIC screen sizes */
+#define        VIC_X_POS_OFF   24
+#define        VIC_Y_POS_OFF   50
+#define        SC_BYTE_WIDTH   40
+#define        SC_PIX_HEIGHT   200
+#define        SC_PIX_WIDTH    320
+#define        SC_SIZE         8000
+/* VDC screen constants        */
+#define        SCREENBYTEWIDTH         80
+#define        SCREENPIXELWIDTH        640
+/* control characters for use as numbers, not chars */
+#define        EOF             0
+#define        BACKSPACE       8
+#define        FORWARDSPACE    9
+#define        TAB             9
+#define        LF              10
+#define        HOME            11
+#define        PAGE_BREAK      12
+#define        UPLINE          12
+#define        CR              13
+#define        ULINEON         14
+#define        ULINEOFF        15
+#define        ESC_GRAPHICS    16
+#define        ESC_RULER       17
+#define        REV_ON          18
+#define        REV_OFF         19
+#define        GOTOX           20
+#define        GOTOY           21
+#define        GOTOXY          22
+#define        NEWCARDSET      23
+#define        BOLDON          24
+#define        ITALICON        25
+#define        OUTLINEON       26
+#define        PLAINTEXT       27
+/* control characters for use in
+   strings: eg: str[10]=BOLD "Hello";  */
+#define CCR            "\015"
+#define CULINEON       "\016"
+#define CULINEOFF      "\017"
+#define CREV_ON                "\022"
+#define CREV_OFF       "\023"
+#define CBOLDON                "\030"
+#define CITALICON      "\031"
+#define COUTLINEON     "\032"
+#define CPLAINTEXT     "\033"
+
+/*values of currentMode        */
+/* bitNumbers */
+#define        UNDERLINE_BIT   7
+#define        BOLD_BIT        6
+#define        REVERSE_BIT     5
+#define        ITALIC_BIT      4
+#define        OUTLINE_BIT     3
+#define        SUPERSCRIPT_BIT 2
+#define        SUBSCRIPT_BIT   1
+/* bitMasks */
+#define        SET_UNDERLINE   0x80
+#define        SET_BOLD        0x40
+#define        SET_REVERSE     0x20
+#define        SET_ITALIC      0x10
+#define        SET_OUTLINE     0x08
+#define        SET_SUPERSCRIPT 0x04
+#define        SET_SUBSCRIPT   0x02
+#define        SET_PLAINTEXT   0
+/* values of dispBufferOn */
+#define        ST_WRGS_FORE    0x20
+#define        ST_WR_BACK      0x40
+#define        ST_WR_FORE      0x80
+/* PutDecimal parameters */
+/* leading 0s? */
+#define        SET_NOSURPRESS  0
+#define        SET_SURPRESS    0x40
+/* justification */
+#define        SET_RIGHTJUST   0
+#define        SET_LEFTJUST    0x80
+/* C128 x flags */
+#define        ADD1_W          0x2000
+#define        DOUBLE_B        0x80
+#define        DOUBLE_W        0x8000
+
+typedef void graphicStr;
+
+#define MOVEPENTO(x,y) (char)1, (unsigned)(x), (char)(y)
+#define LINETO(x,y) (char)2, (unsigned)(x), (char)(y)
+#define RECTANGLETO(x,y) (char)3, (unsigned)(x), (char)(y)
+#define NEWPATTERN(p) (char)5, (char)(p)
+#define FRAME_RECTO(x,y) (char)7, (unsigned)(x), (char)(y)
+#define PEN_X_DELTA(x) (char)8, (unsigned)(x)
+#define PEN_Y_DELTA(y) (char)9, (char)(y)
+#define PEN_XY_DELTA(x,y) (char)10, (unsigned)(x), (char)(y)
+#define GSTR_END (char)NULL
+/* ESC_PUTSTRING can't be implemented - it needs text, not pointer to it
+   #define ESC_PUTSTRING(x,y,text) (char)6, (unsigned)(x), (char)(y), (text), (char)NULL
+*/
+
+#endif
diff --git a/include/geos/gmemory.h b/include/geos/gmemory.h
new file mode 100644 (file)
index 0000000..fb60d6c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  GEOS memory and string functions
+
+  ported to small C on 27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GMEMORY_H
+#define _GMEMORY_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ CopyString(char *dest, char *source);
+void __fastcall__ CmpString(char *dest, char *source);
+void __fastcall__ CopyFString(char len, char *dest, char *source);
+void __fastcall__ CmpFString(char len, char *dest, char *source);
+
+int __fastcall__ CRC(char *buffer, int len);
+void __fastcall__ ClearRam(char *dest, int len);
+void __fastcall__ FillRam(char what, char *dest, int len);
+
+void __fastcall__ MoveData(char *source, char *dest, int len);
+
+void __fastcall__ InitRam(char *myInitTab);
+
+void __fastcall__ StashRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+void __fastcall__ FetchRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+void __fastcall__ SwapRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+char __fastcall__ VerifyRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+
+#endif
diff --git a/include/geos/gmenu.h b/include/geos/gmenu.h
new file mode 100644 (file)
index 0000000..a53c13f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+  GEOS menu and icon functions
+
+  ported to small C on 27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GMENU_H
+#define _GMENU_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ DoMenu(struct menu *myMenu);
+void __fastcall__ ReDoMenu(void);
+void __fastcall__ RecoverMenu(void);
+void __fastcall__ RecoverAllMenus(void);
+void __fastcall__ DoPreviousMenu(void);
+void __fastcall__ GotoFirstMenu(void);
+
+void __fastcall__ DoIcons(struct icontab *myIconTab);
+
+/* DoMenu - menutypes */
+#define        MENU_ACTION     0x00
+#define        DYN_SUB_MENU    0x40
+#define        SUB_MENU        0x80
+#define        HORIZONTAL      0x00
+#define        VERTICAL        0x80
+/* menu string offsets */
+#define        OFF_MY_TOP      0
+#define        OFF_MY_BOT      1
+#define        OFF_MX_LEFT     2
+#define        OFF_MX_RIGHT    4
+#define        OFF_NUM_M_ITEMS 6
+#define        OFF_1ST_M_ITEM  7
+/* icon string offsets */
+#define        OFF_NM_ICNS     0
+#define        OFF_IC_XMOUSE   1
+#define        OFF_IC_YMOUSE   3
+#define        OFF_PIC_ICON    0
+#define        OFF_X_ICON_POS  2
+#define        OFF_Y_ICON_POS  3
+#define        OFF_WDTH_ICON   4
+#define        OFF_HEIGHT_ICON 5
+#define        OFF_SRV_RT_ICON 6
+#define        OFF_NX_ICON     8
+/* icons, menus status flags   */
+#define        ST_FLASH        0x80
+#define        ST_INVERT       0x40
+#define        ST_LD_AT_ADDR   0x01
+#define        ST_LD_DATA      0x80
+#define        ST_PR_DATA      0x40
+#define        ST_WR_PR        0x40
+
+#endif
diff --git a/include/geos/gprocess.h b/include/geos/gprocess.h
new file mode 100644 (file)
index 0000000..c1cc5d7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  GEOS processes (~multitasking) functions
+
+  ported to small C on 27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GPROCESS_H
+#define _GPROCESS_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ InitProcesses(char number, struct process *proctab);
+void __fastcall__ RestartProcess(char number);
+void __fastcall__ EnableProcess(char number);
+void __fastcall__ BlockProcess(char number);
+void __fastcall__ UnBlockProcess(char number);
+void __fastcall__ FreezeProcess(char number);
+void __fastcall__ UnFreezeProcess(char number);
+
+void __fastcall__ Sleep(int jiffies);
+
+/*  Process control variable
+    these probably should be removed from here, as they are
+    internal GEOS information which is updated by functions above
+*/
+
+/* bit numbers */
+#define        RUNABLE_BIT     7
+#define        BLOCKED_BIT     6
+#define        FROZEN_BIT      5
+#define        NOTIMER_BIT     4
+/* bit masks */
+#define        SET_RUNABLE     0x80
+#define        SET_BLOCKED     0x40
+#define        SET_FROZEN      0x20
+#define        SET_NOTIMER     0x10
+
+#endif
diff --git a/include/geos/gsprite.h b/include/geos/gsprite.h
new file mode 100644 (file)
index 0000000..6f7fc28
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+  GEOS mouse and sprite functions
+
+  ported to small C on 27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GSPRITE_H
+#define _GSPRITE_H
+
+void __fastcall__ StartMouseMode(void);
+void __fastcall__ ClearMouseMode(void);
+void __fastcall__ MouseUp(void);
+void __fastcall__ MouseOff(void);
+char __fastcall__ IsMseInRegion(struct window *region);
+
+void __fastcall__ DrawSprite(char spritenum, char *spritepic);
+void __fastcall__ PosSprite(char spritenum, struct pixel *position);
+void __fastcall__ EnablSprite(char spritenum);
+void __fastcall__ DisablSprite(char spritenum);
+
+void __fastcall__ InitTextPrompt(char height);
+void __fastcall__ PromptOn(struct pixel *position);
+void __fastcall__ PromptOff(void);
+char __fastcall__ GetNextChar(void);
+
+/* keyboard constants */
+#define        KEY_F1          1
+#define        KEY_F2          2
+#define        KEY_F3          3
+#define        KEY_F4          4
+#define        KEY_F5          5
+#define        KEY_F6          6
+#define        KEY_NOSCRL      7
+#define        KEY_ENTER       11
+#define        KEY_F7          14
+#define        KEY_F8          15
+#define        KEY_UP          16
+#define        KEY_DOWN        17
+#define        KEY_HOME        18
+#define        KEY_CLEAR       19
+#define        KEY_LARROW      20
+#define        KEY_UPARROR     21
+#define        KEY_STOP        22
+#define        KEY_RUN         23
+#define        KEY_BPS         24
+#define        KEY_HELP        25
+#define        KEY_ALT         26
+#define        KEY_ESC         27
+#define        KEY_INSERT      28
+#define        KEY_DELETE      29
+#define        KEY_RIGHT       30
+#define        KEY_INVALID     31
+#define        KEY_LEFT        BACKSPACE
+
+/* values of faultData - pointer position vs. mouseWindow */
+/* bit numbers */
+#define        OFFTOP_BIT      7
+#define        OFFBOTTOM_BIT   6
+#define        OFFLEFT_BIT     5
+#define        OFFRIGHT_BIT    4
+#define        OFFMENU_BIT     3
+/* bit masks */
+#define        SET_OFFTOP      0x80
+#define        SET_OFFBOTTOM   0x40
+#define        SET_OFFLEFT     0x20
+#define        SET_OFFRIGHT    0x10
+#define        SET_OFFMENU     0x08
+
+/* mouseOn */
+/* bit numbers */
+#define        MOUSEON_BIT     7
+#define        MENUON_BIT      6
+#define        ICONSON_BIT     5
+/* bit masks */
+#define        SET_MSE_ON      0x80
+#define        SET_MENUON      0x40
+#define        SET_ICONSON     0x20
+
+/* pressFlag */
+/* bit numbers */
+#define        KEYPRESS_BIT    7
+#define        INPUT_BIT       6
+#define        MOUSE_BIT       5
+/* bit masks */
+#define        SET_KEYPRESS    0x80
+#define        SET_INPUTCHG    0x40
+#define        SET_MOUSE       0x20
+                 
+#endif
diff --git a/include/geos/gstruct.h b/include/geos/gstruct.h
new file mode 100644 (file)
index 0000000..9c79d29
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+  GEOS structs
+
+  ported to small C on 25-27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GSTRUCT_H
+#define _GSTRUCT_H
+
+struct f_date {                        /* date in filedesctiptor */
+       char f_year;
+       char f_month;
+       char f_day;
+       char f_hour;
+       char f_minute;
+};
+
+struct s_date {                        /* system date & time */
+       char s_year;
+       char s_month;
+       char s_day;
+       char s_hour;
+       char s_minutes;
+       char s_seconds;
+};
+
+struct tr_se {                 /* track and sector */
+       char track;
+       char sector;
+};
+
+struct fileheader {            /* header block (like fileHeader) */
+       struct tr_se n_block;
+       char icon_desc[3];
+       char icon_pic[63];
+       char dostype;
+       char type;
+       char structure;
+       int load_address;
+       int end_address;
+       int exec_address;
+       char class_name[19];
+       char column_flag;
+       char author[64];
+       char note[95];
+};
+
+struct filehandle {            /* filehandle in directory sectors */
+       char dostype;           /* or in dirEntryBuf               */
+       struct tr_se n_block;
+       char name[16];
+       struct tr_se header;
+       char structure;
+       char type;
+       struct f_date date;
+       int size;
+};
+
+struct pixel {                 /* describes point              */
+       int x;
+       char y;
+};
+
+struct fontdesc {              /* describes font               */
+       char baseline;
+       char width;
+       char height;
+       char *index_tbl;
+       char *data_ptr;
+};
+
+struct window {                        /* describes screen region      */
+       char top;
+       char bot;
+       int left;
+       int right;
+};
+
+struct VLIR_info {             /* VLIR information             */
+       char curRecord;         /* currently only used in VLIR  */
+       char usedRecords;       /* as system info (curRecord is mainly of your interest */
+       char fileWritten;
+       int fileSize;
+};
+
+struct process {               /* process info, declare table of that type */
+       int pointer;            /* (like: struct process proctab[2]=...    */
+       int jiffies;            /* last entry HAVE TO BE {0,0}              */
+};
+
+
+struct iconpic {               /* icon/encoded bitmap description          */
+       char *pic_ptr;          /* ptr to a photo scrap (or encoded bitmap) */
+       char x;                 /* position in cards (*8 pixels)            */
+       char y;
+       char width;             /* in cards                                 */
+       char heigth;            /* in lines (pixels)                        */
+};
+
+struct icondef {               /* icon definition for DoIcons              */
+       char *pic_ptr;          /* ptr to a photo scrap (or encoded bitmap) */
+       char x;                 /* position in cards (*8 pixels)            */
+       char y;
+       char width;             /* of icon (in cards)                       */
+       char heigth;            /* of icon in lines (pixels)                */
+       int proc_ptr;           /* pointer to function handling that icon   */
+};
+
+struct icontab {
+       char number;            /* number of declared icons                 */
+       struct pixel mousepos;  /* position of mouse after DoIcons          */
+       struct icondef tab[];   /* table of size declared by icontab.number */
+};
+
+/* everything below is obsolete and kept for unknown reasons */
+
+struct menuitem {
+       char *name;
+       char type;
+       int rest;               /* may be ptr to function, or if submenu ptr to struct menu */
+};
+
+struct menu {
+       struct window size;
+       char number;
+       struct menuitem items[];
+};
+
+struct inittab {               /* use struct inittab mytab[n] for initram              */
+       int ptr;                /* ptr to 1st byte                                      */
+       char number;            /* number of following bytes                            */
+       char values[];          /* warning - in table size of this is same for all!     */
+};
+
+#endif
diff --git a/include/geos/gsym.h b/include/geos/gsym.h
new file mode 100644 (file)
index 0000000..6dc7c51
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+  GEOS constants reassembled 4-2-99
+  ported to small C 26.8.99, 25-26.10.99
+  Maciej 'YTM/Alliance' Witkowiak
+  ytm@friko.onet.pl
+*/
+
+#ifndef _GSYM_H
+#define _GSYM_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+#define nameBuf                char[17]
+#define blockBuf       char[256]
+
+#define        zpage           *(char*)0x0000
+
+#define        CPU_DDR         *(char*)0x00
+#define        CPU_DATA        *(char*)0x01
+
+#define        r0              *(unsigned int*)0x02
+#define        r0L             *(char*)0x02
+#define        r0H             *(char*)0x03
+#define        r1              *(unsigned int*)0x04
+#define        r1L             *(char*)0x04
+#define        r1H             *(char*)0x05
+#define drawWindow     (*(struct window*)0x06)
+#define        r2              *(unsigned int*)0x06
+#define        r2L             *(char*)0x06
+#define        r2H             *(char*)0x07
+#define        r3              *(unsigned int*)0x08
+#define        r3L             *(char*)0x08
+#define        r3H             *(char*)0x09
+#define        r4              *(unsigned int*)0x0a
+#define        r4L             *(char*)0x0a
+#define        r4H             *(char*)0x0b
+#define        r5              *(unsigned int*)0x0c
+#define        r5L             *(char*)0x0c
+#define        r5H             *(char*)0x0d
+#define        r6              *(unsigned int*)0x0e
+#define        r6L             *(char*)0x0e
+#define        r6H             *(char*)0x0f
+#define        r7              *(unsigned int*)0x10
+#define        r7L             *(char*)0x10
+#define        r7H             *(char*)0x11
+#define        r8              *(unsigned int*)0x12
+#define        r8L             *(char*)0x12
+#define        r8H             *(char*)0x13
+#define        r9              *(unsigned int*)0x14
+#define        r9L             *(char*)0x14
+#define        r9H             *(char*)0x15
+#define        r10             *(unsigned int*)0x16
+#define        r10L            *(char*)0x16
+#define        r10H            *(char*)0x17
+#define        r11             *(unsigned int*)0x18
+#define        r11L            *(char*)0x18
+#define        r11H            *(char*)0x19
+#define        r12             *(unsigned int*)0x1a
+#define        r12L            *(char*)0x1a
+#define        r12H            *(char*)0x1b
+#define        r13             *(unsigned int*)0x1c
+#define        r13L            *(char*)0x1c
+#define        r13H            *(char*)0x1d
+#define        r14             *(unsigned int*)0x1e
+#define        r14L            *(char*)0x1e
+#define        r14H            *(char*)0x1f
+#define        r15             *(unsigned int*)0x20
+#define        r15L            *(char*)0x20
+#define        r15H            *(char*)0x21
+/* WARNING - these are used by C as temporary registers! */
+#define        a0              *(unsigned int*)0xfb
+#define        a0L             *(char*)0xfb
+#define        a0H             *(char*)0xfc
+#define        a1              *(unsigned int*)0xfd
+#define        a1L             *(char*)0xfd
+#define        a1H             *(char*)0xfe
+#define        a2              *(unsigned int*)0x70
+#define        a2L             *(char*)0x70
+#define        a2H             *(char*)0x71
+#define        a3              *(unsigned int*)0x72
+#define        a3L             *(char*)0x72
+#define        a3H             *(char*)0x73
+#define        a4              *(unsigned int*)0x74
+#define        a4L             *(char*)0x74
+#define        a4H             *(char*)0x75
+#define        a5              *(unsigned int*)0x76
+#define        a5L             *(char*)0x76
+#define        a5H             *(char*)0x77
+#define        a6              *(unsigned int*)0x78
+#define        a6L             *(char*)0x78
+#define        a6H             *(char*)0x79
+#define        a7              *(unsigned int*)0x7a
+#define        a7L             *(char*)0x7a
+#define        a7H             *(char*)0x7b
+#define        a8              *(unsigned int*)0x7c
+#define        a8L             *(char*)0x7c
+#define        a8H             *(char*)0x7d
+#define        a9              *(unsigned int*)0x7e
+#define        a9L             *(char*)0x7e
+#define        a9H             *(char*)0x7f
+
+#define        curPattern      *(unsigned int*)0x22
+#define        string          *(unsigned int*)0x24
+#define curFontDesc    (*(struct fontdesc*)0x26)
+#define        currentMode     *(char*)0x2e
+#define        dispBufferOn    *(char*)0x2f
+#define        mouseOn         *(char*)0x30
+#define        RAM_64K         *(char*)0x30
+#define        msePicPtr       *(unsigned int*)0x31
+#define curWindow      (*(struct window*)0x33)
+/*#define      IO_IN           *(char*)0x35
+  #define      KRNL_IO_IN      *(char*)0x36
+  #define      KRNL_BAS_IO_IN  *(char*)0x37*/
+#define        pressFlag       *(char*)0x39
+#define mousePos       (*(struct pixel*)0x3a)
+#define        returnAddress   *(unsigned int*)0x3d
+#define        graphMode       *(char*)0x3f
+/*#define      TURBO_DD00      *(char*)0x8e
+  #define      TURBO_DD00_CPY  *(char*)0x8f*/
+#define        STATUS          *(char*)0x90
+#define        curDevice       *(char*)0xba
+
+/* Here's my own errno location, I hope this won't confilct with anything... */
+#define errno          *(char*)0x91
+
+#define        irqvec          *(unsigned int*)0x0314
+#define        bkvec           *(unsigned int*)0x0316
+#define        nmivec          *(unsigned int*)0x0318
+
+#define        APP_RAM         *(char*)0x0400
+#define        BACK_SCR_BASE   *(char*)0x6000
+#define        PRINTBASE       *(char*)0x7900
+#define        OS_VARS         *(char*)0x8000
+
+#define        diskBlkBuf      ((blockBuf)0x8000)
+#define fileHeader     (*(struct fileheader*)0x8100)
+#define curDirHead     ((blockBuf)0x8200)
+#define fileTrScTab    ((struct tr_se[128])0x8300)
+#define dirEntryBuf    (*(struct filehandle*)0x8400)
+
+#define DrACurDkNm     ((nameBuf)0x841e)
+#define DrBCurDkNm     ((nameBuf)0x8430)
+#define dataFileName   ((nameBuf)0x8442)
+#define dataDiskName   ((nameBuf)0x8453)
+#define PrntFileName   ((nameBuf)0x8465)
+#define PrntDiskName   ((nameBuf)0x8476)
+
+#define        curDrive        *(char*)0x8489
+#define        diskOpenFlg     *(char*)0x848a
+#define        isGEOS          *(char*)0x848b
+#define        interleave      *(char*)0x848c
+#define        NUMDRV          *(char*)0x848d
+
+#define driveType      ((char[4])0x848e)
+#define turboFlags     ((char[4])0x8492)
+
+#define        VLIRInfo        (*(struct VLIR_info*)0x8496)
+
+#define        appMain         *(unsigned int*)0x849b
+#define        intTopVector    *(unsigned int*)0x849d
+#define        intBotVector    *(unsigned int*)0x849f
+#define        mouseVector     *(unsigned int*)0x84a1
+#define        keyVector       *(unsigned int*)0x84a3
+#define        inputVector     *(unsigned int*)0x84a5
+#define        mouseFaultVec   *(unsigned int*)0x84a7
+#define        otherPressVec   *(unsigned int*)0x84a9
+#define        StringFaultVec  *(unsigned int*)0x84ab
+#define        alarmTmtVector  *(unsigned int*)0x84ad
+#define        BRKVector       *(unsigned int*)0x84af
+#define        RecoverVector   *(unsigned int*)0x84b1
+#define        selectionFlash  *(char*)0x84b3
+#define        alphaFlag       *(char*)0x84b4
+#define        iconSelFlg      *(char*)0x84b5
+#define        faultData       *(char*)0x84b6
+#define        menuNumber      *(char*)0x84b7
+#define mouseWindow    (*(struct window*)0x84b8)
+#define stringXY       (*(struct pixel*)0x84be)
+#define        mousePicData    *(char*)0x84c1
+
+#define        maxMouseSpeed   *(char*)0x8501
+#define        minMouseSpeed   *(char*)0x8502
+#define        mouseAccel      *(char*)0x8503
+#define        keyData         *(char*)0x8504
+#define        mouseData       *(char*)0x8505
+#define        inputData       *(char*)0x8506
+#define        mouseSpeed      *(char*)0x8507
+#define        random          *(char*)0x850a
+#define        saveFontTab     (*(struct fontdesc*)0x850c)
+
+#define        dblClickCount   *(char*)0x8515
+#define system_date    (*(struct s_date*)0x8516)
+#define        alarmSetFlag    *(char*)0x851c
+#define        sysDBData       *(char*)0x851d
+#define        screencolors    *(char*)0x851e
+#define        dlgBoxRamBuf    *(char*)0x851f
+
+#define        savedmoby2      *(char*)0x88bb
+#define        scr80polar      *(char*)0x88bc
+#define        scr80colors     *(char*)0x88bd
+#define        vdcClrMode      *(char*)0x88be
+#define        driveData       ((char[4])0x88bf)
+#define        ramExpSize      *(char*)0x88c3
+#define        sysRAMFlg       *(char*)0x88c4
+#define        firstBoot       *(char*)0x88c5
+#define        curType         *(char*)0x88c6
+#define        ramBase         *(char*)0x88c7
+/*Original:
+  #define      inputDevName    *(char*)0x88cb
+  #define      memBase         *(char*)0x88cf*/
+#define inputDevName   ((nameBuf)0x88cb)
+#define        DrCCurDkNm      ((nameBuf)0x88dc)
+#define        DrDCurDkNm      ((nameBuf)0x88ee)
+#define        dir2Head        ((blockBuf)0x8900)
+#define        SPRITE_PICS     *(char*)0x8a00
+#define sprpic         ((char[8][64])0x8a00)
+#define COLOR_MATRIX   ((char[1000])0x8c00)
+#define objPointer     ((char[8])0x8ff8)
+
+#define        DISK_BASE       *(char*)0x9000
+#define        SCREEN_BASE     *(char*)0xa000
+#define        OS_ROM          *(char*)0xc000
+#define        OS_JUMPTAB      *(char*)0xc100
+#define        RAMC_BASE       *(char*)0xde00
+#define        RAMC_WINDOW     *(char*)0xdf00
+#define        EXP_BASE        *(char*)0xdf00
+#define        MOUSE_BASE_128  *(char*)0xfd00
+#define        MOUSE_JMP_128   *(char*)0xfd00
+#define        END_MOUSE_128   *(char*)0xfe80
+#define        MOUSE_BASE      *(char*)0xfe80
+#define        MOUSE_JMP       *(char*)0xfe80
+
+#define        config          *(char*)0xff00
+#define        END_MOUSE       *(char*)0xfffa
+#define        NMI_VECTOR      *(unsigned int*)0xfffa
+#define        RESET_VECTOR    *(unsigned int*)0xfffc
+#define        IRQ_VECTOR      *(unsigned int*)0xfffe
+
+#define        vicbase         *(char*)0xd000
+#define        sidbase         *(char*)0xd400
+#define        mmu             *(char*)0xd500
+#define        VDC             *(char*)0xd600
+#define        ctab            *(char*)0xd800
+#define        cia1base        *(char*)0xdc00
+#define        cia2base        *(char*)0xdd00
+
+#define        mob0xpos        *(char*)0xd000
+#define        mob0ypos        *(char*)0xd001
+#define        mob1xpos        *(char*)0xd002
+#define        mob1ypos        *(char*)0xd003
+#define        mob2xpos        *(char*)0xd004
+#define        mob2ypos        *(char*)0xd005
+#define        mob3xpos        *(char*)0xd006
+#define        mob3ypos        *(char*)0xd007
+#define        mob4xpos        *(char*)0xd008
+#define        mob4ypos        *(char*)0xd009
+#define        mob5xpos        *(char*)0xd00a
+#define        mob5ypos        *(char*)0xd00b
+#define        mob6xpos        *(char*)0xd00c
+#define        mob6ypos        *(char*)0xd00d
+#define        mob7xpos        *(char*)0xd00e
+#define        mob7ypos        *(char*)0xd00f
+#define        msbxpos         *(char*)0xd010
+#define        grcntrl1        *(char*)0xd011
+#define        rasreg          *(char*)0xd012
+#define        lpxpos          *(char*)0xd013
+#define        lpypos          *(char*)0xd014
+#define        mobenble        *(char*)0xd015
+#define        grcntrl2        *(char*)0xd016
+#define        grmemptr        *(char*)0xd018
+#define        grirq           *(char*)0xd019
+#define        grirqen         *(char*)0xd01a
+#define        moby2           *(char*)0xd017
+#define        mobprior        *(char*)0xd01b
+#define        mobmcm          *(char*)0xd01c
+#define        mobx2           *(char*)0xd01d
+#define        mobmobcol       *(char*)0xd01e
+#define        mobbakcol       *(char*)0xd01f
+#define        extclr          *(char*)0xd020
+#define        bakclr0         *(char*)0xd021
+#define        bakclr1         *(char*)0xd022
+#define        bakclr2         *(char*)0xd023
+#define        bakclr3         *(char*)0xd024
+#define        mcmclr0         *(char*)0xd025
+#define        mcmclr1         *(char*)0xd026
+#define        mob0clr         *(char*)0xd027
+#define        mob1clr         *(char*)0xd028
+#define        mob2clr         *(char*)0xd029
+#define        mob3clr         *(char*)0xd02a
+#define        mob4clr         *(char*)0xd02b
+#define        mob5clr         *(char*)0xd02c
+#define        mob6clr         *(char*)0xd02d
+#define        mob7clr         *(char*)0xd02e
+#define        keyreg          *(char*)0xd02f
+#define        clkreg          *(char*)0xd030
+
+#define        vdcreg          *(char*)0xd600
+#define        vdcdata         *(char*)0xd601
+
+#endif
+              
diff --git a/include/geos/gsys.h b/include/geos/gsys.h
new file mode 100644 (file)
index 0000000..028bf9c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+  GEOS system functions
+
+  ported to small C on 27.10.1999
+  by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef        _GSYS_H
+#define _GSYS_H
+
+void __fastcall__ FirstInit(void);
+void __fastcall__ InitForIO(void);
+void __fastcall__ DoneWithIO(void);
+void __fastcall__ MainLoop(void);
+void __fastcall__ EnterDeskTop(void);
+void __fastcall__ ToBASIC(void);
+void __fastcall__ Panic(void);
+
+void __fastcall__ CallRoutine(void *myRoutine);
+
+int __fastcall__ GetSerialNumber(void);
+char __fastcall__ GetRandom(void);
+
+void __fastcall__ SetDevice(char newdev);
+
+#endif
diff --git a/include/iso646.h b/include/iso646.h
new file mode 100644 (file)
index 0000000..a3737b9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * iso646.h
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ *
+ */
+
+
+
+#ifndef _ISO646_H
+#define _ISO646_H
+
+
+
+/* Operator tokens */
+#define        and     &&
+#define and_eq &=
+#define bitand &
+#define bitor  |
+#define compl  ~
+#define not    !
+#define not_eq !=
+#define or     ||
+#define or_eq  |=
+#define xor    ^
+#define xor_eq ^=
+
+
+
+/* End of iso646.h */
+#endif
+
+
+
diff --git a/include/joystick.h b/include/joystick.h
new file mode 100644 (file)
index 0000000..44dab00
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * joystick.h
+ *
+ * Ullrich von Bassewitz, 24.09.1998
+ *
+ * Read the joystick on systems that support it.
+ *
+ */
+
+
+
+#ifndef _JOYSTICK_H
+#define _JOYSTICK_H
+
+
+
+/* Define __JOYSTICK__ for systems that support a joystick */
+#ifdef __C64__
+#  define __JOYSTICK__
+#endif
+#ifdef __C128__
+#  define __JOYSTICK__
+#endif
+#ifdef __PLUS4__
+#  define __JOYSTICK__
+#endif
+#ifdef __NES__
+#  define __JOYSTICK__
+#endif
+
+/* Argument for the function */
+#define JOY_1          0
+#define JOY_2          1
+
+/* Result codes of the function. The actual code is a bitwise or
+ * of one or more of the following values.
+ */
+#ifdef __NES__
+#  define JOY_A                0x01
+#  define JOY_B                0x02
+#  define JOY_SELECT   0x04
+#  define JOY_START    0x08
+#  define JOY_UP       0x10
+#  define JOY_DOWN     0x20
+#  define JOY_LEFT     0x40
+#  define JOY_RIGHT    0x80
+#else
+#  define JOY_UP               0x01
+#  define JOY_DOWN     0x02
+#  define JOY_LEFT     0x04
+#  define JOY_RIGHT    0x08
+#  define JOY_FIRE     0x10
+#endif
+
+
+
+unsigned __fastcall__ readjoy (unsigned char joy);
+/* Read the joystick. The argument is one of JOY_1/JOY2 */
+
+
+
+/* End of joystick.h */
+#endif
+
+
+
diff --git a/include/limits.h b/include/limits.h
new file mode 100644 (file)
index 0000000..6b28da4
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * limits.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ *
+ */
+
+
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+
+
+#define CHAR_BIT       8
+
+#define SCHAR_MIN      (-128)
+#define SCHAR_MAX      127
+
+#define UCHAR_MAX      255
+
+#define CHAR_MIN       0
+#define CHAR_MAX       255
+
+#define SHRT_MIN       (-32768)
+#define SHRT_MAX       32767 
+
+#define USHRT_MAX      65535U
+
+#define INT_MIN                (-32768)
+#define INT_MAX                32767
+
+#define UINT_MAX       65535U
+
+#define LONG_MAX       2147483647L
+#define LONG_MIN       (-2147483648L)
+
+#define ULONG_MAX      4294967295UL
+
+
+
+/* End of limits.h */
+#endif
+
+
+
diff --git a/include/locale.h b/include/locale.h
new file mode 100644 (file)
index 0000000..c0732c1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * locale.h
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ *
+ */
+
+
+
+#ifndef _LOCALE_H
+#define _LOCALE_H
+
+
+
+/* NULL pointer */
+#ifdef NULL
+#  undef NULL
+#endif
+#define NULL   0
+
+/* Locale information constants */
+#define LC_ALL         0
+#define LC_COLLATE     1
+#define LC_CTYPE       2
+#define LC_MONETARY    3
+#define LC_NUMERIC     4
+#define LC_TIME                5
+
+/* Struct containing locale settings */
+struct lconv {
+    char*      currency_symbol;
+    char*      decimal_point;
+    char*      grouping;
+    char*      int_curr_symbol;
+    char*      mon_decimal_point;
+    char*      mon_grouping;
+    char*      mon_thousands_sep;
+    char*      negative_sign;
+    char*      positive_sign;
+    char*      thousands_sep;
+    char       frac_digits;
+    char       int_frac_digits;
+    char       n_cs_precedes;
+    char       n_sep_by_space;
+    char       n_sign_posn;
+    char       p_cs_precedes;
+    char       p_sep_by_space;
+    char       p_sign_posn;
+};
+
+/* Function prototypes */
+struct lconv* localeconv (void);
+char* setlocale (int category, const char* locale);
+
+
+
+/* End of locale.h */
+#endif
+
+
+
diff --git a/include/mouse.h b/include/mouse.h
new file mode 100644 (file)
index 0000000..6af499b
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * mouse.h
+ *
+ * Ullrich von Bassewitz, 24.04.1999
+ */
+
+
+
+#ifndef _MOUSE_H
+#define _MOUSE_H
+
+
+
+/* Define __MOUSE__ for systems that support a proportional mouse */
+#ifdef __C64__
+#  define __MOUSE__
+#endif
+#ifdef __C128__
+#  define __MOUSE__
+#endif
+
+
+
+void __fastcall__ mouse_init (unsigned char port, unsigned char sprite);
+/* Setup the mouse interrupt handler. If the sprite value is != zero, the
+ * mouse routines will manage the sprite with this number. That means, it
+ * is moved if the mouse is moved (provided that the mouse cursor is visible),
+ * and switch on and off in the show and hide functions.
+ * The port parameter gives the joystick port used for the mouse and is only
+ * needed to read the mouse button state.
+ * After calling this function, the mouse is invisble, the cursor is placed
+ * at 0/0 (upper left corner), and the bounding box is reset to cover the
+ * whole screen. Call mouse_show once to make the mouse cursor visible.
+ */
+
+void mouse_done (void);
+/* Disable the mouse, remove the interrupt handler. This function MUST be
+ * called before terminating the program, otherwise odd things may happen.
+ * If in doubt, install an exit handler (using atexit) that calls this
+ * function.
+ */
+
+void mouse_hide (void);
+/* Hide the mouse. This function doesn't do anything visible if no sprite is
+ * used. The function manages a counter and may be called more than once.
+ * For each call to mouse_hide there must be a call to mouse_show to make
+ * the mouse visible again.
+ */
+
+void mouse_show (void);
+/* Show the mouse. This function doesn't do anything visible if no sprite is
+ * used. See mouse_hide for more information.
+ */
+
+void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
+/* Set the bounding box for the mouse pointer movement. The mouse X and Y
+ * coordinates will never go outside the given box.
+ * NOTE: The function does *not* check if the mouse is currently inside the
+ * given margins. The proper way to use this function therefore is:
+ *
+ *     - Hide the mouse
+ *     - Set the bounding box
+ *     - Place the mouse at the desired position
+ *     - Show the mouse again.
+ *
+ * NOTE2: When setting the box to something that is larger than the actual
+ * screen, the positioning of the mouse cursor will fail. If such margins
+ * are really what you want, you have to use your own cursor routines.
+ */
+
+void __fastcall__ mouse_move (int x, int y);
+/* Set the mouse cursor to the given position. If a mouse cursor is defined
+ * and currently visible, the mouse cursor is also moved.
+ * NOTE: This function does not check if the given position is valid and
+ * inside the bounding box.
+ */
+
+void mouse_info (void);
+/* Hmmm...
+ */
+
+
+
+/* End of mouse.h */
+#endif
+
+
+
diff --git a/include/pet.h b/include/pet.h
new file mode 100644 (file)
index 0000000..22bc9b9
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * pet.h
+ *
+ * Ullrich von Bassewitz, 26.11.1998
+ */
+
+
+
+#ifndef _PET_H
+#define _PET_H
+
+
+
+/* Color defines */
+#define COLOR_BLACK            0x00
+#define COLOR_WHITE            0x01
+
+
+
+/* End of pet.h */
+#endif
+
+
+
diff --git a/include/plus4.h b/include/plus4.h
new file mode 100644 (file)
index 0000000..2a4dd1b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * plus4.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _PLUS4_H
+#define _PLUS4_H
+
+
+
+/* Additional key defines */
+#define CH_F1                  133
+#define CH_F2                  137
+#define CH_F3                  134
+#define CH_F4                  138
+#define CH_F5                  135
+#define CH_F6                  139
+#define CH_F7                  136
+#define CH_F8                  140
+
+
+
+/* Color attributes */
+#define CATTR_LUMA0            0x00
+#define CATTR_LUMA1            0x10
+#define CATTR_LUMA2            0x20
+#define CATTR_LUMA3            0x30
+#define CATTR_LUMA4            0x40
+#define CATTR_LUMA5            0x50
+#define CATTR_LUMA6            0x60
+#define CATTR_LUMA7            0x70
+#define CATTR_BLINK            0x80
+
+/* Base colors */
+#define BCOLOR_BLACK           0x00
+#define BCOLOR_WHITE           0x01
+#define BCOLOR_RED             0x02
+#define BCOLOR_CYAN                    0x03
+#define BCOLOR_VIOLET          0x04
+#define BCOLOR_GREEN           0x05
+#define BCOLOR_BLUE            0x06
+#define BCOLOR_YELLOW          0x07
+#define BCOLOR_ORANGE          0x08
+#define BCOLOR_BROWN           0x09
+#define BCOLOR_LEMON           0x0A    /* What's that color? */
+#define BCOLOR_LIGHTVIOLET     0x0B
+#define BCOLOR_BLUEGREEN       0x0C
+#define BCOLOR_LIGHTBLUE       0x0D
+#define BCOLOR_DARKBLUE                0x0E
+#define BCOLOR_LIGHTGREEN      0x0F
+
+
+
+/* Now try to mix up a C64/C128 compatible palette */
+#define COLOR_BLACK            (BCOLOR_BLACK)
+#define COLOR_WHITE            (BCOLOR_WHITE | CATTR_LUMA7)
+#define COLOR_RED              (BCOLOR_RED | CATTR_LUMA4)
+#define COLOR_CYAN             (BCOLOR_CYAN | CATTR_LUMA7)
+#define COLOR_VIOLET           (BCOLOR_VIOLET | CATTR_LUMA7)
+#define COLOR_GREEN            (BCOLOR_GREEN | CATTR_LUMA7)
+#define COLOR_BLUE             (BCOLOR_BLUE | CATTR_LUMA7)
+#define COLOR_YELLOW           (BCOLOR_YELLOW | CATTR_LUMA7)
+#define COLOR_ORANGE           (BCOLOR_ORANGE | CATTR_LUMA7)
+#define COLOR_BROWN            (BCOLOR_BROWN | CATTR_LUMA7)
+#define COLOR_LIGHTRED         (BCOLOR_RED | CATTR_LUMA7)
+#define COLOR_GRAY1            (BCOLOR_WHITE | CATTR_LUMA1)
+#define COLOR_GRAY2            (BCOLOR_WHITE | CATTR_LUMA3)
+#define COLOR_LIGHTGREEN       (BCOLOR_LIGHTGREEN | CATTR_LUMA7)
+#define COLOR_LIGHTBLUE        (BCOLOR_LIGHTBLUE | CATTR_LUMA7)
+#define COLOR_GRAY3            (BCOLOR_WHITE | CATTR_LUMA5)
+
+
+
+/* End of plus4.h */
+#endif
+
+
+
diff --git a/include/rs232.h b/include/rs232.h
new file mode 100644 (file)
index 0000000..a54b4d7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * rs232.h
+ *
+ * Ullrich von Bassewitz, 19.3.1999
+ *
+ * This module is based upon the public domain swiftlink module written by
+ * Craig Bruce. Thanks a lot!
+ *
+ */
+
+
+
+#ifndef _RS232_H
+#define _RS232_h
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Baudrate settings */
+#define RS_BAUD_50                             0x00
+#define RS_BAUD_110                            0x01
+#define RS_BAUD_134_5                          0x02
+#define RS_BAUD_300                            0x03
+#define RS_BAUD_600                            0x04
+#define RS_BAUD_1200                           0x05
+#define RS_BAUD_2400                           0x06
+#define RS_BAUD_4800                           0x07
+#define RS_BAUD_9600                           0x08
+#define RS_BAUD_19200                          0x09
+#define RS_BAUD_38400                          0x0A
+#define RS_BAUD_57600                          0x0B
+#define RS_BAUD_115200                         0x0C
+#define RS_BAUD_230400                         0x0D
+
+/* Stop bit settings */
+#define RS_STOP_1                              0x00
+#define RS_STOP_2                              0x80
+
+/* Data bit settings */
+#define RS_BITS_5                              0x60
+#define RS_BITS_6                              0x40
+#define RS_BITS_7                              0x20
+#define RS_BITS_8                              0x00
+
+/* Parity settings */
+#define RS_PAR_NONE                            0x00
+#define RS_PAR_ODD                             0x20
+#define RS_PAR_EVEN                            0x60
+#define RS_PAR_MARK                            0xA0
+#define RS_PAR_SPACE                           0xE0
+
+/* Bit masks to mask out things from the status returned by rs232_status */
+#define RS_STATUS_PE                           0x01    /* Parity error */
+#define RS_STATUS_FE                   0x02    /* Framing error */
+#define RS_STATUS_OVERRUN              0x04    /* Overrun error */
+#define RS_STATUS_RDRF                 0x08    /* Receiver data register full */
+#define RS_STATUS_THRE                 0x10    /* Transmit holding reg. empty */
+#define RS_STATUS_DCD                  0x20    /* NOT data carrier detect */
+#define RS_STATUS_DSR                  0x40    /* NOT data set ready */
+#define RS_STATUS_IRQ                          0x80    /* IRQ condition */
+
+/* Error codes returned by all functions */
+#define RS_ERR_OK                      0x00    /* Not an error - relax */
+#define RS_ERR_NOT_INITIALIZED                 0x01    /* Module not initialized */
+#define RS_ERR_BAUD_TOO_FAST           0x02    /* Cannot handle baud rate */
+#define RS_ERR_BAUD_NOT_AVAIL          0x03    /* Baud rate not available */
+#define RS_ERR_NO_DATA                 0x04    /* Nothing to read */
+#define RS_ERR_OVERFLOW                0x05    /* No room in send buffer */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned char __fastcall__ rs232_init (char hacked);
+/* Initialize the serial port, install the interrupt handler. The parameter
+ * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+ */
+
+unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+/* Set the port parameters. Use a combination of the #defined values above. */
+
+unsigned char __fastcall__ rs232_done (void);
+/* Close the port, deinstall the interrupt hander. You MUST call this function
+ * before terminating the program, otherwise the machine may crash later. If
+ * in doubt, install an exit handler using atexit(). The function will do
+ * nothing, if it was already called.
+ */
+
+unsigned char __fastcall__ rs232_get (char* b);
+/* Get a character from the serial port. If no characters are available, the
+ * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+ */
+
+unsigned char __fastcall__ rs232_put (char b);
+/* Send a character via the serial port. There is a transmit buffer, but
+ * transmitting is not done via interrupt. The function returns
+ * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+ */
+
+unsigned char __fastcall__ rs232_pause (void);
+/* Assert flow control and disable interrupts. */
+
+unsigned char __fastcall__ rs232_unpause (void);
+/* Re-enable interrupts and release flow control */
+
+unsigned char __fastcall__ rs232_status (unsigned char* status, 
+                                        unsigned char* errors);
+/* Return the serial port status. */
+
+
+
+/* End of rs232.h */
+#endif
+
+
+
diff --git a/include/setjmp.h b/include/setjmp.h
new file mode 100644 (file)
index 0000000..af7572e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * setjmp.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+
+
+typedef char jmp_buf [5];
+
+
+
+int __fastcall__ _setjmp (jmp_buf buf);
+#define setjmp _setjmp         /* ISO insists on a macro */
+void __fastcall__ longjmp (jmp_buf buf, int retval);
+
+
+
+/* End of stddef.h */
+#endif
+
+
+
diff --git a/include/stdarg.h b/include/stdarg.h
new file mode 100644 (file)
index 0000000..5910480
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * stdarg.h
+ *
+ * Ullrich von Bassewitz, 31.05.1998
+ *
+ */
+
+
+
+#ifndef _STDARG_H
+#define _STDARG_H
+
+
+
+typedef unsigned char* va_list;
+
+#define va_start(ap, fix)              ap = (va_list)&fix + *(((va_list)&fix)-1) - __fixargs__
+#define va_arg(ap,type)                ((type)*(ap -= ((sizeof (type) + 1) & ~1)))
+#define va_end(ap)
+
+/* This is only valid *before* the first call to va_arg. It will also work
+ * only for int sized parameters.
+ */
+#define va_fix(ap, offs)       *(ap+(__fixargs__-2*offs))
+
+
+
+/* End of stdarg.h */
+#endif
+
+
+
+
diff --git a/include/stddef.h b/include/stddef.h
new file mode 100644 (file)
index 0000000..6f7cbd4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * stddef.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+
+
+/* Standard data types */
+typedef int ptrdiff_t;
+typedef unsigned size_t;
+
+/* NULL pointer */
+#ifdef NULL
+#  undef NULL
+#endif
+#define NULL   0
+
+/* offsetof macro */
+#define offsetof(type, member) (size_t) (&((type*) 0)->member)
+
+
+
+/* End of stddef.h */
+#endif
+
+
+
diff --git a/include/stdio.h b/include/stdio.h
new file mode 100644 (file)
index 0000000..d85aaa4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * stdio.h
+ *
+ * Ullrich von Bassewitz, 30.05.1998
+ *
+ */
+
+
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+
+
+#ifndef _STDDEF_H
+#  include <stddef.h>
+#endif
+#ifndef _STDARG_H
+#  include <stdarg.h>
+#endif
+
+
+
+/* Types */
+typedef struct _FILE FILE;
+typedef unsigned long fpos_t;
+
+/* Standard file descriptors */
+extern FILE* stdin;
+extern FILE* stdout;
+extern FILE* stderr;
+
+/* Standard defines */
+#define _IOFBF         0
+#define _IOLBF         1
+#define _IONBF         2
+#define BUFSIZ         256
+#define EOF            -1
+#define FILENAME_MAX   16
+#define FOPEN_MAX      8
+#define L_tmpnam       (FILENAME_MAX + 1)
+#define SEEK_CUR       0
+#define SEEK_END       1
+#define SEEK_SET       2
+#define TMP_MAX                256
+
+
+
+/* Functions */
+void __fastcall__ clearerr (FILE* f);
+int fclose (FILE* f);
+int __fastcall__ feof (FILE* f);
+int __fastcall__ ferror (FILE* f);
+int __fastcall__ fflush (FILE* f);
+int fgetc (FILE* f);
+char* fgets (char* buf, size_t size, FILE* f);
+FILE* fopen (const char* name, const char* mode);
+int fprintf (FILE* f, const char* format, ...);
+int fputc (int c, FILE* f);
+int fputs (const char* s, FILE* f);
+size_t fread (void* buf, size_t size, size_t count, FILE* f);
+FILE* freopen (const char* name, const char* mode, FILE* f);
+size_t fwrite (const void* buf, size_t size, size_t count, FILE* f);
+int getchar (void);
+char* gets (char* s);
+void perror (const char* s);
+int printf (const char* format, ...);
+int putchar (int c);
+int puts (const char* s);
+int remove (const char* name);
+int rename (const char* old, const char* new);
+int sprintf (char* buf, const char* format, ...);
+int vfprintf (FILE* f, const char* format, va_list ap);
+int vprintf (const char* format, va_list ap);
+int vsprintf (char* buf, const char* format, va_list ap);
+
+#ifndef __STRICT_ANSI__
+FILE* fdopen (int fd, const char* mode);       /* Unix */
+int __fastcall__ fileno (FILE* f);             /* Unix */
+#endif
+
+
+/* Masking macros for some functions */
+#define getchar()      fgetc (stdin)           /* ANSI */
+#define putchar(c)     fputc (c, stdout)       /* ANSI */
+#define getc(f)                fgetc (f)               /* ANSI */
+#define putc(c, f)             fputc (c, f)            /* ANSI */
+
+/* Non-standard function like macros */
+#ifndef __STRICT_ANSI__
+#define flushall()                                     /* Unix */
+#define unlink(name)           remove (name)           /* Unix */
+#endif
+
+
+
+/* End of stdio.h */
+#endif
+
+
+
diff --git a/include/stdlib.h b/include/stdlib.h
new file mode 100644 (file)
index 0000000..7a191a3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * stdlib.h
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ *
+ */
+
+
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+
+
+#include <stddef.h>
+
+
+
+/* Standard exit codes */
+#define EXIT_SUCCESS   0
+#define EXIT_FAILURE   1
+
+
+
+/* Memory management */
+void* malloc (size_t size);
+void* calloc (size_t count, size_t size);
+void* realloc (void* block, size_t size);
+void free (void* block);
+#ifndef __STRICT_ANSI__
+void _hadd (void* mem, size_t size);           /* Non-standard */
+#endif
+
+/* Random numbers */
+#define        RAND_MAX        0x7FFF
+int rand (void);
+void __fastcall__ srand (unsigned seed);
+
+/* Other standard stuff */
+void abort (void);
+int __fastcall__ abs (int val);
+long __fastcall__ labs (long val);
+int __fastcall__ atoi (char* s);
+long __fastcall__ atol (char* s);
+int __fastcall__ atexit (void (*exitfunc) (void));
+void* bsearch (const void* key, const void* base, size_t n,
+              size_t size, int (*cmp) (const void*, const void*));
+void exit (int ret);
+char* __fastcall__ getenv (const char* name);
+void qsort (void* base, size_t count, size_t size,
+           int (*compare) (const void*, const void*));
+
+/* Non-ANSI functions */
+#ifndef __STRICT_ANSI__
+void __fastcall__ _swap (void* p, void* q, size_t size);
+char* __fastcall__ itoa (int val, char* buf, int radix);
+char* __fastcall__ utoa (unsigned val, char* buf, int radix);
+char* __fastcall__ ltoa (long val, char* buf, int radix);
+char* __fastcall__ ultoa (unsigned long val, char* buf, int radix);
+#endif
+
+
+
+/* End of stdlib.h */
+#endif
+
+
+
diff --git a/include/string.h b/include/string.h
new file mode 100644 (file)
index 0000000..4acb2f8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * string.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ *
+ */
+
+
+
+#ifndef _STRING_H
+#define _STRING_H
+
+
+
+#include <stddef.h>
+
+
+
+char* __fastcall__ strcat (char* dest, const char* src);
+char* __fastcall__ strchr (const char* s, int c);
+int __fastcall__ strcmp (const char* s1, const char* s2);
+int __fastcall__ strcoll (const char* s1, const char* s2);
+char* __fastcall__ strcpy (char* dest, const char* src);
+size_t __fastcall__ strcspn (const char* s1, const char* s2);
+char* __fastcall__ strerror (int errcode);
+size_t __fastcall__ strlen (const char* s);
+char* __fastcall__ strncat (char* s1, const char* s2, size_t count);
+int __fastcall__ strncmp (const char* s1, const char* s2, size_t count);
+char* __fastcall__ strncpy (char* dest, const char* src, size_t count);
+char* __fastcall__ strrchr (const char* s, int c);
+size_t __fastcall__ strspn (const char* s1, const char* s2);
+char* __fastcall__ strstr (const char* str, const char* substr);
+char* strtok (char* s1, const char* s2);
+size_t strxfrm (char* s1, const char* s2, size_t count);
+void* __fastcall__ memchr (const void* mem, int c, size_t count);
+int __fastcall__ memcmp (const void* p1, const void* p2, size_t count);
+void* __fastcall__ memcpy (void* dest, const void* src, size_t count);
+void* __fastcall__ memmove (void* dest, const void* src, size_t count);
+void* __fastcall__ memset (void* s, int c, size_t count);
+
+/* Non standard: */
+#ifndef __STRICT_ANSI__
+char* strdup (const char* s);                                /* SYSV/BSD */
+int __fastcall__ stricmp (const char* s1, const char* s2);    /* DOS/Windows */
+int __fastcall__ strcasecmp (const char* s1, const char* s2); /* Same for Unix */
+char* __fastcall__ strlwr (char* s);
+char* __fastcall__ strlower (char* s);
+char* __fastcall__ strupr (char* s);
+char* __fastcall__ strupper (char* s);
+#endif
+
+
+
+/* End of string.h */
+#endif
+
+
+
diff --git a/include/time.h b/include/time.h
new file mode 100644 (file)
index 0000000..195ce14
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * time.h
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ *
+ */
+
+
+
+#ifndef _TIME_H
+#define _TIME_H
+
+
+
+#include <stddef.h>
+
+
+
+typedef unsigned long time_t;
+typedef unsigned long clock_t;
+
+/* Structure for broken down time */
+struct tm {
+    int        tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+};
+
+/* The 610 gets its clock from the AC current */
+#ifdef __CBM__
+#  ifdef __CBM610__
+#    define CLK_TCK                    50      /* POSIX */
+#    define CLOCKS_PER_TICK    50      /* ANSI */
+#  else
+#    define CLK_TCK            60      /* POSIX */
+#    define CLOCKS_PER_TICK    60      /* ANSI */
+#  endif
+#endif
+
+
+
+/* Function prototypes */
+clock_t clock (void);
+
+
+
+/* End of time.h */
+
+#endif
+
+
+
diff --git a/libsrc/.cvsignore b/libsrc/.cvsignore
new file mode 100644 (file)
index 0000000..bf406ef
--- /dev/null
@@ -0,0 +1,2 @@
+libr65.tmp
+*.lib
diff --git a/libsrc/Makefile b/libsrc/Makefile
new file mode 100644 (file)
index 0000000..068bbb4
--- /dev/null
@@ -0,0 +1,120 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .obj .s .c
+
+# Defines used by the submakes:
+export CC = ../../src/cc65/cc65
+export AS = ../../src/ca65/ca65
+
+# Define used within this makefile
+AR = ../src/ar65/ar65
+
+#-----------------------------------------------------------------------------
+
+all :          apple2lib c64lib c128lib cbm610lib geoslib petlib plus4lib
+
+#-----------------------------------------------------------------------------
+# Apple ][
+
+apple2lib:
+       export CFLAGS="-Osir -g -t apple2 -I../../include";\
+       for i in apple2 common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv apple2/crt0.o apple2.o
+       for i in apple2 common runtime conio dbg; do \
+           $(AR) a apple2.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# Atari
+
+atarilib:
+       export CFLAGS="-Osir -g -t atari -I../../include";\
+       for i in atari common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv atari/crt0.o atari.o
+       for i in atari common runtime conio dbg; do \
+           $(AR) a atari.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# C64
+
+c64lib:
+       export CFLAGS="-Osir -g -t c64 -I../../include";\
+       for i in c64 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv c64/crt0.o c64.o
+       for i in c64 cbm common runtime conio dbg; do \
+           $(AR) a c64.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# C128
+
+c128lib:
+       export CFLAGS="-Osir -g -t c128 -I../../include";\
+       for i in c128 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv c128/crt0.o c128.o
+       for i in c128 cbm common runtime conio dbg; do \
+           $(AR) a c128.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# PET-II series
+
+cbm610lib:
+       export CFLAGS="-Osir -g -t cbm610 -I../../include";\
+       for i in cbm610 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv cbm610/crt0.o cbm610.o
+       for i in cbm610 cbm common runtime conio dbg; do \
+           $(AR) a cbm610.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# GEOS on the C64/128
+
+geoslib:
+       export CFLAGS="-Osir -g -t geos -I../../include";\
+               for i in geos common runtime; do $(MAKE) -C $$i; done
+       for i in common runtime; do \
+           $(AR) a geos.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# CBM PET machines
+
+petlib:
+       export CFLAGS="-Osir -g -t pet -I../../include";\
+       for i in pet cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv pet/crt0.o pet.o
+       for i in pet cbm common runtime conio dbg; do \
+           $(AR) a pet.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# Commodore C116, C16 and Plus/4
+
+plus4lib:
+       export CFLAGS="-Osir -g -t plus4 -I../../include";\
+       for i in plus4 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+       mv plus4/crt0.o plus4.o
+       for i in plus4 cbm common runtime conio dbg; do \
+           $(AR) a plus4.lib $$i/*.o;\
+       done
+
+#-----------------------------------------------------------------------------
+# Dummy targets
+
+.PHONY: clean
+clean:
+       @for i in apple2 atari c128 c64 cbm cbm610 common conio dbg geos pet plus4 runtime; do  \
+                  $(MAKE) -C $$i clean;                                                                        \
+       done
+
+.PHONY: zap
+zap:   clean
+       @rm -f *.lib
+
+
+
+
diff --git a/libsrc/apple2/Makefile b/libsrc/apple2/Makefile
new file mode 100644 (file)
index 0000000..57d6956
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = break.o clrscr.o cclear.o cgetc.o chline.o color.o \
+        cputc.o crt0.o ctype.o \
+        cvline.o kbhit.o read.o revers.o where.o write.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/apple2/apple2.inc b/libsrc/apple2/apple2.inc
new file mode 100644 (file)
index 0000000..d24eb8d
--- /dev/null
@@ -0,0 +1,43 @@
+; Break vector
+BRKVec  = $03F0
+
+; Goto Dos
+RESTOR =       $03D0
+
+; Top of available memory
+; This is actually for DOS 3.3 need to change it for ProDos
+TOPMEM  =       $9600
+
+; Soft switches
+;
+; write to USEROM to enable apple rom C000-CFFF
+USEROM =       $C007
+; 80 column card switches
+C80ON  =       $C00C
+C80OFF =       $C00D
+RD80COL        =       $C01F
+PG2OFF =       $C054
+PG2ON  =       $C055
+RDPAGE2        =       $C01C
+
+; Text routines
+MIN_X  =       $20
+MAX_X  =       $21
+MIN_Y  =       $22
+MAX_Y  =       $23
+CH     =       $24
+CV     =       $25
+BASL   =       $28
+TEXTTYP        =       $32
+HOME   =       $FC58
+VTABZ  =       $FC24
+COUT    =      $FDED
+
+; Keyboard entries
+RDKEY  =       $FD0C
+CLEAR_KEY_STROBE = $C010
+KEY_STROBE       = $C000
+
+; Game controller
+OPEN_APPLE = $C061
+CLOSED_APPLE = $C062
diff --git a/libsrc/apple2/break.s b/libsrc/apple2/break.s
new file mode 100644 (file)
index 0000000..e9e2e6d
--- /dev/null
@@ -0,0 +1,109 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+               .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+
+       .include        "apple2.inc"
+
+_brk_a = $45
+_brk_x = $46
+_brk_y = $47
+_brk_sr = $48
+_brk_sp = $49
+_brk_pc = $3A
+
+.bss
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     BRKVec
+       lda     #>brk_handler
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       sec
+       lda     _brk_pc
+       sbc     #$02            ; Point to start of brk
+       sta     _brk_pc
+       lda     _brk_pc+1
+       sbc     #$00
+       sta     _brk_pc+1
+
+       clc
+       lda     _brk_sp
+       adc     #$04            ; Adjust stack pointer
+       sta     _brk_sp
+
+       lda     _brk_sr         ; Clear brk
+       and     #$EF
+       sta     _brk_sr
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       
+       rti                     ; Jump back...
+
+.endproc
+       
diff --git a/libsrc/apple2/cclear.s b/libsrc/apple2/cclear.s
new file mode 100644 (file)
index 0000000..586459c
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+       .export         _cclearxy, _cclear
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_cclearxy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+               pla                     ; Restore the length and run into _cclear
+
+_cclear:
+               cmp     #0              ; Is the length zero?
+               beq     L9              ; Jump if done
+       sta     tmp1                                 
+L1:            lda     #$20            ; Blank - screen code
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/apple2/cgetc.s b/libsrc/apple2/cgetc.s
new file mode 100644 (file)
index 0000000..7d540ee
--- /dev/null
@@ -0,0 +1,25 @@
+       ;;
+       ;; Kevin Ruland
+       ;;
+       ;; char cgetc (void);
+       ;;
+       ;; If open_apple key is pressed then the high-bit of the
+       ;; key is set.
+       
+       .export _cgetc
+
+       .include "apple2.inc"
+
+_cgetc:
+       lda     KEY_STROBE
+       bpl     _cgetc          ; if < 128, no key pressed
+       ;; At this time, the high bit of the key pressed
+       ;; is set
+       sta     CLEAR_KEY_STROBE; clear keyboard strobe
+       bit     OPEN_APPLE      ; check if OpenApple is down
+       bmi     pressed 
+       and     #$7F            ; If not down, then clear high bit
+pressed:       
+       ldx     #0
+       rts
+       
\ No newline at end of file
diff --git a/libsrc/apple2/chline.s b/libsrc/apple2/chline.s
new file mode 100644 (file)
index 0000000..1347c3a
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+       .export         _chlinexy, _chline
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_chlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length
+
+_chline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+L1:            lda     #$2D            ; Horizontal line, screen code
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/apple2/clrscr.s b/libsrc/apple2/clrscr.s
new file mode 100644 (file)
index 0000000..c1a2993
--- /dev/null
@@ -0,0 +1,10 @@
+       ;;
+       ;; Kevin Ruland
+       ;;
+       ;; void clrscr (void);
+
+       .export         _clrscr
+
+       .include        "apple2.inc"
+
+_clrscr = HOME
\ No newline at end of file
diff --git a/libsrc/apple2/color.s b/libsrc/apple2/color.s
new file mode 100644 (file)
index 0000000..cfc8a47
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+       .export         _textcolor, _bgcolor, _bordercolor
+       .import         return0, _revers
+
+       .include        "apple2.inc"
+
+_textcolor     = _revers
+
+_bgcolor       = return0
+
+_bordercolor   = return0
+
+
diff --git a/libsrc/apple2/cputc.s b/libsrc/apple2/cputc.s
new file mode 100644 (file)
index 0000000..f8ea39d
--- /dev/null
@@ -0,0 +1,85 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc
+       .export         _gotoxy, cputdirect
+       .export         newline, putchar
+
+       .import         popa
+
+       .include        "apple2.inc"
+
+; Plot a character - also used as internal function
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy
+       pla                     ; Restore C
+
+_cputc:
+       cmp     #$0D            ; Test for \r = carrage return
+       bne     L1
+       lda     #$00            ; Goto left edge of screen
+       sta     CH
+       rts                     ; That's all we do
+L1:
+       cmp     #$0A            ; Test for \n = line feed
+       beq     newline
+
+cputdirect:
+       jsr     putchar
+       ;; Bump to next column
+       inc     CH
+       lda     CH
+       cmp     MAX_X
+       bne     return
+       lda     #$00
+       sta     CH
+return:        
+       rts
+
+putchar:       
+       ora     #$80            ; Turn on high bit
+       and     TEXTTYP         ; Apply normal, inverse, flash
+       ldy     CH
+       ldx     RD80COL         ; In 80 column mode?
+       bpl     col40           ; No, in 40 cols
+       pha
+       tya
+       lsr                     ; Div by 2
+       tay
+       pla
+       bcs     col40           ; odd cols go in 40 col memory
+       sta     PG2ON
+col40: sta     (BASL),Y
+       sta     PG2OFF
+       rts
+
+newline:
+       lda     CH
+       pha
+       inc     CV
+       lda     CV
+       cmp     MAX_Y
+       bne     L2
+       lda     #$00
+       sta     CV
+L2:
+       jsr     VTABZ
+       pla
+       sta     CH
+       rts
+               
+_gotoxy:
+       sta     CV              ; Store Y
+       jsr     VTABZ
+       jsr     popa            ; Get X
+       sta     CH              ; Store X
+       rts
+
+
diff --git a/libsrc/apple2/crt0.s b/libsrc/apple2/crt0.s
new file mode 100644 (file)
index 0000000..08eb57f
--- /dev/null
@@ -0,0 +1,112 @@
+;
+; Startup code for cc65 (Apple2 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+       .import         __hinit
+       .import         zerobss, push0, doatexit
+       .import         _main
+
+       .include         "apple2.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+
+; These zero page entries overlap with the sweet-16 registers.
+; must be changed if sweet-16 is to be supported
+sp             =       $00             ; stack pointer
+sreg   =       $02             ; secondary register/high 16 bit for longs
+regsave        =       $04             ; slot to save/restore (E)AX into
+ptr1   =       $08             ;
+ptr2   =       $0A
+ptr3   =       $0C
+ptr4   =       $0E
+tmp1   =       $10
+tmp2   =       $11
+tmp3   =       $12
+tmp4   =       $13
+regbank        =       $14             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y        ; Save the zero page locations we need
+       dey
+               bpl     L1
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Save system stuff and setup the stack
+
+               tsx
+               stx     spsave          ; Save the system stack ptr
+
+       lda     #<TOPMEM
+       sta     sp
+       lda     #>TOPMEM
+               sta     sp+1            ; Set argument stack ptr
+
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       lda     #$ff
+       sta     TEXTTYP
+
+; Set up to use Apple ROM $C000-$CFFF
+
+       ;;      sta     USEROM
+
+; Pass an empty command line
+
+       jsr     push0           ; argc
+       jsr     push0           ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit:
+       lda     #$ff
+       sta     TEXTTYP
+
+       jsr     doatexit        ; call exit functions
+
+       ldx     spsave
+       txs                     ; Restore stack pointer
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+               bpl     L2
+
+; Reset changed vectors, back to basic
+
+       jmp     RESTOR
+
+
+.data
+
+zpsave:        .res    zpspace
+
+.bss
+
+spsave:        .res    1
diff --git a/libsrc/apple2/ctype.s b/libsrc/apple2/ctype.s
new file mode 100644 (file)
index 0000000..c0233b2
--- /dev/null
@@ -0,0 +1,309 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to an upper case char to make it lower case
+; char (example: for ASCII, this must be $E0).
+
+
+       .export         __cdiff
+
+__cdiff:
+       .byte   $E0
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+;   * It is fast. If it were'nt for the slow parameter passing of cc65, one
+;     could even define macros for the isxxx functions (this is usually
+;     done on other platforms).
+;
+;   * It is highly portable. The only unportable part is the table itself,
+;     all real code goes into the common library.
+;
+;   * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+;   0 - Lower case char
+;   1 - Upper case char
+;   2 - Numeric digit
+;   3 - Hex digit (both, lower and upper)
+;   4 - Control character
+;   5 - The space character itself
+;   6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+;   7 - Space or tab character
+
+       .export         __ctype
+
+__ctype:
+               .byte   $10     ;   0/00 ___ctrl_@___
+               .byte   $10     ;   1/01 ___ctrl_A___
+               .byte   $10     ;   2/02 ___ctrl_B___
+               .byte   $10     ;   3/03 ___ctrl_C___
+               .byte   $10     ;   4/04 ___ctrl_D___
+               .byte   $10     ;   5/05 ___ctrl_E___
+               .byte   $10     ;   6/06 ___ctrl_F___
+               .byte   $10     ;   7/07 ___ctrl_G___
+               .byte   $10     ;   8/08 ___ctrl_H___
+               .byte   $D0     ;   9/09 ___ctrl_I___
+               .byte   $50     ;  10/0a ___ctrl_J___
+               .byte   $50     ;  11/0b ___ctrl_K___
+               .byte   $50     ;  12/0c ___ctrl_L___
+               .byte   $50     ;  13/0d ___ctrl_M___
+               .byte   $10     ;  14/0e ___ctrl_N___
+               .byte   $10     ;  15/0f ___ctrl_O___
+               .byte   $10     ;  16/10 ___ctrl_P___
+               .byte   $10     ;  17/11 ___ctrl_Q___
+               .byte   $10     ;  18/12 ___ctrl_R___
+               .byte   $10     ;  19/13 ___ctrl_S___
+               .byte   $10     ;  20/14 ___ctrl_T___
+               .byte   $10     ;  21/15 ___ctrl_U___
+               .byte   $10     ;  22/16 ___ctrl_V___
+               .byte   $10     ;  23/17 ___ctrl_W___
+               .byte   $10     ;  24/18 ___ctrl_X___
+               .byte   $10     ;  25/19 ___ctrl_Y___
+               .byte   $10     ;  26/1a ___ctrl_Z___
+               .byte   $10     ;  27/1b ___ctrl_[___
+               .byte   $10     ;  28/1c ___ctrl_\___
+               .byte   $10     ;  29/1d ___ctrl_]___
+               .byte   $10     ;  30/1e ___ctrl_^___
+               .byte   $10     ;  31/1f ___ctrl_____
+               .byte   $A0     ;  32/20 ___SPACE___
+       .byte   $00     ;  33/21 _____!_____
+       .byte   $00     ;  34/22 _____"_____
+       .byte   $00     ;  35/23 _____#_____
+       .byte   $00     ;  36/24 _____$_____
+       .byte   $00     ;  37/25 _____%_____
+       .byte   $00     ;  38/26 _____&_____
+       .byte   $00     ;  39/27 _____'_____
+       .byte   $00     ;  40/28 _____(_____
+       .byte   $00     ;  41/29 _____)_____
+       .byte   $00     ;  42/2a _____*_____
+       .byte   $00     ;  43/2b _____+_____
+       .byte   $00     ;  44/2c _____,_____
+       .byte   $00     ;  45/2d _____-_____
+       .byte   $00     ;  46/2e _____._____
+       .byte   $00     ;  47/2f _____/_____
+       .byte   $0C     ;  48/30 _____0_____
+       .byte   $0C     ;  49/31 _____1_____
+       .byte   $0C     ;  50/32 _____2_____
+       .byte   $0C     ;  51/33 _____3_____
+       .byte   $0C     ;  52/34 _____4_____
+       .byte   $0C     ;  53/35 _____5_____
+       .byte   $0C     ;  54/36 _____6_____
+       .byte   $0C     ;  55/37 _____7_____
+       .byte   $0C     ;  56/38 _____8_____
+       .byte   $0C     ;  57/39 _____9_____
+       .byte   $00     ;  58/3a _____:_____
+       .byte   $00     ;  59/3b _____;_____
+       .byte   $00     ;  60/3c _____<_____
+       .byte   $00     ;  61/3d _____=_____
+       .byte   $00     ;  62/3e _____>_____
+       .byte   $00     ;  63/3f _____?_____
+
+       .byte   $00     ;  64/40 _____@_____
+               .byte   $0A     ;  65/41 _____A_____
+               .byte   $0A     ;  66/42 _____B_____
+               .byte   $0A     ;  67/43 _____C_____
+               .byte   $0A     ;  68/44 _____D_____
+               .byte   $0A     ;  69/45 _____E_____
+               .byte   $0A     ;  70/46 _____F_____
+               .byte   $02     ;  71/47 _____G_____
+               .byte   $02     ;  72/48 _____H_____
+               .byte   $02     ;  73/49 _____I_____
+               .byte   $02     ;  74/4a _____J_____
+               .byte   $02     ;  75/4b _____K_____
+               .byte   $02     ;  76/4c _____L_____
+               .byte   $02     ;  77/4d _____M_____
+               .byte   $02     ;  78/4e _____N_____
+               .byte   $02     ;  79/4f _____O_____
+               .byte   $02     ;  80/50 _____P_____
+               .byte   $02     ;  81/51 _____Q_____
+               .byte   $02     ;  82/52 _____R_____
+               .byte   $02     ;  83/53 _____S_____
+               .byte   $02     ;  84/54 _____T_____
+               .byte   $02     ;  85/55 _____U_____
+               .byte   $02     ;  86/56 _____V_____
+               .byte   $02     ;  87/57 _____W_____
+               .byte   $02     ;  88/58 _____X_____
+               .byte   $02     ;  89/59 _____Y_____
+               .byte   $02     ;  90/5a _____Z_____
+       .byte   $00     ;  91/5b _____[_____
+       .byte   $00     ;  92/5c _____\_____
+       .byte   $00     ;  93/5d _____]_____
+       .byte   $00     ;  94/5e _____^_____
+       .byte   $00     ;  95/5f _UNDERLINE_
+       .byte   $00     ;  96/60 ___grave___
+               .byte   $09     ;  97/61 _____a_____
+               .byte   $09     ;  98/62 _____b_____
+               .byte   $09     ;  99/63 _____c_____
+               .byte   $09     ; 100/64 _____d_____
+               .byte   $09     ; 101/65 _____e_____
+               .byte   $09     ; 102/66 _____f_____
+               .byte   $01     ; 103/67 _____g_____
+               .byte   $01     ; 104/68 _____h_____
+               .byte   $01     ; 105/69 _____i_____
+               .byte   $01     ; 106/6a _____j_____
+               .byte   $01     ; 107/6b _____k_____
+               .byte   $01     ; 108/6c _____l_____
+               .byte   $01     ; 109/6d _____m_____
+               .byte   $01     ; 110/6e _____n_____
+               .byte   $01     ; 111/6f _____o_____
+               .byte   $01     ; 112/70 _____p_____
+               .byte   $01     ; 113/71 _____q_____
+               .byte   $01     ; 114/72 _____r_____
+               .byte   $01     ; 115/73 _____s_____
+               .byte   $01     ; 116/74 _____t_____
+               .byte   $01     ; 117/75 _____u_____
+               .byte   $01     ; 118/76 _____v_____
+               .byte   $01     ; 119/77 _____w_____
+               .byte   $01     ; 120/78 _____x_____
+               .byte   $01     ; 121/79 _____y_____
+               .byte   $01     ; 122/7a _____z_____
+               .byte   $00     ; 123/7b _____{_____
+               .byte   $00     ; 124/7c _____|_____
+               .byte   $00     ; 125/7d _____}_____
+               .byte   $00     ; 126/7e _____~_____
+               .byte   $40     ; 127/7f ____DEL____
+
+               .byte   $00     ; 128/80 ___________
+               .byte   $00     ; 129/81 ___________
+               .byte   $00     ; 130/82 ___________
+               .byte   $00     ; 131/83 ___________
+               .byte   $00     ; 132/84 ___________
+               .byte   $00     ; 133/85 ___________
+               .byte   $00     ; 134/86 ___________
+               .byte   $00     ; 135/87 ___________
+               .byte   $00     ; 136/88 ___________
+               .byte   $00     ; 137/89 ___________
+               .byte   $00     ; 138/8a ___________
+               .byte   $00     ; 139/8b ___________
+               .byte   $00     ; 140/8c ___________
+               .byte   $00     ; 141/8d ___________
+               .byte   $00     ; 142/8e ___________
+               .byte   $00     ; 143/8f ___________
+               .byte   $00     ; 144/90 ___________
+               .byte   $00     ; 145/91 ___________
+               .byte   $00     ; 146/92 ___________
+               .byte   $10     ; 147/93 ___________
+               .byte   $00     ; 148/94 ___________
+               .byte   $00     ; 149/95 ___________
+               .byte   $00     ; 150/96 ___________
+               .byte   $00     ; 151/97 ___________
+               .byte   $00     ; 152/98 ___________
+               .byte   $00     ; 153/99 ___________
+               .byte   $00     ; 154/9a ___________
+               .byte   $00     ; 155/9b ___________
+               .byte   $00     ; 156/9c ___________
+               .byte   $00     ; 157/9d ___________
+               .byte   $00     ; 158/9e ___________
+               .byte   $00     ; 159/9f ___________
+
+               .byte   $00     ; 160/a0 ___________
+               .byte   $00     ; 161/a1 ___________
+               .byte   $00     ; 162/a2 ___________
+               .byte   $00     ; 163/a3 ___________
+               .byte   $00     ; 164/a4 ___________
+               .byte   $00     ; 165/a5 ___________
+               .byte   $00     ; 166/a6 ___________
+               .byte   $00     ; 167/a7 ___________
+               .byte   $00     ; 168/a8 ___________
+               .byte   $00     ; 169/a9 ___________
+               .byte   $00     ; 170/aa ___________
+               .byte   $00     ; 171/ab ___________
+               .byte   $00     ; 172/ac ___________
+               .byte   $00     ; 173/ad ___________
+               .byte   $00     ; 174/ae ___________
+               .byte   $00     ; 175/af ___________
+               .byte   $00     ; 176/b0 ___________
+               .byte   $00     ; 177/b1 ___________
+               .byte   $00     ; 178/b2 ___________
+               .byte   $00     ; 179/b3 ___________
+               .byte   $00     ; 180/b4 ___________
+               .byte   $00     ; 181/b5 ___________
+               .byte   $00     ; 182/b6 ___________
+               .byte   $00     ; 183/b7 ___________
+               .byte   $00     ; 184/b8 ___________
+               .byte   $00     ; 185/b9 ___________
+               .byte   $00     ; 186/ba ___________
+               .byte   $00     ; 187/bb ___________
+               .byte   $00     ; 188/bc ___________
+               .byte   $00     ; 189/bd ___________
+               .byte   $00     ; 190/be ___________
+               .byte   $00     ; 191/bf ___________
+
+               .byte   $02     ; 192/c0 ___________
+               .byte   $02     ; 193/c1 ___________
+               .byte   $02     ; 194/c2 ___________
+               .byte   $02     ; 195/c3 ___________
+               .byte   $02     ; 196/c4 ___________
+               .byte   $02     ; 197/c5 ___________
+               .byte   $02     ; 198/c6 ___________
+               .byte   $02     ; 199/c7 ___________
+               .byte   $02     ; 200/c8 ___________
+               .byte   $02     ; 201/c9 ___________
+               .byte   $02     ; 202/ca ___________
+               .byte   $02     ; 203/cb ___________
+               .byte   $02     ; 204/cc ___________
+               .byte   $02     ; 205/cd ___________
+               .byte   $02     ; 206/ce ___________
+               .byte   $02     ; 207/cf ___________
+               .byte   $02     ; 208/d0 ___________
+               .byte   $02     ; 209/d1 ___________
+               .byte   $02     ; 210/d2 ___________
+               .byte   $02     ; 211/d3 ___________
+               .byte   $02     ; 212/d4 ___________
+               .byte   $02     ; 213/d5 ___________
+               .byte   $02     ; 214/d6 ___________
+               .byte   $02     ; 215/d7 ___________
+               .byte   $02     ; 216/d8 ___________
+               .byte   $02     ; 217/d9 ___________
+               .byte   $02     ; 218/da ___________
+               .byte   $02     ; 219/db ___________
+               .byte   $02     ; 220/dc ___________
+               .byte   $02     ; 221/dd ___________
+               .byte   $02     ; 222/de ___________
+               .byte   $00     ; 223/df ___________
+               .byte   $01     ; 224/e0 ___________
+               .byte   $01     ; 225/e1 ___________
+               .byte   $01     ; 226/e2 ___________
+               .byte   $01     ; 227/e3 ___________
+               .byte   $01     ; 228/e4 ___________
+               .byte   $01     ; 229/e5 ___________
+               .byte   $01     ; 230/e6 ___________
+               .byte   $01     ; 231/e7 ___________
+               .byte   $01     ; 232/e8 ___________
+               .byte   $01     ; 233/e9 ___________
+               .byte   $01     ; 234/ea ___________
+               .byte   $01     ; 235/eb ___________
+               .byte   $01     ; 236/ec ___________
+               .byte   $01     ; 237/ed ___________
+               .byte   $01     ; 238/ee ___________
+               .byte   $01     ; 239/ef ___________
+               .byte   $01     ; 240/f0 ___________
+               .byte   $01     ; 241/f1 ___________
+               .byte   $01     ; 242/f2 ___________
+               .byte   $01     ; 243/f3 ___________
+               .byte   $01     ; 244/f4 ___________
+               .byte   $01     ; 245/f5 ___________
+               .byte   $01     ; 246/f6 ___________
+               .byte   $01     ; 247/f7 ___________
+               .byte   $01     ; 248/f8 ___________
+               .byte   $01     ; 249/f9 ___________
+               .byte   $01     ; 250/fa ___________
+               .byte   $01     ; 251/fb ___________
+               .byte   $01     ; 252/fc ___________
+               .byte   $01     ; 253/fd ___________
+               .byte   $01     ; 254/fe ___________
+               .byte   $00     ; 255/ff ___________
+
diff --git a/libsrc/apple2/cvline.s b/libsrc/apple2/cvline.s
new file mode 100644 (file)
index 0000000..d762ad1
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+       .export         _cvlinexy, _cvline
+       .import         popa, _gotoxy, putchar, newline
+       .importzp       tmp1
+
+_cvlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length and run into _cvline
+
+_cvline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+L1:    lda     #$7C            ; Vertical bar
+       jsr     putchar         ; Write, no cursor advance
+       jsr     newline         ; Advance cursor to next line
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
diff --git a/libsrc/apple2/kbhit.s b/libsrc/apple2/kbhit.s
new file mode 100644 (file)
index 0000000..8471330
--- /dev/null
@@ -0,0 +1,18 @@
+       ;;
+       ;; Kevin Ruland
+       ;;
+       ;; int kbhit (void);
+       ;;
+
+       .export _kbhit
+
+       .import return0, return1
+       
+       .include "apple2.inc"
+
+_kbhit:
+       bit     KEY_STROBE      ; Reading strobe checks for keypress
+       bmi     L1              ; if KEY_STROBE > 127 key was pressed
+       jmp     return0
+L1:
+       jmp     return1
diff --git a/libsrc/apple2/read.s b/libsrc/apple2/read.s
new file mode 100644 (file)
index 0000000..93dec57
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int read (int fd, void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+       .export         _read
+       .import         popax, _cputc
+       .importzp       ptr1, ptr2, ptr3
+
+       .include        "apple2.inc"
+
+_read: jsr     popax           ; get count
+       sta     ptr2
+       stx     ptr2+1          ; save it for later
+       jsr     popax           ; get buf
+       sta     ptr1
+       stx     ptr1+1
+       jsr     popax           ; get fd and discard it
+       lda     #0
+       sta     ptr3
+       sta     ptr3+1          ; set count
+
+L1:            lda     ptr2
+       ora     ptr2+1          ; count zero?
+       beq     L9
+       jsr     RDKEY
+       and     #$7f            ; clear high bit.
+       pha
+       jsr     _cputc
+       pla
+       ldy     #0              ; offset into string
+       sta     (ptr1),y        ; save char
+       inc     ptr1
+       bne     L2
+       inc     ptr1+1
+L2:            inc     ptr3            ; increment count
+       bne     L3
+       inc     ptr3+1
+L3:    cmp     #$0D            ; CR?
+       bne     L1
+
+; Done, return the count
+
+L9:     lda    ptr3
+       ldx     ptr3+1
+       rts
+
+
+
diff --git a/libsrc/apple2/revers.s b/libsrc/apple2/revers.s
new file mode 100644 (file)
index 0000000..7020829
--- /dev/null
@@ -0,0 +1,25 @@
+       ;;
+       ;; Kevin Ruland
+       ;;
+       ;; unsigned char __fastcall__ revers (unsigned char onoff)
+       ;;
+
+       .export         _revers
+
+       .include        "apple2.inc"
+
+_revers:
+       ldy     TEXTTYP         ; Stash old value
+       and     #$FF            ; Test for any bit
+       bne     reverse         ; Nothing set
+       lda     #$FF
+reverse:       
+       ora     #$3F    
+       sta     TEXTTYP
+       tya                     ; What was the old value?
+       eor     #$FF            ; Normal = $FF, Reverse = $3F
+       beq     L2
+       lda     #01
+L2:    
+       rts
+
diff --git a/libsrc/apple2/where.s b/libsrc/apple2/where.s
new file mode 100644 (file)
index 0000000..b17c1f8
--- /dev/null
@@ -0,0 +1,18 @@
+
+       ;; Keivn Ruland
+       ;;
+       ;; unsigned char wherex( void );
+       ;; unsigned char wherey( void );
+
+       .export         _wherex, _wherey
+
+       .include        "apple2.inc"
+
+_wherex:
+       lda     CH
+       rts
+
+_wherey:
+       lda     CV
+       rts
+       
\ No newline at end of file
diff --git a/libsrc/apple2/write.s b/libsrc/apple2/write.s
new file mode 100644 (file)
index 0000000..cb24e00
--- /dev/null
@@ -0,0 +1,53 @@
+       ;;
+       ;; Kevin Ruland
+       ;;
+       ;; int write (int fd, const void* buf, int count);
+       ;;
+       ;; for now will only write to fd = stdout
+       ;;
+
+       .export         _write
+
+       .import         popax
+
+       .importzp       ptr1, ptr2, ptr3
+
+       .include        "apple2.inc"
+
+_write:
+       jsr     popax           ; get count
+       sta     ptr2
+       stx     ptr2+1          ; save for later
+       sta     ptr3
+       sta     ptr3+1          ; save for result
+       jsr     popax           ; get buf
+       sta     ptr1
+       stx     ptr1+1
+       jsr     popax           ; get fd and discard
+L1:    lda     ptr2
+       ora     ptr2+1          ; count zero?
+       beq     L9
+       ldy     #0
+       lda     (ptr1),y
+       cmp     #$0A            ; Check for \n = Crtl-j
+       bne     rawout
+       lda     #$0D            ; Issue cr
+rawout:
+       ora     #$80
+       jsr     COUT
+       inc     ptr1
+       bne     L2
+       inc     ptr1+1
+L2:    lda     ptr2
+       bne     L3
+       dec     ptr2
+       dec     ptr2+1
+       jmp     L1
+L3:    dec     ptr2
+       jmp     L1
+
+; No error, return count
+
+L9:    lda     ptr3
+       ldx     ptr3+1
+       rts
diff --git a/libsrc/atari/Makefile b/libsrc/atari/Makefile
new file mode 100644 (file)
index 0000000..dd23d22
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# makefile for CC65 Atari runtime library
+#
+
+ATARIDEFS = -DDIRECT_SCREEN
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $(ATARIDEFS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $(ATARIDEFS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o ctype.o chline.o cvline.o \
+        color.o gotoxy.o cclear.o revers.o readjoy.o break.o where.o write.o \
+        gotox.o gotoy.o savevec.o rwcommon.o cgetc.o read.o getargs.o close.o \
+        open.o oserror.o fdtable.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/atari/atari.inc b/libsrc/atari/atari.inc
new file mode 100644 (file)
index 0000000..1234cbc
--- /dev/null
@@ -0,0 +1,1028 @@
+;-------------------------------------------------------------------------
+; Atari System Equates -- Version 1.0.0
+; By Freddy Offenga, 4/15/2000
+;
+; References:
+; - Atari 400/800 OS rev.B source code, Atari 1979
+; - Atari OS manual - XL addendum
+; - Atari XL/XE rev.2 source code, Atari 1984
+; - Mapping the Atari - revised edition, Ian Chadwick 1985
+;
+; ##old##      old OS rev.B label - moved or deleted
+; ##1200xl##   new label introduced in 1200XL OS (rev.10/11)
+; ##rev2##     new label introduced in XL/XE OS rev.2
+;-------------------------------------------------------------------------
+
+;-------------------------------------------------------------------------
+; Configuration Equates
+;-------------------------------------------------------------------------
+
+MAXDEV = 33            ;offset to last possible entry of HATABS
+IOCBSZ = 16            ;length of IOCB
+
+SEIOCB = 0*IOCBSZ      ;##rev2## screen editor IOCB index
+MAXIOC = 8*IOCBSZ      ;first invalid IOCB index
+
+DSCTSZ = 128           ;##rev2## disk sector size
+
+LEDGE  = 2             ;left edge
+REDGE  = 39            ;right edge
+
+INIML  = $0700         ;##rev2## initial MEMLO
+
+ICSORG = $CC00         ;##rev2## international character set origin
+DCSORG = $E000         ;##rev2## domestic character set origin
+
+; IOCB Command Code Equates
+
+OPEN   = $03           ;open
+GETREC = $05           ;get record
+GETCHR = $07           ;get character(s)
+PUTREC = $09           ;put record
+PUTCHR = $0B           ;put character(s)
+CLOSE  = $0C           ;close
+STATIS = $0D           ;status
+SPECIL = $0E           ;special
+
+; Special Entry Command Equates
+
+; Screen Commands
+
+DRAWLN = $11           ;draw line
+FILLIN = $12           ;draw line with right fill
+
+; ICAX1 Auxiliary Byte 1 Equates
+
+APPEND = $01           ;open write append (D:)
+DIRECT = $02           ;open for directory access (D:)
+OPNIN  = $04           ;open for input (all devices)
+OPNOT  = $08           ;open for output (all devices)
+MXDMOD = $10           ;open for mixed mode (E:, S:)
+INSCLR = $20           ;open for input without clearing screen
+
+; Device Code Equates
+
+CASSET = 'C'           ;cassette
+DISK   = 'D'           ;disk
+SCREDT = 'E'           ;screen editor
+KBD    = 'K'           ;keyboard
+PRINTR = 'P'           ;printer
+DISPLY = 'S'           ;screen display
+
+; Character and Key Code Equates
+
+CLS    = $7D           ;##rev2## clear screen
+EOL    = $9B           ;end of line (RETURN)
+
+HELP   = $11           ;##1200xl## key code for HELP
+CNTLF1 = $83           ;##1200xl## key code for CTRL-F1
+CNTLF2 = $84           ;##1200xl## key code for CTRL-F2
+CNTLF3 = $93           ;##1200xl## key code for CTRL-F3
+CNTLF4 = $94           ;##1200xl## key code for CTRL-F4
+CNTL1  = $9F           ;##1200xl## key code for CTRL-1
+
+; Status Code Equates
+
+SUCCES = 1             ;($01) succesful operation
+
+BRKABT = 128           ;($80) BREAK key abort
+PRVOPN = 129           ;($81) IOCB already open error
+NONDEV = 130           ;($82) nonexistent device error
+WRONLY = 131           ;($83) IOCB opened for write only error
+NVALID = 132           ;($84) invalid command error
+NOTOPN = 133           ;($85) device/file not open error
+BADIOC = 134           ;($86) invalid IOCB index error
+RDONLY = 135           ;($87) IOCB opened for read only error
+EOFERR = 136           ;($88) end of file error
+TRNRCD = 137           ;($89) truncated record error
+TIMOUT = 138           ;($8A) peripheral device timeout error
+DNACK  = 139           ;($8B) device does not acknowledge command
+FRMERR = 140           ;($8C) serial bus framing error
+CRSROR = 141           ;($8D) cursor overrange error
+OVRRUN = 142           ;($8E) serial bus data overrun error
+CHKERR = 143           ;($8F) serial bus checksum error
+DERROR = 144           ;($90) device done (operation incomplete)
+BADMOD = 145           ;($91) bad screen mode number error
+FNCNOT = 146           ;($92) function not implemented in handler
+SCRMEM = 147           ;($93) insufficient memory for screen mode
+
+; DCB Device Bus Equates
+
+DISKID = $31           ;##rev2## disk bus ID
+PDEVN  = $40           ;##rev2## printer bus ID
+CASET  = $60           ;##rev2## cassette bus ID
+
+; Bus Command Equates
+
+FOMAT  = '!'           ;##rev2## format command
+PUTSEC = 'P'           ;##rev2## put sector command
+READ   = 'R'           ;##rev2## read command
+STATC  = 'S'           ;##rev2## status command
+WRITE  = 'W'           ;##rev2## write command
+
+; Command Auxiliary Byte Equates
+
+DOUBLE = 'D'           ;##rev2## print 20 characters double width
+NORMAL = 'N'           ;##rev2## print 40 characters normally
+PLOT   = 'P'           ;##rev2## plot
+SIDWAY = 'S'           ;##rev2## print 16 characters sideways
+
+; Bus Response Equates
+
+ACK    = 'A'           ;##rev2## device acknowledged
+COMPLT = 'C'           ;##rev2## device succesfully completed operation
+ERROR  = 'E'           ;##rev2## device incurred error
+NACK   = 'N'           ;##rev2## device did not understand
+
+; Floating Point Miscellaneous Equates
+
+FPREC  = 6             ;precision
+
+FMPREC = FPREC-1       ;##rev2## length of mantissa
+
+; Cassette Record Type Equates
+
+HDR    = $FB           ;##rev2## header
+DTA    = $FC           ;##rev2## data record
+DT1    = $FA           ;##rev2## last data record
+EOT    = $FE           ;##rev2## end of tape (file)
+
+TONE1  = 2             ;##rev2## record
+TONE2  = 1             ;##rev2## playback
+
+; Cassette Timing Equates
+
+WLEADN = 1152          ;##rev2## NTSC 19.2 second WRITE file leader
+RLEADN = 576           ;##rev2## NTSC 9.6 second READ file leader
+WIRGLN = 180           ;##rev2## NTSC 3.0 second WRITE IRG
+RIRGLN = 120           ;##rev2## NTSC 2.0 second READ IRG
+WSIRGN = 15            ;##rev2## NTSC 0.25 second WRITE short IRG
+RSIRGN = 10            ;##rev2## NTSC 0.16 second READ short IRG
+BEEPNN = 30            ;##rev2## NTSC 0.5 second beep duration
+BEEPFN = 10            ;##rev2## NTSC 0.16 seconrd beep duration
+
+WLEADP = 960           ;##rev2## PAL 19.2 second WRITE file leader
+RLEADP = 480           ;##rev2## PAL 9.6 second READ file leader
+WIRGLP = 150           ;##rev2## PAL 3.0 second WRITE IRG
+RIRGLP = 100           ;##rev2## PAL 2.0 second READ IRG
+WSIRGP = 13            ;##rev2## PAL 0.25 second WRITE short IRG
+RSIRGP = 8             ;##rev2## PAL 0.16 second READ short IRG
+BEEPNP = 25            ;##rev2## PAL 0.5 second beep duration
+BEEPFP = 8             ;##rev2## PAL 0.16 seconrd beep duration
+
+WIRGHI = 0             ;##rev2## high WRITE IRG
+RIRGHI = 0             ;##rev2## high READ IRG
+
+; Power-up Validation Byte Value Equates
+
+PUPVL1 = $5C           ;##rev2## power-up validation value 1
+PUPVL2 = $93           ;##rev2## power-up validation value 2
+PUPVL3 = $25           ;##rev2## power-up validation value 3
+
+; Relocating Loader Miscellaneous Equates
+
+DATAER = 156           ;##rev2## end of record appears before END
+MEMERR = 157           ;##rev2## memory insufficient for load error
+
+; Miscellaneous Equates
+
+IOCFRE = $FF           ;IOCB free indication
+
+B19200 = $0028         ;##rev2## 19200 baud POKEY counter value
+B00600 = $05CC         ;##rev2## 600 baud POKEY counter value
+
+HITONE = $05           ;##rev2## FSK high freq. POKEY counter value
+LOTONE = $07           ;##rev2## FSK low freq. POKEY counter value
+
+NCOMLO = $34           ;##rev2## PIA lower NOT COMMAND line command
+NCOMHI = $3C           ;##rev2## PIA raise NOT COMMAND line command
+
+MOTRGO = $34           ;##rev2## PIA cassette motor ON command
+MOTRST = $3C           ;##rev2## PIA cassette motor OFF command
+
+NODAT  = $00           ;##rev2## SIO immediate operation
+GETDAT = $40           ;##rev2## SIO read data frame
+PUTDAT = $80           ;##rev2## SIO write data frame
+
+CRETRI = 13            ;##rev2## number of command frame retries
+DRETRI = 1             ;##rev2## number of device retries
+CTIM   = 2             ;##rev2## command frame ACK timeout
+
+NBUFSZ = 40            ;##rev2## print normal buffer size
+DBUFSZ = 20            ;##rev2## print double buffer size
+SBUFSZ = 29            ;##rev2## print sideways buffer size
+
+;-------------------------------------------------------------------------
+; Page Zero Address Equates
+;-------------------------------------------------------------------------
+
+LINZBS = $00           ;LINBUG RAM (WILL BE REPLACED BY MONITOR RAM)
+LNFLG  = $00           ;##1200xl## 1-byte LNBUG flag (0 = not LNBUG)
+NGFLAG = $01           ;##1200xl## 1-byte memory status (0 = failure)
+
+; Not Cleared
+
+CASINI = $02           ;CASSETTE INIT LOCATION
+RAMLO  = $04           ;RAM POINTER FOR MEMORY TEST
+TRAMSZ = $06           ;TEMPORARY REGISTER FOR RAM SIZE
+;TSTDAT        = $07           ;##old## RAM TEST DATA REGISTER
+CMCMD  = $07           ;##rev2## 1-byte command communications
+
+; Cleared upon Coldstart only
+
+WARMST = $08           ;WARM START FLAG
+BOOTQ  = $09           ;SUCCESSFUL BOOT FLAG
+DOSVEC = $0A           ;DISK SOFTWARE START VECTOR
+DOSINI = $0C           ;DISK SOFTWARE INIT ADDRESS
+APPMHI = $0E           ;APPLICATIONS MEMORY HI LIMIT
+
+; Cleared upon Coldstart or Warmstart
+
+INTZBS = $10           ;INTERRUPT HANDLER
+
+POKMSK = $10           ;SYSTEM MASK FOR POKEY IRG ENABLE
+BRKKEY = $11           ;BREAK KEY FLAG
+RTCLOK = $12           ;REAL TIME CLOCK (IN 16 MSEC UNITS>
+BUFADR = $15           ;INDIRECT BUFFER ADDRESS REGISTER
+ICCOMT = $17           ;COMMAND FOR VECTOR
+DSKFMS = $18           ;DISK FILE MANAGER POINTER
+DSKUTL = $1A           ;DISK UTILITIES POINTER
+ABUFPT = $1C           ;##1200xl## 4-byte ACMI buffer pointer area
+
+;PTIMOT        = $1C           ;##old## PRINTER TIME OUT REGISTER
+;PBPNT = $1D           ;##old## PRINT BUFFER POINTER
+;PBUFSZ        = $1E           ;##old## PRINT BUFFER SIZE
+;PTEMP = $1F           ;##old## TEMPORARY REGISTER
+
+ZIOCB  = $20           ;ZERO PAGE I/O CONTROL BLOCK
+IOCBAS = $20           ;16-byte page zero IOCB
+ICHIDZ = $20           ;HANDLER INDEX NUMBER (FF = IOCB FREE)
+ICDNOZ = $21           ;DEVICE NUMBER (DRIVE NUMBER)
+ICCOMZ = $22           ;COMMAND CODE
+ICSTAZ = $23           ;STATUS OF LAST IOCB ACTION
+ICBALZ = $24           ;BUFFER ADDRESS LOW BYTE
+ICBAHZ = $25           ;1-byte high buffer address
+ICPTLZ = $26           ;PUT BYTE ROUTINE ADDRESS -1
+ICPTHZ = $27           ;1-byte high PUT-BYTE routine address
+ICBLLZ = $28           ;BUFFER LENGTH LOW BYTE
+ICBLHZ = $29           ;1-byte high buffer length
+ICAX1Z = $2A           ;AUXILIARY INFORMATION FIRST BYTE
+ICAX2Z = $2B           ;1-byte second auxiliary information
+ICSPRZ = $2C           ;4-byte spares
+
+ENTVEC = $2C           ;##rev2## 2-byte (not used)
+ICIDNO = $2E           ;IOCB NUMBER X 16
+CIOCHR = $2F           ;CHARACTER BYTE FOR CURRENT OPERATION
+
+STATUS = $30           ;INTERNAL STATUS STORAGE
+CHKSUM = $31           ;CHECKSUM (SINGLE BYTE SUM WITH CARRY)
+BUFRLO = $32           ;POINTER TO DATA BUFFER (LO BYTE)
+BUFRHI = $33           ;POINTER TO DATA BUFFER (HI BYTE)
+BFENLO = $34           ;NEXT BYTE PAST END OF THE DATA BUFFER LO
+BFENHI = $35           ;NEXT BYTE PAST END OF THE DATA BUFFER HI
+;CRETRY        = $36           ;##old## NUMBER OF COMMAND FRAME RETRIES
+;DRETRY        = $37           ;##old## NUMBER OF DEVICE RETRIES
+LTEMP  = $36           ;##1200xl## 2-byte loader temporary
+BUFRFL = $38           ;DATA BUFFER FULL FLAG
+RECVDN = $39           ;RECEIVE DONE FLAG
+XMTDON = $3A           ;TRANSMISSION DONE FLAG
+CHKSNT = $3B           ;CHECKSUM SENT FLAG
+NOCKSM = $3C           ;NO CHECKSUM FOLLOWS DATA FLAG
+BPTR   = $3D           ;1-byte cassette buffer pointer
+FTYPE  = $3E           ;1-byte cassette IRG type
+FEOF   = $3F           ;1-byte cassette EOF flag (0 = quiet)
+FREQ   = $40           ;1-byte cassette beep counter
+SOUNDR = $41           ;NOISY I/0 FLAG. (ZERO IS QUIET)
+
+CRITIC = $42           ;DEFINES CRITICAL SECTION (CRITICAL IF NON-Z)
+
+FMSZPG = $43           ;DISK FILE MANAGER SYSTEM ZERO PAGE
+
+;CKEY  = $4A           ;##old## FLAG SET WHEN GAME START PRESSED
+ZCHAIN = $4A           ;##1200xl## 2-byte handler linkage chain pointer
+;CASSBT        = $4B           ;##old## CASSETTE BOOT FLAG
+DSTAT  = $4C           ;DISPLAY STATUS
+ATRACT = $4D           ;ATRACT FLAG
+DRKMSK = $4E           ;DARK ATRACT MASK
+COLRSH = $4F           ;ATRACT COLOR SHIFTER (EOR'ED WITH PLAYFIELD
+
+
+TMPCHR = $50           ;1-byte temporary character
+HOLD1  = $51           ;1-byte temporary
+LMARGN = $52           ;LEFT MARGIN (SET TO 1 AT POWER ON>
+RMARGN = $53           ;RIGHT MARGIN (SET TO 38 AT POWER ON)
+ROWCRS = $54           ;1-byte cursor row
+COLCRS = $55           ;2-byte cursor column
+DINDEX = $57           ;1-byte display mode
+SAVMSC = $58           ;2-byte saved memory scan counter
+OLDROW = $5A           ;1-byte prior row
+OLDCOL = $5B           ;2-byte prior column
+OLDCHR = $5D           ;DATA UNDER CURSOR
+OLDADR = $5E           ;2-byte saved cursor memory address
+FKDEF  = $60           ;##1200xl## 2-byte function key definition table
+;NEWROW        = $60           ;##old## POINT DRAW GOES TO
+;NEWCOL        = $61           ;##old##
+PALNTS = $62           ;##1200xl## 1-byte PAL/NTSC indicator (0 = NTSC)
+LOGCOL = $63           ;POINTS AT COLUMN IN LOGICAL LINE
+ADRESS = $64           ;2-byte temporary address
+
+MLTTMP = $66           ;1-byte temporary
+OPNTMP = $66           ;FIRST BYTE IS USED IN OPEN AS TEMP
+TOADR  = $66           ;##rev2## 2-byte destination address
+
+SAVADR = $68           ;2-byte saved address
+FRMADR = $68           ;##rev2## 2-byte source address
+
+RAMTOP = $6A           ;RAM SIZE DEFINED BY POWER ON LOGIC
+BUFCNT = $6B           ;BUFFER COUNT
+BUFSTR = $6C           ;EDITOR GETCH POINTER
+BITMSK = $6E           ;BIT MASK
+SHFAMT = $6F           ;1-byte shift amount for pixel justifucation
+ROWAC  = $70           ;2-byte draw working row
+COLAC  = $72           ;2-byte draw working column
+ENDPT  = $74           ;2-byte end point
+DELTAR = $76           ;1-byte row difference
+DELTAC = $77           ;2-byte column difference
+KEYDEF = $79           ;##1200xl## 2-byte key definition table address
+;ROWINC        = $79           ;##old##
+;COLINC        = $7A           ;##old##
+SWPFLG = $7B           ;NON-0 1F TXT AND REGULAR RAM IS SWAPPED
+HOLDCH = $7C           ;CH IS MOVED HERE IN KGETCH BEFORE CNTL & SH
+INSDAT = $7D           ;1-byte temporary
+COUNTR = $7E           ;2-byte draw iteration count
+
+; Floating Point Package Page Zero Address Equates
+
+FR0    = $D4           ;6-byte register 0
+FR0M   = $D5           ;##rev2## 5-byte register 0 mantissa
+QTEMP  = $D9           ;##rev2## 1-byte temporary
+
+FRE    = $DA           ;6-byte (internal) register E
+
+FR1    = $E0           ;FP REG1
+FR1M   = $E1           ;##rev2## 5-byte register 1 mantissa
+
+FR2    = $E6           ;6-byte (internal) register 2
+
+FRX    = $EC           ;1-byte temporary
+
+EEXP   = $ED           ;VALUE OF E
+
+FRSIGN = $EE           ;##rev2## 1-byte floating point sign
+NSIGN  = $EE           ;SIGN OF #
+
+PLYCNT = $EF           ;##rev2## 1-byte polynomial degree
+ESIGN  = $EF           ;SIGN OF EXPONENT
+
+SGNFLG = $F0           ;##rev2## 1-byte sign flag
+FCHRFLG        = $F0           ;1ST CHAR FLAG
+
+XFMFLG = $F1           ;##rev2## 1-byte transform flag
+DIGRT  = $F1           ;# OF DIGITS RIGHT OF DECIMAL
+
+CIX    = $F2           ;CURRENT INPUT INDEX
+INBUFF = $F3           ;POINTS TO USER'S LINE INPUT BUFFER
+
+ZTEMP1 = $F5           ;2-byte temporary
+ZTEMP4 = $F7           ;2-byte temporary
+ZTEMP3 = $F9           ;2-byte temporary
+
+;DEGFLG        = $FB           ;##old## same as RADFLG
+;RADFLG        = $FB           ;##old## 0=RADIANS, 6=DEGREES
+
+FLPTR  = $FC           ;2-byte floating point number pointer
+FPTR2  = $FE           ;2-byte floating point number pointer
+
+;-------------------------------------------------------------------------
+; Page Two Address Equates
+;-------------------------------------------------------------------------
+
+INTABS = $0200         ;INTERRUPT RAM
+
+VDSLST = $0200         ;DISPLAY LIST NMI VECTOR
+VPRCED = $0202         ;PROCEED LINE IRQ VECTOR
+VINTER = $0204         ;INTERRUPT LINE IRQ VECTOR
+VBREAK = $0206         ;SOFTWARE BREAK (00) INSTRUCTION IRQ VECTOR
+VKEYBD = $0208         ;POKEY KEYBOARD IRQ VECTOR
+VSERIN = $020A         ;POKEY SERIAL INPUT READY IRQ
+VSEROR = $020C         ;POKEY SERIAL OUTPUT READY IRQ
+VSEROC = $020E         ;POKEY SERIAL OUTPUT COMPLETE IRQ
+VTIMR1 = $0210         ;POKEY TIMER 1 IRG
+VTIMR2 = $0212         ;POKEY TIMER 2 IRG
+VTIMR4 = $0214         ;POKEY TIMER 4 IRG
+VIMIRQ = $0216         ;IMMEDIATE IRG VECTOR
+CDTMV1 = $0218         ;COUNT DOWN TIMER 1
+CDTMV2 = $021A         ;COUNT DOWN TIMER 2
+CDTMV3 = $021C         ;COUNT DOWN TIMER 3
+CDTMV4 = $021E         ;COUNT DOWN TIMER 4
+CDTMV5 = $0220         ;COUNT DOWN TIMER 5
+VVBLKI = $0222         ;IMMEDIATE VERTICAL BLANK NMI VECTOR
+VVBLKD = $0224         ;DEFERRED VERTICAL BLANK NMI VECTOR
+CDTMA1 = $0226         ;COUNT DOWN TIMER 1 JSR ADDRESS
+CDTMA2 = $0228         ;COUNT DOWN TIMER 2 JSR ADDRESS
+CDTMF3 = $022A         ;COUNT DOWN TIMER 3 FLAG
+SRTIMR = $022B         ;SOFTWARE REPEAT TIMER
+CDTMF4 = $022C         ;COUNT DOWN TIMER 4 FLAG
+INTEMP = $022D         ;IAN'S TEMP
+CDTMF5 = $022E         ;COUNT DOWN TIMER FLAG 5
+SDMCTL = $022F         ;SAVE DMACTL REGISTER
+SDLSTL = $0230         ;SAVE DISPLAY LIST LOW BYTE
+SDLSTH = $0231         ;SAVE DISPLAY LIST HI BYTE
+SSKCTL = $0232         ;SKCTL REGISTER RAM
+LCOUNT = $0233         ;##1200xl## 1-byte relocating loader record
+LPENH  = $0234         ;LIGHT PEN HORIZONTAL VALUE
+LPENV  = $0235         ;LIGHT PEN VERTICAL VALUE
+BRKKY  = $0236         ;BREAK KEY VECTOR
+;RELADR        = $0238         ;##1200xl## 2-byte relocatable loader address
+VPIRQ  = $0238         ;##rev2## 2-byte parallel device IRQ vector
+CDEVIC = $023A         ;COMMAND FRAME BUFFER - DEVICE
+CCOMND = $023B         ;COMMAND
+CAUX1  = $023C         ;COMMAND AUX BYTE 1
+CAUX2  = $023D         ;COMMAND AUX BYTE 2
+
+TEMP   = $023E         ;TEMPORARY RAM CELL
+
+ERRFLG = $023F         ;ERROR FLAG - ANY DEVICE ERROR EXCEPT TIME OUT
+
+DFLAGS = $0240         ;DISK FLAGS FROM SECTOR ONE
+DBSECT = $0241         ;NUMBER OF DISK BOOT SECTORS
+BOOTAD = $0242         ;ADDRESS WHERE DISK BOOT LOADER WILL 13E PUT
+COLDST = $0244         ;COLDSTART FLAG (1=IN MIDDLE OF COLDSTART>
+RECLEN = $0245         ;##1200xl## 1-byte relocating loader record length
+DSKTIM = $0246         ;DISK TIME OUT REGISTER
+;LINBUF        = $0247         ;##old## CHAR LINE BUFFER
+PDVMSK = $0247         ;##rev2## 1-byte parallel device selection mask
+SHPDVS = $0248         ;##rev2## 1-byte PDVS (parallel device select)
+PDIMSK = $0249         ;##rev2## 1-byte parallel device IRQ selection
+RELADR = $024A         ;##rev2## 2-byte relocating loader relative adr.
+PPTMPA = $024C         ;##rev2## 1-byte parallel device handler temporary
+PPTMPX = $024D         ;##rev2## 1-byte parallel device handler temporary
+
+CHSALT = $026B         ;##1200xl## 1-byte character set alternate
+VSFLAG = $026C         ;##1200xl## 1-byte fine vertical scroll count
+KEYDIS = $026D         ;##1200xl## 1-byte keyboard disable
+FINE   = $026E         ;##1200xl## 1-byte fine scrolling mode
+GPRIOR = $026F         ;GLOBAL PRIORITY CELL
+
+PADDL0 = $0270         ;1-byte potentiometer 0
+PADDL1 = $0271         ;1-byte potentiometer 1
+PADDL2 = $0272         ;1-byte potentiometer 2
+PADDL3 = $0273         ;1-byte potentiometer 3
+PADDL4 = $0274         ;1-byte potentiometer 4
+PADDL5 = $0275         ;1-byte potentiometer 5
+PADDL6 = $0276         ;1-byte potentiometer 6
+PADDL7 = $0277         ;1-byte potentiometer 7
+
+STICK0 = $0278         ;1-byte joystick 0
+STICK1 = $0279         ;1-byte joystick 1
+STICK2 = $027A         ;1-byte joystick 2
+STICK3 = $027B         ;1-byte joystick 3
+
+PTRIG0 = $027C         ;1-byte paddle trigger 0
+PTRIG1 = $027D         ;1-byte paddle trigger 1
+PTRIG2 = $027E         ;1-byte paddle trigger 2
+PTRIG3 = $027F         ;1-byte paddle trigger 3
+PTRIG4 = $0280         ;1-byte paddle trigger 4
+PTRIG5 = $0281         ;1-byte paddle trigger 5
+PTRIG6 = $0281         ;1-byte paddle trigger 6
+PTRIG7 = $0283         ;1-byte paddle trigger 7
+
+STRIG0 = $0284         ;1-byte joystick trigger 0
+STRIG1 = $0285         ;1-byte joystick trigger 1
+STRIG2 = $0286         ;1-byte joystick trigger 2
+STRIG3 = $0287         ;1-byte joystick trigger 3
+
+;CSTAT = $0288         ;##old## cassette status register
+HIBYTE = $0288         ;##1200xl## 1-byte relocating loader high byte
+WMODE  = $0289         ;1-byte cassette WRITE mode
+BLIM   = $028A         ;1-byte cassette buffer limit
+IMASK  = $028B         ;##rev2## (not used)
+JVECK  = $028C         ;2-byte jump vector or temporary
+NEWADR = $028E         ;##1200xl## 2-byte relocating address
+TXTROW = $0290         ;TEXT ROWCRS
+TXTCOL = $0291         ;TEXT COLCRS
+TINDEX = $0293         ;TEXT INDEX
+TXTMSC = $0294         ;FOOLS CONVRT INTO NEW MSC
+TXTOLD = $0296         ;OLDROW & OLDCOL FOR TEXT (AND THEN SOME)
+;TMPX1 = $029C         ;##old## 1-byte temporary register
+CRETRY = $029C         ;##1200xl## 1-byte number of command frame retries
+HOLD3  = $029D         ;1-byte temporary
+SUBTMP = $029E         ;1-byte temporary
+HOLD2  = $029F         ;1-byte (not used)
+DMASK  = $02A0         ;1-byte display (pixel location) mask
+TMPLBT = $02A1         ;1-byte (not used)
+ESCFLG = $02A2         ;ESCAPE FLAG
+TABMAP = $02A3         ;15-byte (120 bit) tab stop bit map
+LOGMAP = $02B2         ;LOGICAL LINE START BIT MAP
+INVFLG = $02B6         ;INVERSE VIDEO FLAG (TOGGLED BY ATARI KEY)
+FILFLG = $02B7         ;RIGHT FILL FLAG FOR DRAW
+TMPROW = $02B8         ;1-byte temporary row
+TMPCOL = $02B9         ;2-byte temporary column
+SCRFLG = $02BB         ;SET IF SCROLL OCCURS
+HOLD4  = $02BC         ;TEMP CELL USED IN DRAW ONLY
+;HOLD5 = $02BD         ;##old## DITTO
+DRETRY = $02BD         ;##1200xl## 1-byte number of device retries
+SHFLOK = $02BE         ;1-byte shift/control lock flags
+BOTSCR = $02BF         ;BOTTOM OF SCREEN   24 NORM 4 SPLIT
+
+PCOLR0 = $02C0         ;1-byte player-missile 0 color/luminance
+PCOLR1 = $02C1         ;1-byte player-missile 1 color/luminance
+PCOLR2 = $02C2         ;1-byte player-missile 2 color/luminance
+PCOLR3 = $02C3         ;1-byte player-missile 3 color/luminance
+
+COLOR0 = $02C4         ;1-byte playfield 0 color/luminance
+COLOR1 = $02C5         ;1-byte playfield 1 color/luminance
+COLOR2 = $02C6         ;1-byte playfield 2 color/luminance
+COLOR3 = $02C7         ;1-byte playfield 3 color/luminance
+
+COLOR4 = $02C8         ;1-byte background color/luminance
+
+PARMBL = $02C9         ;##rev2## 6-byte relocating loader parameter
+RUNADR = $02C9         ;##1200xl## 2-byte run address
+HIUSED = $02CB         ;##1200xl## 2-byte highest non-zero page address
+ZHIUSE = $02CD         ;##1200xl## 2-byte highest zero page address
+
+OLDPAR = $02CF         ;##rev2## 6-byte relocating loader parameter
+GBYTEA = $02CF         ;##1200xl## 2-byte GET-BYTE routine address
+LOADAD = $02D1         ;##1200xl## 2-byte non-zero page load address
+ZLOADA = $02D3         ;##1200xl## 2-byte zero page load address
+
+DSCTLN = $02D5         ;##1200xl## 2-byte disk sector length
+ACMISR = $02D7         ;##1200xl## 2-byte ACMI interrupt service routine
+KRPDEL = $02D9         ;##1200xl## 1-byte auto-repeat delay
+KEYREP = $02DA         ;##1200xl## 1-byte auto-repeat rate
+NOCLIK = $02DB         ;##1200xl## 1-byte key click disable
+HELPFG = $02DC         ;##1200xl## 1-byte HELP key flag (0 = no HELP)
+DMASAV = $02DD         ;##1200xl## 1-byte SDMCTL save/restore
+PBPNT  = $02DE         ;##1200xl## 1-byte printer buffer pointer
+PBUFSZ = $02DF         ;##1200xl## 1-byte printer buffer size
+
+GLBABS = $02E0         ;4-byte global variables for non-DOS users
+RUNAD  = $02E0         ;##map## 2-byte binary file run address
+INITAD = $02E2         ;##map## 2-byte binary file initialization address
+
+RAMSIZ = $02E4         ;RAM SIZE (HI BYTE ONLY)
+MEMTOP = $02E5         ;TOP OF AVAILABLE USER MEMORY
+MEMLO  = $02E7         ;BOTTOM OF AVAILABLE USER MEMORY
+HNDLOD = $02E9         ;##1200xl## 1-byte user load flag
+DVSTAT = $02EA         ;STATUS BUFFER
+CBAUDL = $02EE         ;1-byte low cassette baud rate
+CBAUDH = $02EF         ;1-byte high cassette baud rate
+CRSINH = $02F0         ;CURSOR INHIBIT (00 = CURSOR ON)
+KEYDEL = $02F1         ;KEY DELAY
+CH1    = $02F2         ;1-byte prior keyboard character
+CHACT  = $02F3         ;CHACTL REGISTER RAM
+CHBAS  = $02F4         ;CHBAS REGISTER RAM
+
+NEWROW = $02F5         ;##1200xl## 1-byte draw destination row
+NEWCOL = $02F6         ;##1200xl## 2-byte draw destination column
+ROWINC = $02F8         ;##1200xl## 1-byte draw row increment
+COLINC = $02F9         ;##1200xl## 1-byte draw column increment
+
+CHAR   = $02FA         ;1-byte internal character
+ATACHR = $02FB         ;ATASCII CHARACTER
+CH     = $02FC         ;GLOBAL VARIABLE FOR KEYBOARD
+FILDAT = $02FD         ;RIGHT FILL DATA <DRAW>
+DSPFLG = $02FE         ;DISPLAY FLAG   DISPLAY CNTLS IF NON-ZERO
+SSFLAG = $02FF         ;START/STOP FLAG FOR PAGING (CNTL 1). CLEARE
+
+;-------------------------------------------------------------------------
+; Page Three Address Equates
+;-------------------------------------------------------------------------
+
+DCB    = $0300         ;DEVICE CONTROL BLOCK
+DDEVIC = $0300         ;PERIPHERAL UNIT 1 BUS I.D. NUMBER
+DUNIT  = $0301         ;UNIT NUMBER
+DCOMND = $0302         ;BUS COMMAND
+DSTATS = $0303         ;COMMAND TYPE/STATUS RETURN
+DBUFLO = $0304         ;1-byte low data buffer address
+DBUFHI = $0305         ;1-byte high data buffer address
+DTIMLO = $0306         ;DEVICE TIME OUT IN 1 SECOND UNITS
+DUNUSE = $0307         ;UNUSED BYTE
+DBYTLO = $0308         ;1-byte low number of bytes to transfer
+DBYTHI = $0309         ;1-byte high number of bytes to transfer
+DAUX1  = $030A         ;1-byte first command auxiliary
+DAUX2  = $030B         ;1-byte second command auxiliary
+
+TIMER1 = $030C         ;INITIAL TIMER VALUE
+;ADDCOR        = $030E         ;##old## ADDITION CORRECTION
+JMPERS = $030E         ;##1200xl## 1-byte jumper options
+CASFLG = $030F         ;CASSETTE MODE WHEN SET
+TIMER2 = $0310         ;2-byte final baud rate timer value
+TEMP1  = $0312         ;TEMPORARY STORAGE REGISTER
+;TEMP2 = $0314         ;##old## TEMPORARY STORAGE REGISTER
+TEMP2  = $0313         ;##1200xl## 1-byte temporary 
+PTIMOT = $0314         ;##1200xl## 1-byte printer timeout
+TEMP3  = $0315         ;TEMPORARY STORAGE REGISTER
+SAVIO  = $0316         ;SAVE SERIAL IN DATA PORT
+TIMFLG = $0317         ;TIME OUT FLAG FOR BAUD RATE CORRECTION
+STACKP = $0318         ;SIO STACK POINTER SAVE CELL
+TSTAT  = $0319         ;TEMPORARY STATUS HOLDER
+
+HATABS = $031A         ;35-byte handler address table (was 38 bytes)
+PUPBT1 = $033D         ;##1200xl## 1-byte power-up validation byte 1
+PUPBT2 = $033E         ;##1200xl## 1-byte power-up validation byte 2
+PUPBT3 = $033F         ;##1200xl## 1-byte power-up validation byte 3
+
+IOCB   = $0340         ;I/O CONTROL BLOCKS
+ICHID  = $0340         ;HANDLER INDEX NUMBER (FF=IOCB FREE)
+ICDNO  = $0341         ;DEVICE NUMBER (DRIVE NUMBER)
+ICCOM  = $0342         ;COMMAND CODE
+ICSTA  = $0343         ;STATUS OF LAST IOCB ACTION
+ICBAL  = $0344         ;1-byte low buffer address
+ICBAH  = $0345         ;1-byte high buffer address
+ICPTL  = $0346         ;1-byte low PUT-BYTE routine address - 1
+ICPTH  = $0347         ;1-byte high PUT-BYTE routine address - 1
+ICBLL  = $0348         ;1-byte low buffer length
+ICBLH  = $0349         ;1-byte high buffer length
+ICAX1  = $034A         ;1-byte first auxiliary information
+ICAX2  = $034B         ;1-byte second auxiliary information
+ICSPR  = $034C         ;FOUR SPARE BYTES
+
+PRNBUF = $03C0         ;PRINTER BUFFER
+SUPERF = $03E8         ;##1200xl## 1-byte editor super function flag
+CKEY   = $03E9         ;##1200xl## 1-byte cassette boot request flag
+CASSBT = $03EA         ;##1200xl## 1-byte cassette boot flag
+CARTCK = $03EB         ;##1200xl## 1-byte cartridge equivalence check
+DERRF  = $03EC         ;##rev2## 1-byte screen OPEN error flag
+
+; Remainder of Page Three Not Cleared upon Reset
+
+ACMVAR = $03ED         ;##1200xl## 11 bytes reserved for ACMI
+BASICF = $03F8         ;##rev2## 1-byte BASIC switch flag
+MINTLK = $03F9         ;##1200xl## 1-byte ACMI module interlock
+GINTLK = $03FA         ;##1200xl## 1-byte cartridge interlock
+CHLINK = $03FB         ;##1200xl## 2-byte loaded handler chain link
+CASBUF = $03FD         ;CASSETTE BUFFER
+
+;-------------------------------------------------------------------------
+; Page Four/Five Address Equates
+;-------------------------------------------------------------------------
+
+; USER AREA STARTS HERE AND GOES TO END OF PAGE FIVE
+USAREA = $0480         ;128 bytes reserved for application
+
+LBPR1  = $057E         ;LBUFF PREFIX 1
+LBPR2  = $057F         ;LBUFF PREFIX 2
+LBUFF  = $0580         ;128-byte line buffer
+
+PLYARG = $05E0         ;6-byte floating point polynomial argument
+FPSCR  = $05E6         ;6-byte floating point temporary
+FPSCR1 = $05EC         ;6-byte floating point temporary
+
+;LBFEND        = $05FF         ;##old## END OF LBUFF
+
+;-------------------------------------------------------------------------
+; Cartridge Address Equates
+;-------------------------------------------------------------------------
+
+CARTCS = $BFFA         ;##rev2## 2-byte cartridge coldstart address
+CART   = $BFFC         ;##rev2## 1-byte cartridge present indicator
+CARTFG = $BFFD         ;##rev2## 1-byte cartridge flags
+CARTAD = $BFFE         ;##rev2## 2-byte cartridge start vector
+
+;-------------------------------------------------------------------------
+; CTIA/GTIA Address Equates
+;-------------------------------------------------------------------------
+
+GTIA   = $D000         ;CTIA/GTIA area
+
+; Read/Write Addresses
+
+CONSOL = $D01F         ;console switches and speaker control
+
+; Read Addresses
+
+M0PF   = $D000         ;missile 0 and playfield collision
+M1PF   = $D001         ;missile 1 and playfield collision
+M2PF   = $D002         ;missile 2 and playfield collision
+M3PF   = $D003         ;missile 3 and playfield collision
+
+P0PF   = $D004         ;player 0 and playfield collision
+P1PF   = $D005         ;player 1 and playfield collision
+P2PF   = $D006         ;player 2 and playfield collision
+P3PF   = $D007         ;player 3 and playfield collision
+
+M0PL   = $D008         ;missile 0 and player collision
+M1PL   = $D009         ;missile 1 and player collision
+M2PL   = $D00A         ;missile 2 and player collision
+M3PL   = $D00B         ;missile 3 and player collision
+
+P0PL   = $D00C         ;player 0 and player collision
+P1PL   = $D00D         ;player 1 and player collision
+P2PL   = $D00E         ;player 2 and player collision
+P3PL   = $D00F         ;player 3 and player collision
+
+TRIG0  = $D010         ;joystick trigger 0
+TRIG1  = $D011         ;joystick trigger 1
+
+TRIG2  = $D012         ;cartridge interlock
+TRIG3  = $D013         ;ACMI module interlock
+
+PAL    = $D014         ;##rev2## PAL/NTSC indicator
+
+; Write Addresses
+
+HPOSP0 = $D000         ;player 0 horizontal position
+HPOSP1 = $D001         ;player 1 horizontal position
+HPOSP2 = $D002         ;player 2 horizontal position
+HPOSP3 = $D003         ;player 3 horizontal position
+
+HPOSM0 = $D004         ;missile 0 horizontal position
+HPOSM1 = $D005         ;missile 1 horizontal position
+HPOSM2 = $D006         ;missile 2 horizontal position
+HPOSM3 = $D007         ;missile 3 horizontal position
+
+SIZEP0 = $D008         ;player 0 size
+SIZEP1 = $D009         ;player 1 size
+SIZEF2 = $D00A         ;player 2 size
+SIZEP3 = $D00B         ;player 3 size
+
+SIZEM  = $D00C         ;missile sizes
+
+GRAFP0 = $D00D         ;player 0 graphics
+GRAFP1 = $D00E         ;player 1 graphics
+GRAFP2 = $D00F         ;player 2 graphics
+GRAFP3 = $D010         ;player 3 graphics
+
+GRAFM  = $D011         ;missile graphics
+
+COLPM0 = $D012         ;player-missile 0 color/luminance
+COLPM1 = $D013         ;player-missile 1 color/luminance
+COLPM2 = $D014         ;player-missile 2 color/luminance
+COLPM3 = $D015         ;player-missile 3 color/luminance
+
+COLPF0 = $D016         ;playfield 0 color/luminance
+COLPF1 = $D017         ;playfield 1 color/luminance
+COLPF2 = $D018         ;playfield 2 color/luminance
+COLPF3 = $D019         ;playfield 3 color/luminance
+
+COLBK  = $D01A         ;background color/luminance
+
+PRIOR  = $D01B         ;priority select
+VDELAY = $D01C         ;vertical delay
+GRACTL = $D01D         ;graphic control
+HITCLR = $D01E         ;collision clear
+
+;-------------------------------------------------------------------------
+; PBI Address Equates
+;-------------------------------------------------------------------------
+
+PBI    = $D100         ;##rev2## parallel bus interface area
+
+; Read Addresses
+
+PDVI   = $D1FF         ;##rev2## parallel device IRQ status
+
+; Write Addresses
+
+PDVS   = $D1FF         ;##rev2## parallel device select
+
+; PBI RAM Address Equates
+
+PBIRAM = $D600         ;##rev2## parallel bus interface RAM area
+
+; Parallel Device Address Equates
+
+PDID1  = $D803         ;##rev2## parallel device ID 1
+PDIDV  = $D805         ;##rev2## parallel device I/O vector
+PDIRQV = $D808         ;##rev2## parallel device IRQ vector
+PDID2  = $D80B         ;##rev2## parallel device ID 2
+PDVV   = $D80D         ;##rev2## parallel device vector table
+
+;-------------------------------------------------------------------------
+; POKEY Address Equates
+;-------------------------------------------------------------------------
+
+POKEY  = $D200         ;POKEY area
+
+; Read Addresses
+
+POT0   = $D200         ;potentiometer 0
+POT1   = $D201         ;potentiometer 1
+POT2   = $D202         ;potentiometer 2
+POT3   = $D203         ;potentiometer 3
+POT4   = $D204         ;potentiometer 4
+POT5   = $D205         ;potentiometer 5
+POT6   = $D206         ;potentiometer 6
+POT7   = $D207         ;potentiometer 7
+
+ALLPOT = $D208         ;potentiometer port status
+KBCODE = $D209         ;keyboard code
+RANDOM = $D20A         ;random number generator
+SERIN  = $D20D         ;serial port input
+IRQST  = $D20E         ;IRQ interrupt status
+SKSTAT = $D20F         ;serial port and keyboard status
+
+; Write Addresses
+
+AUDF1  = $D200         ;channel 1 audio frequency
+AUDC1  = $D201         ;channel 1 audio control
+
+AUDF2  = $D202         ;channel 2 audio frequency
+AUDC2  = $D203         ;channel 2 audio control
+
+AUDF3  = $D204         ;channel 3 audio frequency
+AUDC3  = $D205         ;channel 3 audio control
+
+AUDF4  = $D206         ;channel 4 audio frequency
+AUDC4  = $D207         ;channel 4 audio control
+
+AUDCTL = $D208         ;audio control
+STIMER = $D209         ;start timers
+SKRES  = $D20A         ;reset SKSTAT status
+POTGO  = $D20B         ;start potentiometer scan sequence
+SEROUT = $D20D         ;serial port output
+IRQEN  = $D20E         ;IRQ interrupt enable
+SKCTL  = $D20F         ;serial port and keyboard control
+
+;-------------------------------------------------------------------------
+; PIA Address Equates
+;-------------------------------------------------------------------------
+
+PIA    = $D300         ;PIA area
+
+PORTA  = $D300         ;port A direction register or jacks one/two
+PORTB  = $D301         ;port B direction register or memory management
+
+PACTL  = $D302         ;port A control
+PBCTL  = $D303         ;port B control
+
+;-------------------------------------------------------------------------
+; ANTIC Address Equates
+;-------------------------------------------------------------------------
+
+ANTIC  = $D400         ;ANTIC area
+
+; Read Addresses
+
+VCOUNT = $D40B         ;vertical line counter
+PENH   = $D40C         ;light pen horizontal position
+PENV   = $D40D         ;light pen vertical position
+NMIST  = $D40F         ;NMI interrupt status
+
+; Write Addresses
+
+DMACTL = $D400         ;DMA control
+CHACTL = $D401         ;character control
+DLISTL = $D402         ;low display list address
+DLISTH = $D403         ;high display list address
+HSCROL = $D404         ;horizontal scroll
+VSCROL = $D405         ;vertical scroll
+PMBASE = $D407         ;player-missile base address
+CHBASE = $D409         ;character base address
+WSYNC  = $D40A         ;wait for HBLANK synchronization
+NMIEN  = $D40E         ;NMI enable
+NMIRES = $D40F         ;NMI iterrupt reset
+
+;-------------------------------------------------------------------------
+; Floating Point Package Address Equates
+;-------------------------------------------------------------------------
+
+AFP    = $D800         ;convert ASCII to floating point
+FASC   = $D8E6         ;convert floating point to ASCII
+IFP    = $D9AA         ;convert integer to floating point
+FPI    = $D9D2         ;convert floating point to integer
+ZFR0   = $DA44         ;zero FR0
+ZF1    = $DA46         ;zero floating point number
+FSUB   = $DA60         ;subtract floating point numbers
+FADD   = $DA66         ;add floating point numbers
+FMUL   = $DADB         ;multiply floating point numbers
+FDIV   = $DB28         ;divide floating point numbers
+PLYEVL = $DD40         ;evaluate floating point polynomial
+FLD0R  = $DD89         ;load floating point number
+FLD0P  = $DD8D         ;load floating point number
+FLD1R  = $DD98         ;load floating point number
+PLD1P  = $DD9C         ;load floating point number
+FST0R  = $DDA7         ;store floating point number
+FST0P  = $DDAB         ;store floating point number
+FMOVE  = $DDB6         ;move floating point number
+LOG    = $DECD         ;calculate floating point logarithm
+LOG10  = $DED1         ;calculate floating point base 10 logarithm
+EXP    = $DDC0         ;calculate floating point exponential
+EXP10  = $DDCC         ;calculate floating point base 10 exponential
+
+;-------------------------------------------------------------------------
+; Device Handler Vector Table Address Equates
+;-------------------------------------------------------------------------
+
+EDITRV = $E400         ;editor handler vector table
+SCRENV = $E410         ;screen handler vector table
+KEYBDV = $E420         ;keyboard handler vector table
+PRINTV = $E430         ;printer handler vector table
+CASETV = $E440         ;cassette handler vector table
+
+;-------------------------------------------------------------------------
+; Jump Vector Address Equates
+;-------------------------------------------------------------------------
+
+DISKIV = $E450         ;vector to initialize DIO
+DSKINV = $E453         ;vector to DIO
+CIOV   = $E456         ;vector to CIO
+SIOV   = $E459         ;vector to SIO
+SETVBV = $E45C         ;vector to set VBLANK parameters
+SYSVBV = $E45F         ;vector to process immediate VBLANK
+XITVBV = $E462         ;vector to process deferred VBLANK
+SIOINV = $E465         ;vector to initialize SIO
+SENDEV = $E468         ;vector to enable SEND
+INTINV = $E46B         ;vector to initialize interrupt handler
+CIOINV = $E46E         ;vector to initialize CIO
+BLKBDV = $E471         ;vector to power-up display
+WARMSV = $E474         ;vector to warmstart
+COLDSV = $E477         ;vector to coldstart
+RBLOKV = $E47A         ;vector to read cassette block
+CSOPIV = $E47D         ;vector to open cassette for input
+VCTABL = $E480         ;RAM vector initial value table
+PUPDIV = $E480         ;##rev2## vector to power-up display
+SLFTSV = $E483         ;##rev2## vector to self-test
+PHENTV = $E486         ;##rev2## vector to enter peripheral handler
+PHUNLV = $E489         ;##rev2## vector to unlink peripheral handler
+PHINIV = $E48C         ;##rev2## vector to initialize peripheral handler
+GPDVV  = $E48F         ;##rev2## generic parallel device handler vector
+
+; NOTE: OS rom self-test labels are not included in this file
+
+;-------------------------------------------------------------------------
+; Some misc. stuff from the 400/800 rev.B source
+;-------------------------------------------------------------------------
+
+; THE FOLLOWING ARE IN BASIC CARTRIDGE:
+SIN    = $BD81         ;FR0 <- SIN (FR0) DEGFLG (0=RAD,6=DEG) CARRY
+COS    = $BD73         ;FR0 <- COS (FR0) CARRY
+ATAN   = $BE43         ;FR0 <- ATAN(FR0) CARRY
+SQR    = $BEB1         ;FR0 <- ROOT(FR0) CARRY
+
+RADON  = 0             ;INDICATES RADIANS
+DEGON  = 6             ;INDICATES DEGREES
+
+ASCZER = '0'           ;ASCII ZERO
+COLON  = $3A           ;ASCII COLON 
+CR     = $9B           ;SYSTEM EOL (CARRIAGE RETURN)
+
+;-------------------------------------------------------------------------
+; 6502
+;-------------------------------------------------------------------------
+
+NMIVEC = $FFFA
+RESVEC = $FFFC
+IRQVEC = $FFFE
+
+;-------------------------------------------------------------------------
+; BASIC
+;-------------------------------------------------------------------------
+
+LOMEM  = $80           ;2-byte low memory pointer
+VNTP   = $82           ;2-byte variable name table address
+VNTD   = $84           ;2-byte variable name table end + 1
+VVTP   = $86           ;2-byte variable value table
+STMTAB = $88           ;2-byte statement table address
+STMCUR = $8A           ;2-byte current statement pointer
+STARP  = $8C           ;2-byte string and array table pointer
+RUNSTK = $8E           ;2-byte runtime stack address
+;MEMTOP        = $90           ;2-byte top of memory pointer
+STOPLN = $BA           ;2-byte stopped line number
+ERRSAVE        = $C3           ;1-byte error code
+PTABW  = $C9           ;1-byte tab width
+
+;-------------------------------------------------------------------------
+; DOS
+;-------------------------------------------------------------------------
+
+DOS    = $0700
+
+RENAME = $20           ;RENAME DISK FILE
+DELETE = $21           ;DELETE DISK FILE
+FORMAT = $21           ;FORMAT
+LOCKFL = $23           ;LOCK FILE TO READ ONLY
+UNLOCK = $24           ;UNLOCK LOCKED FILE
+POINT  = $25           ;POINT SECTOR
+NOTE   = $26           ;NOTE SECTOR
+
+; Command line table, Index values for (DOSVEC),Y -- COMTAB
+; Compatible with OS/A+, DOS XL and SpartaDOS
+
+COMTAB = 0             ;DOS entry jump vector
+ZCRNAME        = 3             ;file name crunch routine jump vector
+BUFOFF = 10            ;next parameter buffer offset
+COMFNAM        = 33            ;destination buffer for crunch routine
+LBUF   = 63            ;command line input buffer
+
+;-------------------------------------------------------------------------
+; ATASCII CHARACTER DEFS
+;-------------------------------------------------------------------------
+
+ATCLR  = $7D           ;CLEAR SCREEN CHARACTER
+ATRUB  = $7E           ;BACK SPACE (RUBOUT)
+ATTAB  = $7F           ;TAB
+ATEOL  = $9B           ;END-OF-LINE
+ATDELL = $9C           ;Delete line
+ATBEL  = $FD           ;CONSOLE BELL
+ATURW  = $1C           ;UP-ARROW
+ATDRW  = $1D           ;DOWN-ARROW
+ATLRW  = $1E           ;LEFT-ARROW
+ATRRW  = $1F           ;RIGHT-ARROW
+
+;-------------------------------------------------------------------------
+; End of atari.inc
+;-------------------------------------------------------------------------
+
diff --git a/libsrc/atari/break.s b/libsrc/atari/break.s
new file mode 100644 (file)
index 0000000..975d387
--- /dev/null
@@ -0,0 +1,106 @@
+;
+; Christian Groessler, 27-Feb-2000
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+               .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+
+       .include        "atari.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     VBREAK
+       sta     oldvec
+       lda     VBREAK+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     VBREAK
+       lda     #>brk_handler
+       sta     VBREAK+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     VBREAK
+       lda     oldvec+1
+       sta     VBREAK+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       sty     _brk_y
+       stx     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
diff --git a/libsrc/atari/cclear.s b/libsrc/atari/cclear.s
new file mode 100644 (file)
index 0000000..f4ee4e9
--- /dev/null
@@ -0,0 +1,34 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+       .export         _cclearxy, _cclear
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_cclearxy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+               pla                     ; Restore the length and run into _cclear
+
+_cclear:
+               cmp     #0              ; Is the length zero?
+               beq     L9              ; Jump if done
+       sta     tmp1                                 
+.ifdef DIRECT_SCREEN
+L1:            lda     #0              ; Blank - screen code
+.else
+L1:            lda     #$20            ; Blank
+.endif
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/atari/cgetc.s b/libsrc/atari/cgetc.s
new file mode 100644 (file)
index 0000000..f64d97b
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; get a kbd char.
+;
+; char cgetc(void)
+;
+
+        .include "atari.inc"
+        .export _cgetc
+        
+_cgetc:
+        lda     KEYBDV+5
+        pha
+        lda     KEYBDV+4
+        pha
+        rts
+       ldx     #0
+       rts
diff --git a/libsrc/atari/chline.s b/libsrc/atari/chline.s
new file mode 100644 (file)
index 0000000..6b5e6a1
--- /dev/null
@@ -0,0 +1,34 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+       .export         _chlinexy, _chline
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_chlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length
+
+_chline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+.ifdef DIRECT_SCREEN
+L1:            lda     #$12+64         ; Horizontal line, screen code
+.else
+L1:            lda     #$12            ; Horizontal line
+.endif
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/atari/close.s b/libsrc/atari/close.s
new file mode 100644 (file)
index 0000000..c7995e9
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; Christian Groessler, May-2000
+;
+; int close(int fd);
+;
+
+       .include "atari.inc"
+       .export _close
+       .import __do_oserror,popax,__oserror
+       .import fdtoiocb_down,__inviocb
+
+.proc  _close
+       jsr     popax
+       jsr     fdtoiocb_down           ; get iocb index into X and decr. usage count
+       bmi     inverr
+       bne     ok                      ; not last one -> don't close yet
+;      asl     a
+;      asl     a
+;      asl     a
+;      asl     a
+;      tax
+       lda     #CLOSE
+       sta     ICCOM,x
+       jsr     CIOV
+       bpl     ok
+       jmp     __do_oserror
+
+ok:    ldx     #0
+       stx     __oserror               ; clear system specific error code
+       txa
+       rts
+
+inverr:        jmp     __inviocb
+
+.endproc
+
diff --git a/libsrc/atari/clrscr.s b/libsrc/atari/clrscr.s
new file mode 100644 (file)
index 0000000..ac8f896
--- /dev/null
@@ -0,0 +1,47 @@
+;
+; Christian Groessler, Apr-2000
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+
+       .include        "atari.inc"
+
+.ifdef DIRECT_SCREEN
+
+       .importzp       ptr1
+
+_clrscr:lda    SAVMSC          ; screen memory
+       sta     ptr1
+       lda     SAVMSC+1
+       clc
+       adc     #>(40*24)
+       sta     ptr1+1
+       lda     #0              ; screen code of space char
+       ldy     #<(40*24)       ; 40x24: size of default atari screen
+       ldx     #>(40*24)
+_clr1: sta     (ptr1),y
+       dey
+       bne     _clr1
+       sta     (ptr1),y
+       dex
+       bmi     done
+       ldy     ptr1+1
+       dey
+       sty     ptr1+1
+       ldy     #255
+       jmp     _clr1
+
+done:  sta     COLCRS
+       sta     ROWCRS
+       rts
+
+.else
+
+       .import         putchar
+_clrscr:
+       lda     #ATCLR
+       jmp     putchar
+
+.endif
diff --git a/libsrc/atari/color.s b/libsrc/atari/color.s
new file mode 100644 (file)
index 0000000..ea398ed
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+       .export         _textcolor, _bgcolor, _bordercolor
+
+       .include        "atari.inc"
+
+_textcolor:
+       ldx     COLOR1  ; get old value
+       sta     COLOR1  ; set new value
+       txa
+       rts
+
+
+_bgcolor:
+       ldx     COLOR2  ; get old value
+       sta     COLOR2  ; set new value
+       txa
+       rts
+
+
+_bordercolor:
+       ldx     COLOR4  ; get old value
+       sta     COLOR4  ; set new value
+       txa
+       rts
+
diff --git a/libsrc/atari/conio.s b/libsrc/atari/conio.s
new file mode 100644 (file)
index 0000000..651d0e5
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Christian Groessler
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio
+       .import         xsize, ysize, plot
+
+       .include        "atari.inc"
+
+.code
+
+initconio:
+       ldx     #40
+       ldy     #24
+       stx     xsize
+       sty     ysize
+       rts
+
diff --git a/libsrc/atari/cputc.s b/libsrc/atari/cputc.s
new file mode 100644 (file)
index 0000000..95bc775
--- /dev/null
@@ -0,0 +1,190 @@
+;
+; Mark Keates, Christian Groessler
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc
+       .export         plot, cputdirect, putchar
+       .import         popa, _gotoxy
+
+       .include        "atari.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+.ifdef DIRECT_SCREEN
+
+       .importzp tmp4,ptr4
+
+_cputc:
+       cmp     #$0D            ; CR
+       bne     L4
+       lda     #0
+       sta     COLCRS
+       beq     plot            ; return
+       
+L4:    cmp     #$0A            ; LF
+       beq     newline
+       cmp     #ATEOL          ; Atari-EOL?
+       beq     newline
+
+       tay
+       rol     a
+       rol     a
+       rol     a
+       rol     a
+       and     #3
+       tax
+       tya
+       and     #$9f
+       ora     ataint,x
+
+cputdirect:                    ; accepts screen code
+       jsr     putchar
+       
+; advance cursor
+       inc     COLCRS
+       lda     COLCRS
+       cmp     #40
+       bcc     plot
+       lda     #0
+       sta     COLCRS
+
+       .export newline
+newline:
+       inc     ROWCRS
+       lda     ROWCRS
+       cmp     #24
+       bne     plot
+       lda     #0
+       sta     ROWCRS
+plot:  ldy     COLCRS
+       ldx     ROWCRS
+       rts
+
+putchar:
+       pha                     ; save char
+       lda     #0
+       sta     tmp4
+       lda     ROWCRS
+       asl     a
+       rol     tmp4
+       asl     a
+       rol     tmp4            ; row * 4
+       adc     ROWCRS
+       bcc     L1
+       inc     tmp4            ; row * 5
+L1:    asl     a
+       rol     tmp4            ; row * 10
+       asl     a
+       rol     tmp4
+       asl     a
+       rol     tmp4            ; row * 40
+L3:    clc
+       adc     SAVMSC          ; add start of screen memory
+       sta     ptr4
+       lda     tmp4
+       adc     SAVMSC+1
+       sta     ptr4+1
+       pla                     ; get char again
+       ora     INVFLG
+       ldy     COLCRS
+       sta     (ptr4),y
+       rts
+
+       .rodata
+ataint:        .byte   64,0,32,96
+
+;****************************************************************
+.else  ;***** above DIRECT_SCREEN, below thru OS ***************
+;****************************************************************
+
+       .import         __do_oserror,cursor,__oserror
+
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     COLCRS
+               beq     plot            ; Recalculate pointers
+
+; don't know whether this is needed. the compiler generates
+; already ATEOL chars for \n
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       lda     #ATEOL
+
+; Printable char of some sort
+
+L2:
+cputdirect:
+       pha
+       and     #$7f
+       cmp     #32             ; control char?
+       bcs     goon
+       lda     #$1b
+       jsr     putchar
+goon:  pla
+       jsr     putchar         ; Write the character to the screen
+
+plot:  ldy     COLCRS
+       ldx     ROWCRS
+       rts
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+.if 0
+       tax
+       lda     #>(retr-1)
+       pha
+       lda     #<(retr-1)
+       pha
+       lda     ICPTH
+       pha
+       lda     ICPTL
+       pha
+       lda     #0
+       sta     LOGCOL
+       txa
+       rts
+retr:
+.endif
+.if 1
+       pha
+       ldx     #0              ; iocb #0 (screen editor)
+       txa
+       sta     ICBLL,x
+       sta     ICBLH,x
+       sta     ICBAL,x
+       sta     ICBAH,x
+       lda     #PUTCHR
+       sta     ICCOM,x
+       lda     cursor
+       beq     putc7
+       lda     #0
+       beq     putc8
+putc7: lda     #1
+putc8: sta     CRSINH
+       pla
+       jsr     CIOV
+       bpl     putc9
+       jmp     __do_oserror    ; update system specific error code
+
+putc9: tya
+       ldx     #0
+       stx     __oserror
+       ldy     COLCRS
+.endif
+       rts
+
+.endif ; not defined DIRECT_SCREEN
diff --git a/libsrc/atari/crt0.s b/libsrc/atari/crt0.s
new file mode 100644 (file)
index 0000000..39235e0
--- /dev/null
@@ -0,0 +1,191 @@
+;
+; Startup code for cc65 (ATARI version)
+;
+; Contributing authors:
+;      Mark Keates
+;      Freddy Offenga
+;      Christian Groessler
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+       .import         getargs, argc, argv
+       .import         __hinit, initconio, zerobss, pushax, doatexit
+       .import         _main,__filetab
+       .import         __CODE_LOAD__, __BSS_LOAD__
+
+       .include        "atari.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       fntemp, regbank, zpspace
+
+sp     = $D2           ; (2bytes) stack pointer
+sreg   = $D4           ; (2bytes) secondary register/high 16 bit for longs
+regsave = $D6          ; (4bytes) slot to save/restore (E)AX into
+ptr1   = $DA           ; (2bytes)
+ptr2   = $DC           ; (2bytes)
+ptr3   = $DE           ; (2bytes)
+ptr4   = $E0           ; (2bytes)
+tmp1   = $E2           ; (1byte)
+tmp2   = $E3           ; (1byte)
+tmp3   = $E4           ; (1byte)
+tmp4   = $E5           ; (1byte)
+fntemp = $E6           ; (2bytes) pointer to file name
+regbank = $E8          ; (6bytes) 6 byte register bank
+zpspace = $EE - sp     ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; EXE header
+
+       .segment "EXEHDR"
+       .word   $FFFF
+       .word   __CODE_LOAD__
+       .word   __BSS_LOAD__ - 1
+       .code
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       rts     ; fix for SpartaDOS / OS/A+
+               ; they first call the entry point from AUTOSTRT and
+               ; then the load addess (this rts here).
+               ; We point AUTOSTRT directly after the rts.
+
+; Real entry point:
+
+; Save the zero page locations we need
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y
+       dey
+       bpl     L1
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; setup the stack
+
+       tsx
+       stx     spsave
+
+; report memory usage and initialize stack pointer
+
+       lda     APPMHI
+       sta     appmsav
+       lda     APPMHI+1
+       sta     appmsav+1
+       
+       lda     #<$8000
+       sta     sp
+       sta     APPMHI
+       lda     #>$8000
+       sta     sp+1            ; Set argument stack ptr
+       sta     APPMHI+1
+       
+; set left margin to 0
+
+       lda     LMARGN
+       sta     old_lmargin
+       lda     #0
+       sta     LMARGN
+
+; set keyb to upper/lowercase mode
+
+       ldx     SHFLOK
+       stx     old_shflok
+       sta     SHFLOK
+       
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       jsr     initconio
+
+       lda     #$FF
+       sta     CH
+
+; ugly hack for now: set stdio stream handles
+; all to iocb #0
+; until we know where to go with fd<->iocb relation
+; this won't stay here!
+
+       lda     #0
+       sta     __filetab + 2
+       sta     __filetab + 4
+
+; Pass command line if present
+
+       jsr     getargs
+
+       lda     argc
+       ldx     argc+1
+       jsr     pushax          ; argc
+       lda     #<argv
+       ldx     #>argv
+       jsr     pushax          ; argv
+
+       ldy     #4              ; Argument size
+       jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr     doatexit        ; call exit functions
+
+       ldx     spsave
+       txs                     ; Restore stack pointer
+
+; restore left margin
+
+       lda     old_lmargin
+       sta     LMARGN
+
+; restore kb mode
+
+       lda     old_shflok
+       sta     SHFLOK
+
+; restore APPMHI
+       
+       lda     appmsav
+       sta     APPMHI
+       lda     appmsav+1
+       sta     APPMHI+1
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+       bpl     L2
+
+; Back to DOS
+
+       rts
+
+.data
+
+zpsave:        .res    zpspace
+       
+.bss
+
+spsave:                .res    1
+appmsav:       .res    1
+old_shflok:    .res    1
+old_lmargin:   .res    1
+
+       .segment "AUTOSTRT"
+       .word   $02E0
+       .word   $02E1
+       .word   __CODE_LOAD__ + 1
diff --git a/libsrc/atari/ctype.s b/libsrc/atari/ctype.s
new file mode 100644 (file)
index 0000000..c0233b2
--- /dev/null
@@ -0,0 +1,309 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to an upper case char to make it lower case
+; char (example: for ASCII, this must be $E0).
+
+
+       .export         __cdiff
+
+__cdiff:
+       .byte   $E0
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+;   * It is fast. If it were'nt for the slow parameter passing of cc65, one
+;     could even define macros for the isxxx functions (this is usually
+;     done on other platforms).
+;
+;   * It is highly portable. The only unportable part is the table itself,
+;     all real code goes into the common library.
+;
+;   * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+;   0 - Lower case char
+;   1 - Upper case char
+;   2 - Numeric digit
+;   3 - Hex digit (both, lower and upper)
+;   4 - Control character
+;   5 - The space character itself
+;   6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+;   7 - Space or tab character
+
+       .export         __ctype
+
+__ctype:
+               .byte   $10     ;   0/00 ___ctrl_@___
+               .byte   $10     ;   1/01 ___ctrl_A___
+               .byte   $10     ;   2/02 ___ctrl_B___
+               .byte   $10     ;   3/03 ___ctrl_C___
+               .byte   $10     ;   4/04 ___ctrl_D___
+               .byte   $10     ;   5/05 ___ctrl_E___
+               .byte   $10     ;   6/06 ___ctrl_F___
+               .byte   $10     ;   7/07 ___ctrl_G___
+               .byte   $10     ;   8/08 ___ctrl_H___
+               .byte   $D0     ;   9/09 ___ctrl_I___
+               .byte   $50     ;  10/0a ___ctrl_J___
+               .byte   $50     ;  11/0b ___ctrl_K___
+               .byte   $50     ;  12/0c ___ctrl_L___
+               .byte   $50     ;  13/0d ___ctrl_M___
+               .byte   $10     ;  14/0e ___ctrl_N___
+               .byte   $10     ;  15/0f ___ctrl_O___
+               .byte   $10     ;  16/10 ___ctrl_P___
+               .byte   $10     ;  17/11 ___ctrl_Q___
+               .byte   $10     ;  18/12 ___ctrl_R___
+               .byte   $10     ;  19/13 ___ctrl_S___
+               .byte   $10     ;  20/14 ___ctrl_T___
+               .byte   $10     ;  21/15 ___ctrl_U___
+               .byte   $10     ;  22/16 ___ctrl_V___
+               .byte   $10     ;  23/17 ___ctrl_W___
+               .byte   $10     ;  24/18 ___ctrl_X___
+               .byte   $10     ;  25/19 ___ctrl_Y___
+               .byte   $10     ;  26/1a ___ctrl_Z___
+               .byte   $10     ;  27/1b ___ctrl_[___
+               .byte   $10     ;  28/1c ___ctrl_\___
+               .byte   $10     ;  29/1d ___ctrl_]___
+               .byte   $10     ;  30/1e ___ctrl_^___
+               .byte   $10     ;  31/1f ___ctrl_____
+               .byte   $A0     ;  32/20 ___SPACE___
+       .byte   $00     ;  33/21 _____!_____
+       .byte   $00     ;  34/22 _____"_____
+       .byte   $00     ;  35/23 _____#_____
+       .byte   $00     ;  36/24 _____$_____
+       .byte   $00     ;  37/25 _____%_____
+       .byte   $00     ;  38/26 _____&_____
+       .byte   $00     ;  39/27 _____'_____
+       .byte   $00     ;  40/28 _____(_____
+       .byte   $00     ;  41/29 _____)_____
+       .byte   $00     ;  42/2a _____*_____
+       .byte   $00     ;  43/2b _____+_____
+       .byte   $00     ;  44/2c _____,_____
+       .byte   $00     ;  45/2d _____-_____
+       .byte   $00     ;  46/2e _____._____
+       .byte   $00     ;  47/2f _____/_____
+       .byte   $0C     ;  48/30 _____0_____
+       .byte   $0C     ;  49/31 _____1_____
+       .byte   $0C     ;  50/32 _____2_____
+       .byte   $0C     ;  51/33 _____3_____
+       .byte   $0C     ;  52/34 _____4_____
+       .byte   $0C     ;  53/35 _____5_____
+       .byte   $0C     ;  54/36 _____6_____
+       .byte   $0C     ;  55/37 _____7_____
+       .byte   $0C     ;  56/38 _____8_____
+       .byte   $0C     ;  57/39 _____9_____
+       .byte   $00     ;  58/3a _____:_____
+       .byte   $00     ;  59/3b _____;_____
+       .byte   $00     ;  60/3c _____<_____
+       .byte   $00     ;  61/3d _____=_____
+       .byte   $00     ;  62/3e _____>_____
+       .byte   $00     ;  63/3f _____?_____
+
+       .byte   $00     ;  64/40 _____@_____
+               .byte   $0A     ;  65/41 _____A_____
+               .byte   $0A     ;  66/42 _____B_____
+               .byte   $0A     ;  67/43 _____C_____
+               .byte   $0A     ;  68/44 _____D_____
+               .byte   $0A     ;  69/45 _____E_____
+               .byte   $0A     ;  70/46 _____F_____
+               .byte   $02     ;  71/47 _____G_____
+               .byte   $02     ;  72/48 _____H_____
+               .byte   $02     ;  73/49 _____I_____
+               .byte   $02     ;  74/4a _____J_____
+               .byte   $02     ;  75/4b _____K_____
+               .byte   $02     ;  76/4c _____L_____
+               .byte   $02     ;  77/4d _____M_____
+               .byte   $02     ;  78/4e _____N_____
+               .byte   $02     ;  79/4f _____O_____
+               .byte   $02     ;  80/50 _____P_____
+               .byte   $02     ;  81/51 _____Q_____
+               .byte   $02     ;  82/52 _____R_____
+               .byte   $02     ;  83/53 _____S_____
+               .byte   $02     ;  84/54 _____T_____
+               .byte   $02     ;  85/55 _____U_____
+               .byte   $02     ;  86/56 _____V_____
+               .byte   $02     ;  87/57 _____W_____
+               .byte   $02     ;  88/58 _____X_____
+               .byte   $02     ;  89/59 _____Y_____
+               .byte   $02     ;  90/5a _____Z_____
+       .byte   $00     ;  91/5b _____[_____
+       .byte   $00     ;  92/5c _____\_____
+       .byte   $00     ;  93/5d _____]_____
+       .byte   $00     ;  94/5e _____^_____
+       .byte   $00     ;  95/5f _UNDERLINE_
+       .byte   $00     ;  96/60 ___grave___
+               .byte   $09     ;  97/61 _____a_____
+               .byte   $09     ;  98/62 _____b_____
+               .byte   $09     ;  99/63 _____c_____
+               .byte   $09     ; 100/64 _____d_____
+               .byte   $09     ; 101/65 _____e_____
+               .byte   $09     ; 102/66 _____f_____
+               .byte   $01     ; 103/67 _____g_____
+               .byte   $01     ; 104/68 _____h_____
+               .byte   $01     ; 105/69 _____i_____
+               .byte   $01     ; 106/6a _____j_____
+               .byte   $01     ; 107/6b _____k_____
+               .byte   $01     ; 108/6c _____l_____
+               .byte   $01     ; 109/6d _____m_____
+               .byte   $01     ; 110/6e _____n_____
+               .byte   $01     ; 111/6f _____o_____
+               .byte   $01     ; 112/70 _____p_____
+               .byte   $01     ; 113/71 _____q_____
+               .byte   $01     ; 114/72 _____r_____
+               .byte   $01     ; 115/73 _____s_____
+               .byte   $01     ; 116/74 _____t_____
+               .byte   $01     ; 117/75 _____u_____
+               .byte   $01     ; 118/76 _____v_____
+               .byte   $01     ; 119/77 _____w_____
+               .byte   $01     ; 120/78 _____x_____
+               .byte   $01     ; 121/79 _____y_____
+               .byte   $01     ; 122/7a _____z_____
+               .byte   $00     ; 123/7b _____{_____
+               .byte   $00     ; 124/7c _____|_____
+               .byte   $00     ; 125/7d _____}_____
+               .byte   $00     ; 126/7e _____~_____
+               .byte   $40     ; 127/7f ____DEL____
+
+               .byte   $00     ; 128/80 ___________
+               .byte   $00     ; 129/81 ___________
+               .byte   $00     ; 130/82 ___________
+               .byte   $00     ; 131/83 ___________
+               .byte   $00     ; 132/84 ___________
+               .byte   $00     ; 133/85 ___________
+               .byte   $00     ; 134/86 ___________
+               .byte   $00     ; 135/87 ___________
+               .byte   $00     ; 136/88 ___________
+               .byte   $00     ; 137/89 ___________
+               .byte   $00     ; 138/8a ___________
+               .byte   $00     ; 139/8b ___________
+               .byte   $00     ; 140/8c ___________
+               .byte   $00     ; 141/8d ___________
+               .byte   $00     ; 142/8e ___________
+               .byte   $00     ; 143/8f ___________
+               .byte   $00     ; 144/90 ___________
+               .byte   $00     ; 145/91 ___________
+               .byte   $00     ; 146/92 ___________
+               .byte   $10     ; 147/93 ___________
+               .byte   $00     ; 148/94 ___________
+               .byte   $00     ; 149/95 ___________
+               .byte   $00     ; 150/96 ___________
+               .byte   $00     ; 151/97 ___________
+               .byte   $00     ; 152/98 ___________
+               .byte   $00     ; 153/99 ___________
+               .byte   $00     ; 154/9a ___________
+               .byte   $00     ; 155/9b ___________
+               .byte   $00     ; 156/9c ___________
+               .byte   $00     ; 157/9d ___________
+               .byte   $00     ; 158/9e ___________
+               .byte   $00     ; 159/9f ___________
+
+               .byte   $00     ; 160/a0 ___________
+               .byte   $00     ; 161/a1 ___________
+               .byte   $00     ; 162/a2 ___________
+               .byte   $00     ; 163/a3 ___________
+               .byte   $00     ; 164/a4 ___________
+               .byte   $00     ; 165/a5 ___________
+               .byte   $00     ; 166/a6 ___________
+               .byte   $00     ; 167/a7 ___________
+               .byte   $00     ; 168/a8 ___________
+               .byte   $00     ; 169/a9 ___________
+               .byte   $00     ; 170/aa ___________
+               .byte   $00     ; 171/ab ___________
+               .byte   $00     ; 172/ac ___________
+               .byte   $00     ; 173/ad ___________
+               .byte   $00     ; 174/ae ___________
+               .byte   $00     ; 175/af ___________
+               .byte   $00     ; 176/b0 ___________
+               .byte   $00     ; 177/b1 ___________
+               .byte   $00     ; 178/b2 ___________
+               .byte   $00     ; 179/b3 ___________
+               .byte   $00     ; 180/b4 ___________
+               .byte   $00     ; 181/b5 ___________
+               .byte   $00     ; 182/b6 ___________
+               .byte   $00     ; 183/b7 ___________
+               .byte   $00     ; 184/b8 ___________
+               .byte   $00     ; 185/b9 ___________
+               .byte   $00     ; 186/ba ___________
+               .byte   $00     ; 187/bb ___________
+               .byte   $00     ; 188/bc ___________
+               .byte   $00     ; 189/bd ___________
+               .byte   $00     ; 190/be ___________
+               .byte   $00     ; 191/bf ___________
+
+               .byte   $02     ; 192/c0 ___________
+               .byte   $02     ; 193/c1 ___________
+               .byte   $02     ; 194/c2 ___________
+               .byte   $02     ; 195/c3 ___________
+               .byte   $02     ; 196/c4 ___________
+               .byte   $02     ; 197/c5 ___________
+               .byte   $02     ; 198/c6 ___________
+               .byte   $02     ; 199/c7 ___________
+               .byte   $02     ; 200/c8 ___________
+               .byte   $02     ; 201/c9 ___________
+               .byte   $02     ; 202/ca ___________
+               .byte   $02     ; 203/cb ___________
+               .byte   $02     ; 204/cc ___________
+               .byte   $02     ; 205/cd ___________
+               .byte   $02     ; 206/ce ___________
+               .byte   $02     ; 207/cf ___________
+               .byte   $02     ; 208/d0 ___________
+               .byte   $02     ; 209/d1 ___________
+               .byte   $02     ; 210/d2 ___________
+               .byte   $02     ; 211/d3 ___________
+               .byte   $02     ; 212/d4 ___________
+               .byte   $02     ; 213/d5 ___________
+               .byte   $02     ; 214/d6 ___________
+               .byte   $02     ; 215/d7 ___________
+               .byte   $02     ; 216/d8 ___________
+               .byte   $02     ; 217/d9 ___________
+               .byte   $02     ; 218/da ___________
+               .byte   $02     ; 219/db ___________
+               .byte   $02     ; 220/dc ___________
+               .byte   $02     ; 221/dd ___________
+               .byte   $02     ; 222/de ___________
+               .byte   $00     ; 223/df ___________
+               .byte   $01     ; 224/e0 ___________
+               .byte   $01     ; 225/e1 ___________
+               .byte   $01     ; 226/e2 ___________
+               .byte   $01     ; 227/e3 ___________
+               .byte   $01     ; 228/e4 ___________
+               .byte   $01     ; 229/e5 ___________
+               .byte   $01     ; 230/e6 ___________
+               .byte   $01     ; 231/e7 ___________
+               .byte   $01     ; 232/e8 ___________
+               .byte   $01     ; 233/e9 ___________
+               .byte   $01     ; 234/ea ___________
+               .byte   $01     ; 235/eb ___________
+               .byte   $01     ; 236/ec ___________
+               .byte   $01     ; 237/ed ___________
+               .byte   $01     ; 238/ee ___________
+               .byte   $01     ; 239/ef ___________
+               .byte   $01     ; 240/f0 ___________
+               .byte   $01     ; 241/f1 ___________
+               .byte   $01     ; 242/f2 ___________
+               .byte   $01     ; 243/f3 ___________
+               .byte   $01     ; 244/f4 ___________
+               .byte   $01     ; 245/f5 ___________
+               .byte   $01     ; 246/f6 ___________
+               .byte   $01     ; 247/f7 ___________
+               .byte   $01     ; 248/f8 ___________
+               .byte   $01     ; 249/f9 ___________
+               .byte   $01     ; 250/fa ___________
+               .byte   $01     ; 251/fb ___________
+               .byte   $01     ; 252/fc ___________
+               .byte   $01     ; 253/fd ___________
+               .byte   $01     ; 254/fe ___________
+               .byte   $00     ; 255/ff ___________
+
diff --git a/libsrc/atari/cvline.s b/libsrc/atari/cvline.s
new file mode 100644 (file)
index 0000000..4ff351e
--- /dev/null
@@ -0,0 +1,35 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+       .include "atari.inc"
+       
+       .export         _cvlinexy, _cvline
+       .import         popa, _gotoxy, putchar, newline
+       .importzp       tmp1
+
+_cvlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length and run into _cvline
+
+_cvline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+L1:    lda     COLCRS
+       pha
+       lda     #$7C            ; Vertical bar
+       jsr     putchar         ; Write, no cursor advance
+       pla
+       sta     COLCRS
+       inc     ROWCRS
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
diff --git a/libsrc/atari/fdtable.s b/libsrc/atari/fdtable.s
new file mode 100644 (file)
index 0000000..547681e
--- /dev/null
@@ -0,0 +1,103 @@
+;
+; Christian Groessler, May-2000
+;
+; fd indirection table & helper functions
+;
+
+       .include "atari.inc"
+       .export fdtoiocb
+       .export fdtoiocb_down
+       .export fd_table
+
+       .data
+
+fd_table:
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+       .byte   0,$ff,0,0
+
+MAX_FD_VAL     =       (* - fd_table) / 4
+
+ft_usa  = 0    ; usage counter
+ft_iocb        = 1     ; iocb index (0,$10,$20,etc.), $ff for empty entry
+ft_dev  = 2    ; device of open iocb
+ft_flag = 3    ; flags
+
+       .code
+
+; gets fd in ax, decrements usage counter
+; return iocb index in X
+; return N bit set for invalid fd
+; return Z bit set if last user
+; all registers destroyed
+.proc  fdtoiocb_down
+
+       cpx     #0
+       bne     inval
+       cmp     #MAX_FD_VAL
+       bcs     inval
+       asl     a                       ; create index into fd table
+       asl     a
+       tax
+       lda     #$ff
+       cmp     fd_table+ft_iocb,x      ; entry in use?
+       beq     inval                   ; no, return error
+       lda     fd_table+ft_usa,x       ; get usage counter
+       beq     ok_notlast              ; 0?
+       sec
+       sbc     #1                      ; decr usage counter
+       sta     fd_table+ft_usa,x
+retiocb:php
+       txa
+       tay
+       lda     fd_table+ft_iocb,x      ; get iocb
+       tax
+       plp
+       bne     cont
+       php
+       lda     #$ff
+       sta     fd_table+ft_iocb,y      ; clear table entry
+       plp
+cont:  rts
+
+ok_notlast:
+       lda     #1                      ; clears Z
+       jmp     retiocb
+
+.endproc
+
+inval: ldx     #$ff                    ; sets N
+       rts
+
+
+; gets fd in ax
+; return iocb index in X
+; return N bit set for invalid fd
+; all registers destroyed
+.proc  fdtoiocb
+
+       cpx     #0
+       bne     inval
+       cmp     #MAX_FD_VAL
+       bcs     inval
+       asl     a                       ; create index into fd table
+       asl     a
+       tax
+       lda     #$ff
+       cmp     fd_table+ft_iocb,x      ; entry in use?
+       beq     inval                   ; no, return error
+       lda     fd_table+ft_usa,x       ; get usage counter
+       beq     inval                   ; 0? should not happen
+       lda     fd_table+ft_iocb,x      ; get iocb
+       rts
+
+.endproc
diff --git a/libsrc/atari/getargs.s b/libsrc/atari/getargs.s
new file mode 100644 (file)
index 0000000..04cf25e
--- /dev/null
@@ -0,0 +1,220 @@
+; get arguments from command line (when DOS supports it)
+; and supply function to get default device: char *getdefdev(void);
+
+; Freddy Offenga, 4/21/2000
+
+; SpartaDOS:
+; the ZCRNAME routine is only used to get the default drive because
+; ZCRNAME has two disadvantages:
+; 1. It will convert D: into D1: instead of Dn: (n = default drive)
+; 2. It will give a 'no arguments' status if it detects something
+;    like Dn: (without filename).
+
+; OS/A+ DOS:
+; ZCRNAME is slightly different from SpartaDOS. It will convert D:
+; into Dn: where n is the default drive.
+
+MAXARGS        = 16            ; max. amount of arguments in arg. table
+CL_SIZE = 64           ; command line buffer size
+SPACE  = 32            ; SPACE char.
+
+        .include "atari.inc"
+       .export getargs, argc, argv
+       .export _getdefdev              ; get default device (e.g. "D1:")
+       .importzp ptr1
+
+; Get command line
+
+getargs:
+       lda     #0
+       sta     argc
+       sta     argc+1
+       sta     argv
+       sta     argv+1
+
+       jsr     detect
+       bcs     argdos          ; carry set = DOS supports arguments
+       rts
+; Move SpartaDOS command line to our own buffer
+
+argdos:        lda     DOSVEC
+       clc
+       adc     #<LBUF
+       sta     ptr1
+       lda     DOSVEC+1
+       adc     #>LBUF
+       sta     ptr1+1
+
+       ldy     #0
+cpcl:  lda     (ptr1),y
+       sta     ourcl,y
+       iny
+       cmp     #ATEOL
+       beq     movdon
+       cpy     #CL_SIZE
+       bne     cpcl
+
+movdon:        lda     #0
+       sta     ourcl,y         ; null terminate behind ATEOL
+
+; Get default device (LBUF will be destroyed!!)
+
+       ldy     #BUFOFF
+       lda     #0
+       sta     (DOSVEC),y      ; reset buffer offset
+
+; Store dummy argument
+
+       ldy     #LBUF
+       lda     dumpar1
+       sta     (DOSVEC),y
+       iny
+       lda     dumpar2
+       sta     (DOSVEC),y
+
+; One extra store to avoid the buggy sequence from OS/A+ DOS:
+; <D><RETURN><:> => drive number = <RETURN>
+
+       iny
+       sta     (DOSVEC),y
+
+; Create crunch vector
+
+       ldy     #ZCRNAME+1
+       lda     (DOSVEC),y
+       sta     crvec+1
+       iny
+       lda     (DOSVEC),y
+       sta     crvec+2
+
+crvec: jsr     $FFFF           ; will be set to crunch vector
+
+; Get default device
+
+       ldy     #COMFNAM        ;  COMFNAM is always "Dn:"
+       lda     (DOSVEC),y
+       sta     defdev
+       iny
+       lda     (DOSVEC),y
+       sta     defdev+1
+
+; Turn command line into argv table
+
+       ldy     #0
+eatspc:        lda     ourcl,y         ; eat spaces
+       cmp     #ATEOL
+       beq     finargs
+       cmp     #SPACE
+       bne     rpar            ; begin of argument found
+       iny
+       cpy     #CL_SIZE
+       bne     eatspc
+       beq     finargs         ; only spaces is no argument
+
+; Store argument vector
+
+rpar:  lda     argc            ; low-byte
+       asl
+       tax                     ; table index
+       tya                     ; ourcl index
+       clc
+       adc     #<ourcl
+       sta     argv,x
+       lda     #>ourcl
+       adc     #0
+       sta     argv+1,x
+       ldx     argc
+       inx
+       stx     argc
+       cpx     #MAXARGS
+       beq     finargs
+
+; Skip this arg.
+
+skiparg:
+       ldx     ourcl,y
+       cpx     #ATEOL          ; end of line?
+       beq     eopar
+       cpx     #SPACE
+       beq     eopar
+       iny
+       cpy     #CL_SIZE
+       bne     skiparg
+
+; End of arg. -> place 0
+
+eopar:
+       lda     #0
+       sta     ourcl,y
+       iny                     ; y behind arg.
+       cpx     #ATEOL          ; was it the last arg?
+       bne     eatspc
+
+; Finish args
+
+finargs:
+       lda     argc
+       asl
+       tax
+       lda     #0
+       sta     argv,x
+       sta     argv+1,x
+       rts
+
+; DOS type detection
+
+detect:
+       lda     DOS
+       cmp     #$53            ; "S" (SpartaDOS)
+       beq     spdos
+
+       ldy     #COMTAB
+       lda     #$4C
+       cmp     (DOSVEC),y
+       bne     nordos
+
+       ldy     #ZCRNAME
+       cmp     (DOSVEC),y
+       bne     nordos
+
+       ldy     #6              ; OS/A+ has a jmp here
+       cmp     (DOSVEC),y
+       beq     nordos
+
+spdos: sec                     ; SpartaDOS, OS/A+ or DOS XL
+       rts
+
+nordos:        clc                     ; normal DOS (no args) detected
+       rts
+
+; Get default device (set by getargs routine)
+
+_getdefdev:
+       lda     #<defdev
+       ldx     #>defdev
+       rts
+
+       .data
+
+; Dummy argument to get default device
+
+dumpar1:
+       .byte   "X"
+dumpar2:
+       .byte   ATEOL
+
+; Buffer for command line / argv strings
+
+ourcl: .res    CL_SIZE
+       .byte   ATEOL
+
+; Default device
+
+defdev:
+       .byte   "D1:", 0
+
+       .bss
+
+argc:  .res    2
+argv:  .res    (1 + MAXARGS) * 2
diff --git a/libsrc/atari/gotox.s b/libsrc/atari/gotox.s
new file mode 100644 (file)
index 0000000..3b3efe0
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Christian Groessler, 19-Feb-2000
+;
+; void gotox (unsigned char x);
+;
+
+       .include        "atari.inc"
+       .export         _gotox
+
+_gotox:
+       sta     COLCRS          ; Set X
+       lda     #0
+       sta     COLCRS+1
+       rts
diff --git a/libsrc/atari/gotoxy.s b/libsrc/atari/gotoxy.s
new file mode 100644 (file)
index 0000000..6716298
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+
+       .include "atari.inc"
+
+       .export         _gotoxy
+       .import         popa
+
+_gotoxy:                       ; Set the cursor position
+       sta     ROWCRS          ; Set Y
+       jsr     popa            ; Get X
+       sta     COLCRS          ; Set X
+       lda     #0
+       sta     COLCRS+1        ;
+       rts             
diff --git a/libsrc/atari/gotoy.s b/libsrc/atari/gotoy.s
new file mode 100644 (file)
index 0000000..73593af
--- /dev/null
@@ -0,0 +1,12 @@
+;
+; Christian Groessler, 19-Feb-2000
+;
+; void gotoy (unsigned char y);
+;
+
+       .include        "atari.inc"
+       .export         _gotoy
+
+_gotoy:
+       sta     ROWCRS          ; Set Y
+       rts
diff --git a/libsrc/atari/kbhit.s b/libsrc/atari/kbhit.s
new file mode 100644 (file)
index 0000000..25418c1
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+
+       .include        "atari.inc"
+
+_kbhit:
+       lda     CH      ; Get number of characters
+       cmp     #$FF
+       bne     L1
+       jmp     return1
+L1:    jmp     return0
+
+
+
+
diff --git a/libsrc/atari/open.s b/libsrc/atari/open.s
new file mode 100644 (file)
index 0000000..93519a6
--- /dev/null
@@ -0,0 +1,208 @@
+;
+; Christian Groessler, May-2000
+;
+; int open(const char *name,int flags,...);
+; returns fd
+;
+
+UCASE_FILENAME = 1             ; comment it out if filename shouldn't be uppercased
+
+       .include "atari.inc"
+       .include "../common/fmode.inc"
+       .include "../common/errno.inc"
+       .export _open
+       .import __do_oserror,__seterrno,incsp4
+       .import ldaxysp,addysp,subysp
+       .import _strupr,__oserror
+       .importzp tmp4,sp
+.ifdef UCASE_FILENAME
+       .importzp tmp3,ptr4
+.endif
+
+.proc  _open
+
+       cpy     #4              ; correct # of arguments (bytes)?
+       beq     parmok          ; parameter count ok
+       tya                     ; parm count < 4 shouldn't be needed to be checked
+       sec                     ;       (it generates a c compiler warning)
+       sbc     #4
+       tay
+       jsr     addysp          ; fix stack, throw away unused parameters
+
+parmok:        jsr     findfreeiocb
+       beq     iocbok          ; we found one
+
+       lda     #<EMFILE        ; "too many open files"
+       ldx     #>EMFILE
+seterr:        jsr     __seterrno
+       jsr     incsp4          ; clean up stack
+       lda     #$FF
+       tax
+       rts                     ; return -1
+
+       ; process the mode argument
+       ; @@@TODO: append not handled yet!
+
+iocbok:        stx     tmp4
+       jsr     clriocb         ; init with zero
+       ldy     #1
+       jsr     ldaxysp         ; get mode
+       ldx     tmp4
+       cmp     #O_RDONLY
+       bne     l1
+       lda     #OPNIN
+set:   sta     ICAX1,x
+       bne     cont
+
+l1:    cmp     #O_WRONLY
+       bne     l2
+       lda     #OPNOT
+       bne     set
+
+l2:    ; O_RDWR
+       lda     #OPNOT|OPNIN
+       bne     set
+
+       ; process the filename argument
+
+cont:  ldy     #3
+       jsr     ldaxysp
+
+.ifdef UCASE_FILENAME
+       ; we make sure that the filename doesn't contain lowercase letters
+       ; we copy the filename we got onto the stack, uppercase it and use this
+       ; one to open the iocb
+       ; we're using tmp3, ptr4
+
+       ; save the original pointer
+       sta     ptr4
+       stx     ptr4+1
+
+       ; now we need the length of the name
+       ldy     #0
+loop:  lda     (ptr4),y
+       beq     str_end
+       cmp     #ATEOL          ; we also accept Atari EOF char as end of string
+       beq     str_end
+       iny
+       bne     loop            ; not longer than 255 chars (127 real limit)
+toolong:lda    #<EINVAL        ; file name is too long
+       ldx     #>EINVAL
+       jmp     seterr
+
+str_end:iny                    ; room for terminating zero
+       cpy     #128            ; we only can handle lenght < 128
+       bcs     toolong
+       sty     tmp3            ; save size
+       jsr     subysp          ; make room on the stack
+
+       ; copy filename to the temp. place on the stack
+       lda     #0              ; end-of-string
+       sta     (sp),y          ; Y still contains length + 1
+       dey
+loop2: lda     (ptr4),y
+       sta     (sp),y
+       dey
+       bpl     loop2           ; bpl: this way we only support a max. length of 127
+
+       ; uppercase the temp. filename
+       ldx     sp+1
+       lda     sp
+       jsr     _strupr
+
+       ; leave X and Y pointing to the modified filename
+       lda     sp
+       ldx     sp+1
+
+.endif ; defined UCASE_FILENAME
+
+       ldy     tmp4
+
+       jsr     newfd           ; maybe we don't need to open and can reuse an iocb
+       bcc     noopen
+
+       sta     ICBAL,y
+       txa
+       sta     ICBAH,y
+       ldx     tmp4
+       lda     #OPEN
+       sta     ICCOM,x
+       jsr     CIOV
+
+       ; clean up the stack
+
+       php
+       txa
+       pha
+       tya
+       pha
+
+.ifdef UCASE_FILENAME
+       ldy     tmp3            ; get size
+       jsr     addysp          ; free used space on the stack
+.endif ; defined UCASE_FILENAME
+
+       jsr     incsp4          ; clean up stack
+
+       pla
+       tay
+       pla
+       tax
+       plp
+
+       bpl     ok
+       jmp     __do_oserror
+
+ok:    txa
+       lsr     a
+       lsr     a
+       lsr     a
+       lsr     a
+       ldx     #0
+       stx     __oserror
+       rts
+
+.endproc
+
+
+; find a free iocb
+; no entry parameters
+; return ZF = 0/1 for not found/found
+;        index in X if found
+; all registers destroyed
+
+.proc  findfreeiocb
+
+       ldx     #0
+       ldy     #$FF
+loop:  tya
+       cmp     ICHID,x
+       beq     found
+       txa
+       clc
+       adc     #$10
+       tax
+       cmp     #$80
+       bcc     loop
+       inx                     ; return ZF cleared
+found: rts
+
+.endproc
+
+
+; clear iocb except for ICHID field
+; expects X to be index to IOCB (0,$10,$20,etc.)
+; all registers destroyed
+
+.proc  clriocb
+
+       inx                     ; don't clear ICHID
+       ldy     #15
+       lda     #0
+loop:  sta     ICHID,x
+       dey
+       inx
+       bne     loop
+       rts
+
+.endproc
diff --git a/libsrc/atari/oserror.s b/libsrc/atari/oserror.s
new file mode 100644 (file)
index 0000000..dcbe7db
--- /dev/null
@@ -0,0 +1,85 @@
+;
+; Christian Groessler, May-2000
+;
+; os specific error code mapping
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+;
+
+       .include "../common/errno.inc"
+       .export __osmaperrno
+
+.proc  __osmaperrno
+
+       cmp     #$80            ; error or success
+       bcs     errcode         ; error, jump
+
+       lda     #0              ; no error, return 0
+       tax
+       rts
+
+errcode:and    #$7f            ; create index from error number
+       tax
+       cpx     #MAX_OSERR_VAL  ; valid number?
+       bcs     inverr          ; no
+
+       lda     maptable,x
+       ldx     #0
+       rts
+
+inverr:        lda     #<EUNKNOWN
+       ldx     #>EUNKNOWN
+       rts
+
+.endproc
+
+.rodata
+       
+maptable:
+       .byte   EINTR   ;BRKABT = 128           ;($80) BREAK key abort
+       .byte   EBUSY   ;PRVOPN = 129           ;($81) IOCB already open error
+       .byte   ENODEV  ;NONDEV = 130           ;($82) nonexistent device error
+       .byte   EACCES  ;WRONLY = 131           ;($83) IOCB opened for write only error
+       .byte   ENOSYS  ;NVALID = 132           ;($84) invalid command error
+       .byte   EINVAL  ;NOTOPN = 133           ;($85) device/file not open error
+       .byte   EINVAL  ;BADIOC = 134           ;($86) invalid IOCB index error
+       .byte   EACCES  ;RDONLY = 135           ;($87) IOCB opened for read only error
+       .byte   EINVAL  ;EOFERR = 136           ;($88) end of file error (should never come,
+                                               ;      specially handled by read.s)
+       .byte   EIO     ;TRNRCD = 137           ;($89) truncated record error
+       .byte   EIO     ;TIMOUT = 138           ;($8A) peripheral device timeout error
+       .byte   EIO     ;DNACK  = 139           ;($8B) device does not acknowledge command
+       .byte   EIO     ;FRMERR = 140           ;($8C) serial bus framing error
+       .byte   EINVAL  ;CRSROR = 141           ;($8D) cursor overrange error
+       .byte   EIO     ;OVRRUN = 142           ;($8E) serial bus data overrun error
+       .byte   EIO     ;CHKERR = 143           ;($8F) serial bus checksum error
+       .byte   EIO     ;DERROR = 144           ;($90) device done (operation incomplete)
+       .byte   EINVAL  ;BADMOD = 145           ;($91) bad screen mode number error
+       .byte   ENOSYS  ;FNCNOT = 146           ;($92) function not implemented in handler
+       .byte   ENOMEM  ;SCRMEM = 147           ;($93) insufficient memory for screen mode
+; codes below taken from "Mein Atari Computer" (german version of "Your Atari Computer")
+       .byte   EUNKNOWN        ; 148 - haven't found documentation
+       .byte   EUNKNOWN        ; 149 - haven't found documentation
+       .byte   EBUSY           ; 150 - serial port already open
+       .byte   EACCES          ; 151 - concurrent mode I/O not enabled (serial)
+       .byte   EINVAL          ; 152 - invalid buffer address for concurrent mode
+       .byte   EAGAIN          ; 153 - concurrent mode enabled (and another access tried)
+       .byte   EACCES          ; 154 - concurrent mode I/O not active (serial)
+       .byte   EUNKNOWN        ; 155 - haven't found documentation
+       .byte   EUNKNOWN        ; 156 - haven't found documentation
+       .byte   EUNKNOWN        ; 157 - haven't found documentation
+       .byte   EUNKNOWN        ; 158 - haven't found documentation
+       .byte   EUNKNOWN        ; 159 - haven't found documentation
+       .byte   ENOENT          ; 160 - drive number error (DOS)
+       .byte   EMFILE          ; 161 - too many open files
+       .byte   ENOSPC          ; 162 - disk full
+       .byte   EIO             ; 163 - unrecoverable system data I/O error
+       .byte   ESPIPE          ; 164 - file number mismatch (inv. seek or disk data strucs damaged)
+       .byte   ENOENT          ; 165 - invalid file name (e.g. lowercase)
+       .byte   ESPIPE          ; 166 - point data length error
+       .byte   EACCES          ; 167 - file locked (read-only)
+       .byte   ENOSYS          ; 168 - command invalid
+       .byte   ENOSPC          ; 169 - directory full
+       .byte   ENOENT          ; 170 - file not found
+       .byte   ESPIPE          ; 171 - point command invalid
+
+MAX_OSERR_VAL = (* - maptable)
diff --git a/libsrc/atari/read.s b/libsrc/atari/read.s
new file mode 100644 (file)
index 0000000..de2990d
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Christian Groessler, Apr-2000
+;
+; int read(int fd,void *buf,int count)
+;
+
+       .include "atari.inc"
+       .import __rwsetup,__do_oserror,__inviocb,__oserror
+       .export _read
+
+_read: jsr     __rwsetup       ; do common setup for read and write
+       beq     done            ; if size 0, it's a no-op
+       cpx     #$FF            ; invalid iocb?
+       beq     _inviocb
+       lda     #GETCHR         ; iocb command code
+       sta     ICCOM,x
+       jsr     CIOV            ; read it
+       bpl     done
+       cpy     #EOFERR         ; eof is treated specially
+       beq     done
+       jmp     __do_oserror    ; update errno
+
+done:  lda     ICBLL,x         ; buf len lo
+       pha                     ; save
+       lda     ICBLH,x         ; get buf len hi
+       tax                     ; to X
+       lda     #0
+       sta     __oserror       ; clear system dependend error code
+       pla                     ; get buf len lo
+       rts
+
+_inviocb:
+       jmp     __inviocb
diff --git a/libsrc/atari/readjoy.s b/libsrc/atari/readjoy.s
new file mode 100644 (file)
index 0000000..c9e3cd5
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Christian Groessler
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+       .export         _readjoy
+
+       .include        "atari.inc"
+
+
+.proc  _readjoy
+
+       and     #3              ; fix joystick number
+       tax                     ; Joystick number (0-3) into X
+
+; Read joystick
+
+       lda     STRIG0,x        ; get button
+       asl     a
+       asl     a
+       asl     a
+       asl     a
+       ora     STICK0,x        ; add position information
+       eor     #$1F
+       ldx     #0              ; fix X
+       rts
+
+.endproc
+
diff --git a/libsrc/atari/revers.s b/libsrc/atari/revers.s
new file mode 100644 (file)
index 0000000..ee59e71
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned char revers (unsigned char onoff);
+;
+       .include "atari.inc"
+       
+       .export         _revers
+
+_revers:
+       ldx     #$00            ; Assume revers off
+       tay                     ; Test onoff
+       beq     L1              ; Jump if off
+       ldx     #$80            ; Load on value
+L1:    ldy     #$00            ; Assume old value is zero
+       lda     INVFLG          ; Load old value
+       stx     INVFLG          ; Set new value
+       beq     L2              ; Jump if old value zero
+       iny                     ; Make old value = 1
+L2:    ldx     #$00            ; Load high byte of result
+       tya                     ; Load low byte, set CC
+       rts
+
diff --git a/libsrc/atari/rwcommon.s b/libsrc/atari/rwcommon.s
new file mode 100644 (file)
index 0000000..8a88814
--- /dev/null
@@ -0,0 +1,77 @@
+;
+; common iocb setup routine for read, write
+; expects parameters (int fd,void *buf,int count)
+;
+        .include "atari.inc"
+       .include "../common/errno.inc"
+        .importzp tmp2,tmp3
+        .import incsp6,ldaxysp
+       .import __errno,__oserror
+       .import fdtoiocb
+        
+        .export __rwsetup
+
+__rwsetup:
+       
+        ldy     #5
+        jsr     ldaxysp         ; get fd
+       jsr     fdtoiocb        ; convert to iocb
+       bmi     iocberr
+;      asl     a               ; iocb #  -->  iocb index
+;      asl     a
+;      asl     a
+;      asl     a
+        sta     tmp3            ; save it
+        ldy     #1
+        jsr     ldaxysp         ; get size
+        php                     ; save cond codes, for zero-ness
+        stx     tmp2
+        ldx     tmp3            ; iocb
+       cpx     #$80            ; iocb must be 0...7
+       bcs     iocberr 
+        sta     ICBLL,x
+        lda     tmp2            ; size hi
+        sta     ICBLH,x
+        ldy     #3              ; get buf addr (was 2 in orig. version)
+        jsr     ldaxysp
+        stx     tmp2
+        ldx     tmp3
+        sta     ICBAL,x
+        lda     tmp2
+        sta     ICBAH,x
+       jsr     incsp6          ; pop args
+        plp
+        rts
+
+iocberr:jsr     incsp6          ; pop args
+       plp                     ; throw away
+       ldx     #$FF            ; indicate error + clear ZF
+       rts
+
+       
+;
+; this routine updates errno.  do a JMP here right after calling
+; CIOV.  we expect status in Y.
+;
+        .export __do_oserror,__seterrno,__inviocb
+__do_oserror:
+       sty     __oserror       ; save os dependent error code
+retminus:      
+       lda     #$FF
+       tax                     ; return -1
+       rts
+
+__seterrno:
+        sta     __errno
+        stx     __errno+1
+        rts
+
+;
+; sets EINVAL error code and returns -1
+;
+
+__inviocb:
+       lda     #<EINVAL
+       ldx     #>EINVAL
+       jsr     __seterrno
+       jmp     retminus        ; return -1
diff --git a/libsrc/atari/savevec.s b/libsrc/atari/savevec.s
new file mode 100644 (file)
index 0000000..d29bde6
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; save and restore system vectors
+; originally by Mark Keates
+;
+; void save_vecs(void);
+; void rest_vecs(void);
+;
+
+       .export _save_vecs,_rest_vecs
+.include       "atari.inc"
+
+       .bss
+
+old_dli:     .res 2
+old_dlist:   .res 2
+old_vbi:     .res 2
+old_vbd:     .res 2
+old_gra:     .res 1
+old_dma:     .res 1
+old_prior:   .res 1
+old_cols:    .res 8
+old_set:     .res 1
+old_rmargin: .res 1    ; lmargin saved in startup code
+
+       .code
+
+.proc  _save_vecs
+
+       lda     VDSLST
+       sta     old_dli
+       lda     VDSLST+1
+               sta     old_dli+1
+       lda     SDLSTL
+       sta     old_dlist
+       lda     SDLSTL+1
+               sta     old_dlist+1
+       lda     VVBLKI
+       sta     old_vbi
+       lda     VVBLKI+1
+               sta     old_vbi+1
+       lda     VVBLKD
+       sta     old_vbd
+       lda     VVBLKD+1
+               sta     old_vbd+1
+       lda     GRACTL
+       sta     old_gra
+       lda     SDMCTL
+       sta     old_dma
+       lda     GPRIOR
+               sta     old_prior
+       lda     CHBAS
+       sta     old_set
+       lda     RMARGN
+       sta     old_rmargin
+
+       ldy     #7
+SETUP1:
+       lda     PCOLR0,y
+       sta     old_cols,y
+       dey
+       bpl     SETUP1
+       rts
+
+.endproc
+
+.proc  _rest_vecs
+
+       lda     #6
+       ldx     old_vbi+1
+       ldy     old_vbi
+       jsr     SETVBV
+       lda     #7
+       ldx     old_vbd+1
+       ldy     old_vbd
+       jsr     SETVBV
+       lda     old_dli
+       sta     VDSLST
+       lda     old_dli+1
+               sta     VDSLST+1
+       lda     old_dlist
+       sta     SDLSTL
+       lda     old_dlist+1
+               sta     SDLSTL+1
+       lda     old_gra
+       sta     GRACTL
+       lda     old_prior
+               sta     GPRIOR
+       lda     old_dma
+       sta     SDMCTL
+       lda     old_set
+       sta     CHBAS
+       lda     old_rmargin
+       sta     RMARGN
+       lda     #$FF
+       sta     CH
+       ldy     #7
+SETUP2:
+       lda     old_cols,Y
+       sta     PCOLR0,Y
+       dey
+       bpl     SETUP2
+       rts
+
+.endproc
+
diff --git a/libsrc/atari/where.s b/libsrc/atari/where.s
new file mode 100644 (file)
index 0000000..25c2d0f
--- /dev/null
@@ -0,0 +1,27 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char wherex (void);
+; unsigned char wherey (void);
+
+       .export         _wherex, _wherey
+       .import         plot
+       
+       .include        "atari.inc"
+
+_wherex:
+       sec
+       jsr     plot            ; Get cursor position
+       tya
+       rts
+
+_wherey:
+       sec
+       jsr     plot            ; Get cursor position
+       txa
+       rts
+
+
+
+
+
diff --git a/libsrc/atari/write.s b/libsrc/atari/write.s
new file mode 100644 (file)
index 0000000..e6bc8cc
--- /dev/null
@@ -0,0 +1,29 @@
+;
+; write(iocb, buf, nbytes)->nbytes written
+;
+       .include "atari.inc"
+       .import __rwsetup,__do_oserror,__inviocb,__oserror
+       .export _write
+_write:
+       jsr     __rwsetup       ; do common setup
+       beq     write9          ; if size 0, it's a no-op
+       cpx     #$FF            ; invalid iocb?
+       beq     _inviocb
+       lda     #PUTCHR
+       sta     ICCOM,x
+       jsr     CIOV
+       bpl     write9
+       jmp     __do_oserror    ; update errno
+
+write9:
+       lda     ICBLL,x         ; get buf len lo
+       pha
+       lda     ICBLH,x         ; buf len hi
+       tax
+       lda     #0
+       sta     __oserror       ; clear system dependend error code
+       pla
+       rts
+
+_inviocb:
+       jmp     __inviocb
diff --git a/libsrc/c128/Makefile b/libsrc/c128/Makefile
new file mode 100644 (file)
index 0000000..868e8e4
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o conio.o kbhit.o clrscr.o cgetc.o readjoy.o\
+        color.o cputc.o break.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/c128/break.s b/libsrc/c128/break.s
new file mode 100644 (file)
index 0000000..f0d69ce
--- /dev/null
@@ -0,0 +1,127 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+       .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+       .importzp       ptr1
+
+       .include        "c128.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+.code
+
+; Where will we put the break stub?
+stub_addr      = $0E00                 ; BASIC sprite area
+
+
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L2              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       ldy     #stub_size-1    ; Copy our stub into the low mem area
+L1:    lda     brk_stub,y
+       sta     stub_addr,y
+       dey
+       bpl     L1
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L2:            lda     #<stub_addr     ; Set the break vector to our stub
+       sta     BRKVec
+       lda     #>stub_addr
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       pla
+       sta     _brk_y
+       pla
+       sta     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+
+               jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
+brk_stub:
+       .org    stub_addr
+               pla                     ; Get original MMU value
+       sta     MMU_CR          ; Re-enable our config
+       jmp     brk_handler     ; Jump to the user handler
+       .reloc
+
+stub_size      = * - brk_stub
diff --git a/libsrc/c128/c128.inc b/libsrc/c128/c128.inc
new file mode 100644 (file)
index 0000000..7bfcfcd
--- /dev/null
@@ -0,0 +1,185 @@
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST                     = $90           ; IEC status byte
+
+FNAM_LEN               = $B7           ; Length of filename
+SECADR                 = $B9           ; Secondary address
+DEVNUM                 = $BA           ; Device number
+FNAM_BANK              = $C7           ; Bank for filename
+FNAM_LO                = $BB           ; Address of filename
+FNAM_HI                = $BC
+KEY_COUNT              = $D0           ; Number of keys in input buffer
+MODE                   = $D7           ; 40/80 column mode flag
+CURS_X                 = $EC           ; Cursor column
+CURS_Y                 = $EB           ; Cursor row
+SCREEN_PTR             = $E0           ; Pointer to current char in text screen
+CRAM_PTR               = $E2           ; Pointer to current char in color RAM
+
+CHARCOLOR       = $F1
+FKEY_COUNT             = $D1           ; Characters for function key
+FKEY_LEN       = $1000         ; Function key lengths
+FKEY_TEXT      = $100A         ; Function key texts
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CURS_ON                = $CD6F
+CURS_OFF        = $CD9F
+CLRSCR         = $C142
+KBDREAD                = $C006
+
+; ---------------------------------------------------------------------------
+; Vectors
+
+IRQVec         = $0314
+BRKVec         = $0316
+NMIVec         = $0318
+KeyStoreVec    = $033C
+
+; ---------------------------------------------------------------------------
+; I/O: VIC
+
+VIC            = $D000
+VIC_SPR0_X     = $D000
+VIC_SPR0_Y     = $D001
+VIC_SPR1_X     = $D002
+VIC_SPR1_Y     = $D003
+VIC_SPR2_X     = $D004
+VIC_SPR2_Y     = $D005
+VIC_SPR3_X     = $D006
+VIC_SPR3_Y     = $D007
+VIC_SPR4_X     = $D008
+VIC_SPR4_Y     = $D009
+VIC_SPR5_X     = $D00A
+VIC_SPR5_Y     = $D00B
+VIC_SPR6_X     = $D00C
+VIC_SPR6_Y     = $D00D
+VIC_SPR7_X     = $D00E
+VIC_SPR7_Y     = $D00F
+VIC_SPR_HI_X   = $D010
+VIC_SPR_ENA    = $D015
+VIC_SPR_EXP_X  = $D017
+VIC_SPR_EXP_Y  = $D01D
+VIC_SPR_MCOLOR = $D01C
+VIC_SPR_BG_PRIO = $D01B
+
+VIC_SPR_MCOLOR0 = $D025
+VIC_SPR_MCOLOR1 = $D026
+
+VIC_SPR0_COLOR = $D027
+VIC_SPR1_COLOR = $D028
+VIC_SPR2_COLOR = $D029
+VIC_SPR3_COLOR = $D02A
+VIC_SPR4_COLOR = $D02B
+VIC_SPR5_COLOR = $D02C
+VIC_SPR6_COLOR = $D02D
+VIC_SPR7_COLOR = $D02E
+
+VIC_CTRL1      = $D011
+VIC_CTRL2      = $D016
+
+VIC_HLINE      = $D012
+
+VIC_VIDEO_ADR  = $D018
+
+VIC_IRR                = $D019         ; Interrupt request register
+VIC_IMR                = $D01A         ; Interrupt mask register
+
+VIC_BORDERCOLOR = $D020
+VIC_BG_COLOR0  = $D021
+VIC_BG_COLOR1  = $D022
+VIC_BG_COLOR2  = $D023
+VIC_BG_COLOR3  = $D024
+
+; 128 stuff:
+VIC_KBD_128    = $D02F         ; Extended kbd bits (visible in 64 mode)
+VIC_CLK_128    = $D030         ; Clock rate register (visible in 64 mode)
+
+
+; ---------------------------------------------------------------------------
+; I/O: SID
+
+SID            = $D400
+SID_S1Lo       = $D400
+SID_S1Hi       = $D401
+SID_PB1Lo      = $D402
+SID_PB1Hi      = $D403
+SID_Ctl1       = $D404
+SID_AD1                = $D405
+SID_SUR1       = $D406
+
+SID_S2Lo       = $D407
+SID_S2Hi       = $D408
+SID_PB2Lo      = $D409
+SID_PB2Hi      = $D40A
+SID_Ctl2       = $D40B
+SID_AD2                = $D40C
+SID_SUR2       = $D40D
+
+SID_S3Lo       = $D40E
+SID_S3Hi       = $D40F
+SID_PB3Lo      = $D410
+SID_PB3Hi      = $D411
+SID_Ctl3       = $D412
+SID_AD3                = $D413
+SID_SUR3       = $D414
+
+SID_FltLo      = $D415
+SID_FltHi      = $D416
+SID_FltCtl     = $D417
+SID_Amp                = $D418
+SID_ADConv1    = $D419
+SID_ADConv2    = $D41A
+SID_Noise      = $D41B
+SID_Read3      = $D41C
+
+; ---------------------------------------------------------------------------
+; I/O: VDC (128 only)
+
+VDC_INDEX      = $D600
+VDC_DATA       = $D601
+
+; ---------------------------------------------------------------------------
+; I/O: CIAs
+
+CIA1           = $DC00
+CIA1_PRA       = $DC00
+CIA1_PRB       = $DC01
+CIA1_DDRA      = $DC02
+CIA1_DDRB      = $DC03
+CIA1_ICR       = $DC0D
+CIA1_CRA       = $DC0E
+CIA1_CRB       = $DC0F
+
+CIA2           = $DD00
+CIA2_PRA       = $DD00
+CIA2_PRB       = $DD01
+CIA2_DDRA      = $DD02
+CIA2_DDRB      = $DD03
+CIA2_ICR       = $DD0D
+CIA2_CRA       = $DD0E
+CIA2_CRB       = $DD0F
+
+; ---------------------------------------------------------------------------
+; I/O: MMU
+
+MMU_CR         = $FF00
+
+; ---------------------------------------------------------------------------
+; Super CPU
+
+SCPU_VIC_Bank1 = $D075
+SCPU_Slow      = $D07A
+SCPU_Fast      = $D07B
+SCPU_EnableRegs = $D07E
+SCPU_DisableRegs= $D07F
+SCPU_Detect    = $D0BC
+
+
diff --git a/libsrc/c128/cgetc.s b/libsrc/c128/cgetc.s
new file mode 100644 (file)
index 0000000..391a25f
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+       .export         _cgetc
+       .import         cursor
+
+       .include        "c128.inc"
+
+_cgetc:        lda     KEY_COUNT       ; Get number of characters
+       bne     L2              ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+       lda     cursor
+               beq     L1
+       jsr     CURS_ON
+       jmp     L2
+L1:            lda     #$01
+       jsr     CURS_OFF
+L2:            lda     KEY_COUNT       ; Check characters again
+       beq     L2
+       jsr     CURS_OFF        ; Switch cursor off, if characters available
+
+               jsr     KBDREAD         ; Read char and return in A
+       ldx     #0
+       rts
+
+          
diff --git a/libsrc/c128/clrscr.s b/libsrc/c128/clrscr.s
new file mode 100644 (file)
index 0000000..54219b0
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+
+       .include        "c128.inc"
+
+_clrscr        = CLRSCR
+
+
+
diff --git a/libsrc/c128/color.s b/libsrc/c128/color.s
new file mode 100644 (file)
index 0000000..c633090
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+       .export         _textcolor, _bgcolor, _bordercolor
+
+       .include        "c128.inc"
+
+
+_textcolor:
+       ldx     CHARCOLOR       ; get old value
+       sta     CHARCOLOR       ; set new value
+       txa
+       rts
+
+
+_bgcolor:
+       ldx     VIC_BG_COLOR0   ; get old value
+       sta     VIC_BG_COLOR0   ; set new value
+       txa
+       rts
+
+
+_bordercolor:
+       ldx     VIC_BG_COLOR0   ; get old value
+       sta     VIC_BORDERCOLOR ; set new value
+       txa
+       rts
+
diff --git a/libsrc/c128/conio.s b/libsrc/c128/conio.s
new file mode 100644 (file)
index 0000000..481b4e7
--- /dev/null
@@ -0,0 +1,50 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio, doneconio
+       .exportzp       CURS_X, CURS_Y
+       .import         xsize, ysize
+
+       .include        "c128.inc"
+       .include        "../cbm/cbm.inc"
+
+.bss
+keyvec:        .res    2
+
+
+.code
+
+initconio:
+       jsr     SCREEN
+       inx
+       stx     xsize
+       iny
+       sty     ysize
+
+; Save the old vector
+
+       lda     KeyStoreVec
+       sta     keyvec
+       lda     KeyStoreVec+1
+       sta     keyvec+1
+
+; Set the new vector. I can only hope that this works for other C128
+; versions...
+
+       lda     #<$C6B7
+       ldx     #>$C6B7
+
+SetVec:        sei
+       sta     KeyStoreVec
+       stx     KeyStoreVec+1
+       cli
+       rts
+
+doneconio:
+       lda     keyvec
+       ldx     keyvec+1
+       bne     SetVec
+
diff --git a/libsrc/c128/cputc.s b/libsrc/c128/cputc.s
new file mode 100644 (file)
index 0000000..99253d0
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc, cputdirect, putchar
+       .export         advance, newline, plot
+       .import         popa, _gotoxy
+       .import         xsize, revers
+
+       .include        "c128.inc"
+       .include        "../cbm/cbm.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     CURS_X
+               beq     plot            ; Recalculate pointers
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       ldy     CURS_Y
+       iny
+       bne     newline         ; Recalculate pointers
+
+; Printable char of some sort
+
+L2:            cmp     #' '
+       bcc     cputdirect      ; Other control char
+       tay
+       bmi     L10
+       cmp     #$60
+       bcc     L3
+       and     #$DF
+       bne     cputdirect      ; Branch always
+L3:    and     #$3F
+
+cputdirect:
+       jsr     putchar         ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+       iny
+       cpy     xsize
+       bne     L9
+       ldy     #0              ; new line
+newline:
+       clc
+       lda     xsize
+       adc     SCREEN_PTR
+       sta     SCREEN_PTR
+       bcc     L4
+       inc     SCREEN_PTR+1
+L4:    clc
+       lda     xsize
+       adc     CRAM_PTR
+       sta     CRAM_PTR
+       bcc     L5
+       inc     CRAM_PTR+1
+L5:    inc     CURS_Y
+L9:            sty     CURS_X
+       rts
+
+; Handle character if high bit set
+
+L10:   and     #$7F
+               cmp     #$7E            ; PI?
+       bne     L11
+       lda     #$5E            ; Load screen code for PI
+       bne     cputdirect
+L11:   ora     #$40
+       bne     cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot:  ldy     CURS_X
+       ldx     CURS_Y
+       clc
+       jmp     PLOT            ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+       ora     revers          ; Set revers bit
+               ldy     CURS_X
+       sta     (SCREEN_PTR),y  ; Set char
+       lda     CHARCOLOR
+       sta     (CRAM_PTR),y    ; Set color
+       rts
diff --git a/libsrc/c128/crt0.s b/libsrc/c128/crt0.s
new file mode 100644 (file)
index 0000000..f10078d
--- /dev/null
@@ -0,0 +1,141 @@
+;
+; Startup code for cc65 (C128 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+       .import         __hinit, initconio, doneconio, zerobss
+       .import         push0, doatexit, _main
+
+       .include        "c128.inc"
+       .include        "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+
+sp             =       $02             ; stack pointer
+sreg   =       $04             ; secondary register/high 16 bit for longs
+regsave        =       $06             ; slot to save/restore (E)AX into
+ptr1   =       $0A             ;
+ptr2   =       $0C
+ptr3   =       $0E
+ptr4   =       $10
+tmp1   =       $12
+tmp2   =       $13
+tmp3   =       $14
+tmp4   =       $15
+regbank        =       $16             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+       .org    $1BFF
+        .word   Head            ; Load address
+Head:   .word   @Next
+        .word   1000            ; Line number
+        .byte   $9E,"7181"      ; SYS 7181
+        .byte   $00             ; End of BASIC line
+@Next:  .word   0               ; BASIC end marker
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y        ; save the zero page locations we need
+       dey
+               bpl     L1
+
+; Close open files
+
+       jsr     CLRCH
+
+; Switch to second charset
+
+       lda     #14
+       jsr     BSOUT
+
+; Get the current MMU setting and save it. Set new memory config.
+
+       lda     MMU_CR          ; Get current memory configuration...
+               pha                     ; ...and save it for later
+       lda     #$0E            ; Bank0 with kernal ROM
+       sta     MMU_CR
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Save system stuff and setup the stack
+
+       pla                     ; Get MMU setting
+       sta     mmusave
+
+               tsx
+               stx     spsave          ; save system stk ptr
+
+       lda     #<$C000
+       sta     sp
+       lda     #>$C000
+       sta     sp+1
+
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       jsr     initconio
+
+; Pass an empty command line
+
+       jsr     push0           ; argc
+       jsr     push0           ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr     doatexit        ; call exit functions
+
+; Reset the conio stuff
+
+       jsr     doneconio
+
+; Reset stack and the MMU
+
+       ldx     spsave          ; Patched at runtime
+       txs
+               lda     mmusave         ; Patched at runtime
+       sta     MMU_CR
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+       bpl     L2
+
+; Done
+
+       jmp     RESTOR
+
+.data
+zpsave:        .res    zpspace
+
+.bss
+spsave:        .res    1
+mmusave:.res   1
+
+
+
diff --git a/libsrc/c128/dbgbreak.s b/libsrc/c128/dbgbreak.s
new file mode 100644 (file)
index 0000000..472d800
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 10.08.1998
+;
+; unsigned DbgSetBreakVec (unsigned Addr);
+;
+
+       .export         _DbgSetBreakVec
+       .import         popax, utstax
+       
+       .include        "../cbm/cbm.inc"
+
+_DbgSetBreakVec:
+       jsr     popax           ; Get the new address
+       ldy     BRKVec
+       sta     BRKVec
+       lda     BRKVec+1
+       stx     BRKVec+1
+       tax
+       tya
+       jmp     utstax
+
+
+
+
diff --git a/libsrc/c128/kbhit.s b/libsrc/c128/kbhit.s
new file mode 100644 (file)
index 0000000..f63b941
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 18.08.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+
+       .include        "c128.inc"
+
+_kbhit:
+       lda     KEY_COUNT       ; Get number of characters
+;      ora     FKEY_COUNT      ; Or with number of chars from function keys
+       bne     L1
+       jmp     return0
+L1:    jmp     return1
+
+
+
+
diff --git a/libsrc/c128/readjoy.s b/libsrc/c128/readjoy.s
new file mode 100644 (file)
index 0000000..e409805
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+       .export         _readjoy
+
+       .include        "c128.inc"
+
+
+.proc  _readjoy
+
+       tax                     ; Joystick number into X
+       bne     joy2
+
+; Read joystick 1
+
+joy1:  lda     #$7F
+       sei
+       sta     CIA1_PRA
+       lda     CIA1_PRB
+       cli
+       and     #$1F
+       eor     #$1F
+       rts
+
+; Read joystick 2
+
+joy2:  ldx     #0
+       lda     #$E0
+       ldy     #$FF
+       sta     CIA1_DDRA
+       lda     CIA1_PRA
+       sty     CIA1_DDRA
+       and     #$1F
+       eor     #$1F
+       rts
+
+.endproc
+
diff --git a/libsrc/c64/Makefile b/libsrc/c64/Makefile
new file mode 100644 (file)
index 0000000..bfa8bc2
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o read.o write.o kbhit.o conio.o clrscr.o mouse.o\
+        cputc.o cgetc.o color.o readjoy.o break.o rs232.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/c64/break.s b/libsrc/c64/break.s
new file mode 100644 (file)
index 0000000..8b90d4f
--- /dev/null
@@ -0,0 +1,108 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+               .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+
+       .include        "c64.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     BRKVec
+       lda     #>brk_handler
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       pla
+       sta     _brk_y
+       pla
+       sta     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
diff --git a/libsrc/c64/c64.inc b/libsrc/c64/c64.inc
new file mode 100644 (file)
index 0000000..315aaf6
--- /dev/null
@@ -0,0 +1,194 @@
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST             = $90           ; IEC status byte
+
+FNAM_LEN       = $B7           ; Length of filename
+SECADR         = $B9           ; Secondary address
+DEVNUM         = $BA           ; Device number
+KEY_COUNT              = $C6           ; Number of keys in input buffer
+CURS_FLAG      = $CC           ; 1 = cursor off
+CURS_BLINK     = $CD           ; Blink counter
+CURS_CHAR      = $CE           ; Character under the cursor
+CURS_COLOR      = $287         ; Color under the cursor
+CURS_STATE     = $CF           ; Cursor blink state
+SCREEN_PTR     = $D1           ; Pointer to current char in text screen
+CURS_X         = $D3           ; Cursor column
+CURS_Y         = $D6           ; Cursor row
+CRAM_PTR       = $F3           ; Pointer to current char in color RAM
+
+CHARCOLOR       = $286
+PALFLAG                = $2A6          ; $01 = PAL, $00 = NTSC
+
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CLRSCR         = $E544
+KBDREAD                = $E5B4
+NAMED_OPEN     = $F3D5
+NAMED_CLOSE    = $F642
+PLOTCHAR       = $EA1C         ; Char in A, color in X
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec         = $0314
+BRKVec         = $0316
+NMIVec         = $0318
+
+; ---------------------------------------------------------------------------
+; I/O: VIC
+
+VIC            = $D000
+VIC_SPR0_X     = $D000
+VIC_SPR0_Y     = $D001
+VIC_SPR1_X     = $D002
+VIC_SPR1_Y     = $D003
+VIC_SPR2_X     = $D004
+VIC_SPR2_Y     = $D005
+VIC_SPR3_X     = $D006
+VIC_SPR3_Y     = $D007
+VIC_SPR4_X     = $D008
+VIC_SPR4_Y     = $D009
+VIC_SPR5_X     = $D00A
+VIC_SPR5_Y     = $D00B
+VIC_SPR6_X     = $D00C
+VIC_SPR6_Y     = $D00D
+VIC_SPR7_X     = $D00E
+VIC_SPR7_Y     = $D00F
+VIC_SPR_HI_X   = $D010
+VIC_SPR_ENA    = $D015
+VIC_SPR_EXP_X  = $D017
+VIC_SPR_EXP_Y  = $D01D
+VIC_SPR_MCOLOR = $D01C
+VIC_SPR_BG_PRIO = $D01B
+
+VIC_SPR_MCOLOR0 = $D025
+VIC_SPR_MCOLOR1 = $D026
+
+VIC_SPR0_COLOR = $D027
+VIC_SPR1_COLOR = $D028
+VIC_SPR2_COLOR = $D029
+VIC_SPR3_COLOR = $D02A
+VIC_SPR4_COLOR = $D02B
+VIC_SPR5_COLOR = $D02C
+VIC_SPR6_COLOR = $D02D
+VIC_SPR7_COLOR = $D02E
+
+VIC_CTRL1      = $D011
+VIC_CTRL2      = $D016
+
+VIC_HLINE      = $D012
+
+VIC_VIDEO_ADR  = $D018
+
+VIC_IRR                = $D019         ; Interrupt request register
+VIC_IMR                = $D01A         ; Interrupt mask register
+
+VIC_BORDERCOLOR = $D020
+VIC_BG_COLOR0  = $D021
+VIC_BG_COLOR1  = $D022
+VIC_BG_COLOR2  = $D023
+VIC_BG_COLOR3  = $D024
+
+; 128 stuff:
+VIC_KBD_128    = $D02F         ; Extended kbd bits (visible in 64 mode)
+VIC_CLK_128    = $D030         ; Clock rate register (visible in 64 mode)
+
+
+; ---------------------------------------------------------------------------
+; I/O: SID
+
+SID            = $D400
+SID_S1Lo       = $D400
+SID_S1Hi       = $D401
+SID_PB1Lo      = $D402
+SID_PB1Hi      = $D403
+SID_Ctl1       = $D404
+SID_AD1                = $D405
+SID_SUR1       = $D406
+
+SID_S2Lo       = $D407
+SID_S2Hi       = $D408
+SID_PB2Lo      = $D409
+SID_PB2Hi      = $D40A
+SID_Ctl2       = $D40B
+SID_AD2                = $D40C
+SID_SUR2       = $D40D
+
+SID_S3Lo       = $D40E
+SID_S3Hi       = $D40F
+SID_PB3Lo      = $D410
+SID_PB3Hi      = $D411
+SID_Ctl3       = $D412
+SID_AD3                = $D413
+SID_SUR3       = $D414
+
+SID_FltLo      = $D415
+SID_FltHi      = $D416
+SID_FltCtl     = $D417
+SID_Amp                = $D418
+SID_ADConv1    = $D419
+SID_ADConv2    = $D41A
+SID_Noise      = $D41B
+SID_Read3      = $D41C
+
+; ---------------------------------------------------------------------------
+; I/O: VDC (128 only)
+
+VDC_INDEX      = $D600
+VDC_DATA       = $D601
+
+; ---------------------------------------------------------------------------
+; I/O: CIAs
+
+CIA1           = $DC00
+CIA1_PRA       = $DC00
+CIA1_PRB       = $DC01
+CIA1_DDRA      = $DC02
+CIA1_DDRB      = $DC03
+CIA1_ICR       = $DC0D
+CIA1_CRA       = $DC0E
+CIA1_CRB       = $DC0F
+
+CIA2           = $DD00
+CIA2_PRA       = $DD00
+CIA2_PRB       = $DD01
+CIA2_DDRA      = $DD02
+CIA2_DDRB      = $DD03
+CIA2_ICR       = $DD0D
+CIA2_CRA       = $DD0E
+CIA2_CRB       = $DD0F
+
+; ---------------------------------------------------------------------------
+; Super CPU
+
+SCPU_VIC_Bank1 = $D075
+SCPU_Slow      = $D07A
+SCPU_Fast      = $D07B
+SCPU_EnableRegs = $D07E
+SCPU_DisableRegs= $D07F
+SCPU_Detect    = $D0BC
+
+
+; ---------------------------------------------------------------------------
+; Processor Port at $01
+
+LORAM          = $01           ; Enable the basic rom
+HIRAM          = $02           ; Enable the kernal rom
+IOEN           = $04           ; Enable I/O
+CASSDATA       = $08           ; Cassette data
+CASSPLAY       = $10           ; Cassette: Play
+CASSMOT                = $20           ; Cassette motor on
+TP_FAST                = $80           ; Switch Rossmoeller TurboProcess to fast mode
+
+RAMONLY                = $F8           ; (~(LORAM | HIRAM | IOEN)) & $FF
+
+
diff --git a/libsrc/c64/cgetc.s b/libsrc/c64/cgetc.s
new file mode 100644 (file)
index 0000000..5c4b407
--- /dev/null
@@ -0,0 +1,61 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+       .export         _cgetc
+       .import         cursor
+
+       .include        "c64.inc"
+
+_cgetc:        lda     KEY_COUNT       ; Get number of characters
+               bne     L3              ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+       lda     CURS_FLAG
+       pha
+       lda     cursor
+       jsr     setcursor
+L1:    lda     KEY_COUNT
+       beq     L1
+       ldx     #0
+       pla
+       bne     L2
+               inx
+L2:            txa
+               jsr     setcursor
+
+L3:            jsr     KBDREAD         ; Read char and return in A
+       ldx     #0
+       rts
+
+
+; Switch the cursor on or off
+
+.proc  setcursor
+
+               tax                     ; On or off?
+       bne     seton           ; Go set it on
+       lda     CURS_FLAG       ; Is the cursor currently off?
+       bne     crs9            ; Jump if yes
+       lda     #1
+       sta     CURS_FLAG       ; Mark it as off
+       lda     CURS_STATE      ; Cursor currently displayed?
+       beq     crs8            ; Jump if no
+       ldy     CURS_X          ; Get the character column
+               lda     (SCREEN_PTR),y  ; Get character
+       eor     #$80
+       sta     (SCREEN_PTR),y  ; Store character back
+       lda     CURS_COLOR
+       sta     (CRAM_PTR),y    ; Store color back
+crs8:  lda     #0
+       sta     CURS_STATE      ; Cursor not displayed
+crs9:  rts
+
+seton:         lda     #0
+       sta     CURS_FLAG
+       rts
+
+.endproc
diff --git a/libsrc/c64/clrscr.s b/libsrc/c64/clrscr.s
new file mode 100644 (file)
index 0000000..e0f8aed
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+
+       .include        "c64.inc"
+
+_clrscr = CLRSCR
+
+
+
diff --git a/libsrc/c64/color.s b/libsrc/c64/color.s
new file mode 100644 (file)
index 0000000..d4a4e4f
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+       .export         _textcolor, _bgcolor, _bordercolor
+
+       .include        "c64.inc"
+
+_textcolor:
+       ldx     CHARCOLOR       ; get old value
+       sta     CHARCOLOR       ; set new value
+       txa
+       rts
+
+
+_bgcolor:
+       ldx     VIC_BG_COLOR0   ; get old value
+       sta     VIC_BG_COLOR0   ; set new value
+       txa
+       rts
+
+
+_bordercolor:
+       ldx     VIC_BG_COLOR0   ; get old value
+       sta     VIC_BORDERCOLOR ; set new value
+       txa
+       rts
+
diff --git a/libsrc/c64/conio.s b/libsrc/c64/conio.s
new file mode 100644 (file)
index 0000000..f822c94
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio
+       .exportzp       CURS_X, CURS_Y
+       .import         xsize, ysize
+
+       .include        "../cbm/cbm.inc"
+       .include        "c64.inc"
+
+.code
+
+initconio:
+       jsr     SCREEN
+       stx     xsize
+       sty     ysize
+       rts
+
+
+
diff --git a/libsrc/c64/cputc.s b/libsrc/c64/cputc.s
new file mode 100644 (file)
index 0000000..bb7384a
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc, cputdirect, putchar
+       .export         advance, newline, plot
+       .import         popa, _gotoxy
+       .import         xsize, revers
+
+       .include        "c64.inc"
+       .include        "../cbm/cbm.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     CURS_X
+               beq     plot            ; Recalculate pointers
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       ldy     CURS_Y
+       iny
+       bne     newline         ; Recalculate pointers
+
+; Printable char of some sort
+
+L2:            cmp     #' '
+       bcc     cputdirect      ; Other control char
+       tay
+       bmi     L10
+       cmp     #$60
+       bcc     L3
+       and     #$DF
+       bne     cputdirect      ; Branch always
+L3:    and     #$3F
+
+cputdirect:
+       jsr     putchar         ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+       iny
+       cpy     xsize
+       bne     L9
+       ldy     #0              ; new line
+newline:
+       clc
+       lda     xsize
+       adc     SCREEN_PTR
+       sta     SCREEN_PTR
+       bcc     L4
+       inc     SCREEN_PTR+1
+L4:    clc
+       lda     xsize
+       adc     CRAM_PTR
+       sta     CRAM_PTR
+       bcc     L5
+       inc     CRAM_PTR+1
+L5:    inc     CURS_Y
+L9:            sty     CURS_X
+       rts
+
+; Handle character if high bit set
+
+L10:   and     #$7F
+               cmp     #$7E            ; PI?
+       bne     L11
+       lda     #$5E            ; Load screen code for PI
+       bne     cputdirect
+L11:   ora     #$40
+       bne     cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot:  ldy     CURS_X
+       ldx     CURS_Y
+       clc
+       jmp     PLOT            ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+       ora     revers          ; Set revers bit
+               ldy     CURS_X
+       sta     (SCREEN_PTR),y  ; Set char
+       lda     CHARCOLOR
+       sta     (CRAM_PTR),y    ; Set color
+       rts
diff --git a/libsrc/c64/crt0.s b/libsrc/c64/crt0.s
new file mode 100644 (file)
index 0000000..6d68f23
--- /dev/null
@@ -0,0 +1,132 @@
+;
+; Startup code for cc65 (C64 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+               .import         __hinit, initconio, zerobss, push0, doatexit
+       .import         _main
+
+       .include        "c64.inc"
+       .include        "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+
+sp             =       $02             ; stack pointer
+sreg   =       $04             ; secondary register/high 16 bit for longs
+regsave        =       $06             ; slot to save/restore (E)AX into
+ptr1   =       $0A             ;
+ptr2   =       $0C
+ptr3   =       $0E
+ptr4   =       $10
+tmp1   =       $12
+tmp2   =       $13
+tmp3   =       $14
+tmp4   =       $15
+regbank =              $16             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+       .org    $7FF
+        .word   Head            ; Load address
+Head:   .word   @Next
+        .word   1000            ; Line number
+        .byte   $9E,"2061"      ; SYS 2061
+        .byte   $00             ; End of BASIC line
+@Next:  .word   0               ; BASIC end marker
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y        ; Save the zero page locations we need
+       dey
+               bpl     L1
+
+; Close open files
+
+       jsr     CLRCH
+
+; Switch to second charset
+
+       lda     #14
+       jsr     BSOUT
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Save system stuff and setup the stack
+
+               tsx
+               stx     spsave          ; Save the system stack ptr
+
+       lda     $01
+       sta     mmusave         ; Save the memory configuration
+       lda     $01
+       and     #$F8
+               ora     #$06            ; Enable kernal+I/O, disable basic
+       sta     $01
+
+       lda     #<$D000
+       sta     sp
+       lda     #>$D000
+               sta     sp+1            ; Set argument stack ptr
+
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       jsr     initconio
+
+; Pass an empty command line
+
+               jsr     push0           ; argc
+       jsr     push0           ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr     doatexit        ; call exit functions
+
+       ldx     spsave
+       txs                     ; Restore stack pointer
+               lda     mmusave
+       sta     $01             ; Restore memory configuration
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+               bpl     L2
+
+; Reset changed vectors, back to basic
+
+       jmp     RESTOR
+
+
+.data
+
+zpsave:        .res    zpspace
+
+.bss
+
+spsave:        .res    1
+mmusave:.res   1
diff --git a/libsrc/c64/kbhit.s b/libsrc/c64/kbhit.s
new file mode 100644 (file)
index 0000000..1a54c2e
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+
+       .include        "c64.inc"
+
+_kbhit:
+       lda     KEY_COUNT       ; Get number of characters
+       bne     L1
+       jmp     return0
+L1:    jmp     return1
+
+
+
+
diff --git a/libsrc/c64/mouse.s b/libsrc/c64/mouse.s
new file mode 100644 (file)
index 0000000..bada17d
--- /dev/null
@@ -0,0 +1,384 @@
+;
+; Ullrich von Bassewitz, 24.04.1999
+;
+; Routines for the 1351 proportional mouse. Parts of the code are from
+; the Commodore 1351 mouse users guide.
+;
+
+       .export         _mouse_init, _mouse_done
+       .export         _mouse_hide, _mouse_show
+       .export         _mouse_box, _mouse_info
+       .export         _mouse_move
+
+               .import         popa, popsreg, addysp1
+       .importzp       sp, sreg
+
+       .include        "c64.inc"
+
+.code
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_init (unsigned char port, unsigned char sprite);
+;
+
+_mouse_init:
+       tax                             ; Save sprite number
+       jsr     popa                    ; Get the port number
+
+               ldy     OldIRQ+1                ; Already initialized?
+               bne     Done                    ; Jump if yes
+
+       stx     MouseSprite             ; Remember the sprite number
+       sta     MousePort               ; Remember the port number
+
+; Initialize variables
+
+               ldx     #0
+       stx     XPos
+       stx     XPos+1
+       stx     YPos
+       stx     YPos+1
+       stx     OldPotX
+       stx     OldPotY
+               stx     XMin
+       stx     XMin+1
+       stx     YMin
+       stx     YMin+1
+       stx     YMax+1
+       inx                             ; X = 1
+               stx     Visible                 ; Mouse *not* visible
+       stx     XMax+1                  ; >320
+       ldx     #<320
+       stx     XMax
+       ldx     #200
+       stx     YMax
+
+; Remember the old IRQ vector
+
+       lda     IRQVec
+       sta     OldIRQ
+       lda     IRQVec+1
+       sta     OldIRQ+1
+
+; Set our own IRQ vector
+
+       lda     #<MouseIRQ
+       ldx     #>MouseIRQ
+       bne     SetIRQ
+
+; --------------------------------------------------------------------------
+;
+; void mouse_done (void);
+;
+
+_mouse_done:
+               lda     OldIRQ                  ; Initialized?
+       ldx     OldIRQ+1
+       beq     Done                    ; Jump if no
+       ldy     #0
+       sty     OldIRQ+1                ; Reset the initialized flag
+SetIRQ:        sei                             ; Disable interrupts
+       sta     IRQVec                  ; Set the new/old vector
+       stx     IRQVec+1
+       cli                             ; Enable interrupts
+Done:  rts
+
+; --------------------------------------------------------------------------
+;
+; void mouse_hide (void);
+;
+
+_mouse_hide:
+               lda     Visible                 ; Get the flag
+       bne     @L1                     ; Jump if already invisible
+               ldx     MouseSprite             ; Sprite defined?
+       beq     @L1                     ; Jump if no
+
+       lda     BitMask-1,x             ; Get bit mask
+       eor     #$FF                    ; We must clear the bit
+
+       sei                             ; Disable interrupts
+       and     VIC_SPR_ENA
+       sta     VIC_SPR_ENA             ; Disable sprite
+       cli                             ; Enable interrupts
+
+@L1:   inc     Visible                 ; Set the flag to invisible
+       rts
+
+; --------------------------------------------------------------------------
+;
+; void mouse_show (void);
+;
+
+_mouse_show:
+               dec     Visible                 ; Get the flag
+       bne     @L1                     ; Jump if still invisible
+               ldx     MouseSprite             ; Sprite defined?
+       beq     @L1                     ; Jump if no
+
+       lda     BitMask-1,x             ; Get bit mask
+               sei                             ; Disable interrupts
+               ora     VIC_SPR_ENA
+       sta     VIC_SPR_ENA             ; Enable sprite
+       cli                             ; Enable interrupts
+
+@L1:   rts
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
+;
+
+_mouse_box:
+       sei                             ; Disable interrupts
+
+       sta     YMax
+       stx     YMax+1                  ; maxy
+
+       ldy     #0
+       lda     (sp),y
+       sta     XMax
+       iny
+       lda     (sp),y
+       sta     XMax+1                  ; maxx
+
+       iny
+       lda     (sp),y
+       sta     YMin
+       iny
+       lda     (sp),y
+       sta     YMin+1                  ; miny
+
+       iny
+       lda     (sp),y
+       sta     XMin
+       iny
+       lda     (sp),y
+       sta     XMin+1                  ; minx
+
+       cli                             ; Enable interrupts
+
+       jmp     addysp1                 ; Drop params, return
+
+; --------------------------------------------------------------------------
+;
+; void mouse_info (...);
+;
+
+_mouse_info:
+       rts
+
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_move (int x, int y);
+;
+
+_mouse_move:
+       jsr     popsreg                 ; Get X
+       sei                             ; Disable interrupts
+
+       sta     YPos
+       stx     YPos+1
+       lda     sreg
+       ldx     sreg+1
+       sta     XPos
+       stx     XPos+1                  ; Set new position
+
+       lda     Visible                 ; Mouse visible?
+       bne     @L9                     ; Jump if no
+       lda     MouseSprite             ; Sprite defined?
+       beq     @L9
+
+       jsr     MoveSprite              ; Move the sprite to the mouse pos
+
+@L9:   cli                             ; Enable interrupts
+       rts
+
+; --------------------------------------------------------------------------
+;
+; Mouse interrupt handler
+;
+
+MouseIRQ:
+       cld
+       lda     SID_ADConv1             ; Get mouse X movement
+       ldy     OldPotX
+       jsr     MoveCheck               ; Calculate movement vector
+       sty     OldPotX
+
+; Calculate the new X coordinate (--> a/y)
+
+       clc
+       adc     XPos
+       tay                             ; Remember low byte
+       txa
+       adc     XPos+1
+
+; Limit the X coordinate to the bounding box
+
+       cpy     XMin+1
+       bne     @L1
+       cmp     XMin
+@L1:   bpl     @L2
+               ldy     XMin
+       lda     XMin+1
+       jmp     @L4
+
+@L2:   cpy     XMax+1
+       bne     @L3
+       cmp     XMax
+       beq     @L4
+@L3:   bmi     @L4
+               ldy     XMax
+       lda     XMax+1
+@L4:   sty     XPos
+       sta     XPos+1
+
+; Calculate the Y movement vector
+
+       lda     SID_ADConv2             ; Get mouse Y movement
+       ldy     OldPotY
+       jsr     MoveCheck               ; Calculate movement
+       sty     OldPotY
+
+; Calculate the new Y coordinate (--> a/y)
+
+       clc
+       adc     YPos
+       tay                             ; Remember low byte
+       txa
+       adc     YPos+1
+
+; Limit the Y coordinate to the bounding box
+
+               cpy     YMin+1
+       bne     @L5
+       cmp     YMin
+@L5:   bpl     @L6
+               ldy     YMin
+       lda     YMin+1
+       jmp     @L8
+
+@L6:   cpy     YMax+1
+       bne     @L7
+       cmp     YMax
+       beq     @L8
+@L7:   bmi     @L8
+               ldy     YMax
+       lda     YMax+1
+@L8:           sty     YPos
+       sta     YPos+1
+
+; Jump to the next IRQ handler
+
+       jmp     (OldIRQ)
+
+
+; --------------------------------------------------------------------------
+;
+; Move check routine, called for both coordinates.
+;
+; Entry:       y = old value of pot register
+;              a = current value of pot register
+; Exit:                y = value to use for old value
+;              x/a = delta value for position
+;
+
+MoveCheck:
+       sty     OldValue
+       sta     NewValue
+       ldx     #$00
+
+       sec                             ; a = mod64 (new - old)
+       sbc     OldValue
+       and     #%01111111
+       cmp     #%01000000              ; if (a > 0)
+       bcs     @L1                     ;
+       lsr     a                       ;   a /= 2;
+       beq     @L2                     ;   if (a != 0)
+       ldy     NewValue                ;     y = NewValue
+       rts                             ;   return
+
+@L1:   ora     #%11000000              ; else or in high order bits
+       cmp     #$FF                    ; if (a != -1)
+       beq     @L2
+       sec
+       ror     a                       ;   a /= 2
+       ldx     #$FF                    ;   high byte = -1
+       ldy     NewValue
+       rts
+
+@L2:   lda     #0
+       rts
+
+; --------------------------------------------------------------------------
+;
+; Move the mouse sprite to the current mouse position. Must be called
+; with interrupts off.
+;
+
+MoveSprite:
+       lda     Visible                 ; Mouse pointer visible?
+       bne     @L9                     ; Jump if no
+       ldx     MouseSprite             ; Sprite defined?
+       beq     @L9                     ; Jump if no
+       ldy     BitMask-1,x             ; Get high bit mask
+       txa
+       asl     a                       ; Index*2
+       tax
+
+; Set the X position
+
+       lda     XPos+1                  ; Negative?
+               bmi     @L2                     ; Jump if yes
+       beq     @L1
+               tya                             ; Load high position bit
+@L1:   ora     VIC_SPR_HI_X            ; Set high bit
+       sta     VIC_SPR_HI_X
+       lda     XPos
+       sta     VIC_SPR0_X,x            ; Set low byte
+
+; Set the Y position
+
+@L2:   ldy     YPos+1                  ; Negative or too large?
+       bne     @L9                     ; Jump if yes
+       lda     YPos
+       sta     VIC_SPR0_Y,x            ; Set Y position
+
+; Done
+
+@L9:   rts
+
+; --------------------------------------------------------------------------
+; Data
+
+.bss
+
+OldIRQ:                .res    2               ; Old IRQ vector
+MousePort:     .res    1               ; Port used for the mouse
+MouseSprite:   .res    1               ; Number of sprite to control
+OldValue:      .res    1               ; Temp for MoveCheck routine
+NewValue:      .res    1               ; Temp for MoveCheck routine
+
+Visible:       .res    1               ; Is the mouse visible?
+OldPotX:       .res    1               ; Old hw counter values
+OldPotY:       .res    1
+
+XPos:          .res    2               ; Current mouse position, X
+YPos:          .res    2               ; Current mouse position, Y
+
+XMin:          .res    2               ; X1 value of bounding box
+YMin:          .res    2               ; Y1 value of bounding box
+XMax:          .res    2               ; X2 value of bounding box
+YMax:          .res    2               ; Y2 value of bounding box
+
+.data
+
+BitMask:       .byte   $01, $02, $04, $08, $10, $20, $40, $80
+
+
+
+
+                   
diff --git a/libsrc/c64/read.s b/libsrc/c64/read.s
new file mode 100644 (file)
index 0000000..1aa40ad
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int read (int fd, void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+       .export         _read
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+       .include        "../cbm/cbm.inc"
+
+_read: jsr     popax           ; get count
+       sta     ptr2
+       stx     ptr2+1          ; save it for later
+       jsr     popax           ; get buf
+       sta     ptr1
+       stx     ptr1+1
+       jsr     popax           ; get fd and discard it
+       lda     #0
+       sta     ptr3
+       sta     ptr3+1          ; set count
+
+L1:            lda     ptr2
+       ora     ptr2+1          ; count zero?
+       beq     L9
+       jsr     BASIN
+       ldy     #0
+       sta     (ptr1),y        ; save char
+       inc     ptr1
+       bne     L2
+       inc     ptr1+1
+L2:            inc     ptr3            ; increment count
+       bne     L3
+       inc     ptr3+1
+L3:    cmp     #$0D            ; CR?
+       bne     L1
+
+; Done, return the count
+
+L9:     lda    ptr3
+       ldx     ptr3+1
+       rts
+
+
+
diff --git a/libsrc/c64/readjoy.s b/libsrc/c64/readjoy.s
new file mode 100644 (file)
index 0000000..e5bb2f1
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+       .export         _readjoy
+
+       .include        "c64.inc"
+
+
+.proc  _readjoy
+
+       tax                     ; Joystick number into X
+       bne     joy2
+
+; Read joystick 1
+
+joy1:  lda     #$7F
+       sei
+       sta     CIA1_PRA
+       lda     CIA1_PRB
+       cli
+       and     #$1F
+       eor     #$1F
+       rts
+
+; Read joystick 2
+
+joy2:  ldx     #0
+       lda     #$E0
+       ldy     #$FF
+       sta     CIA1_DDRA
+       lda     CIA1_PRA
+       sty     CIA1_DDRA
+       and     #$1F
+       eor     #$1F
+       rts
+
+.endproc
+
diff --git a/libsrc/c64/rs232.s b/libsrc/c64/rs232.s
new file mode 100644 (file)
index 0000000..e3c406f
--- /dev/null
@@ -0,0 +1,699 @@
+;
+; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
+;
+; This software is Public Domain.  It is in Buddy assembler format.
+;
+; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
+; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
+; Serial Cartridge.  Both devices are based on the 6551 ACIA chip.  It also
+; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
+;
+; The code assumes that the kernal + I/O are in context.  On the C128, call
+; it from Bank 15.  On the C64, don't flip out the Kernal unless a suitable
+; NMI catcher is put into the RAM under then Kernal.  For the SuperCPU, the
+; interrupt handling assumes that the 65816 is in 6502-emulation mode.
+;
+;--------------------------------------------------------------------------
+;
+; Adapted for the use with the cc65 runtime library by
+; Ullrich von Bassewitz (uz@musoftware.de) 02-May-1999.
+;
+; All external functions are C callable, the return value is an error code.
+;
+
+
+       .importzp       ptr1, ptr2, tmp1, tmp2
+       .import         popa, popax
+       .export         _rs232_init, _rs232_params, _rs232_done, _rs232_get
+       .export         _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
+
+
+useC64         = 1
+.if useC64
+   NmiExit  = $febc     ;exit address for nmi
+.else
+   NmiExit  = $ff33     ;exit address for nmi
+.endif
+
+ACIA           = $DE00
+
+
+
+;----------------------------------------------------------------------------
+;
+; Global variables
+;
+
+.bss
+DropCnt:       .res    4       ; Number of bytes lost from rx buffer full
+Initialized:   .res    1       ; Flag indicating driver is initialized
+Stopped:       .res    1       ; Flow-stopped flag
+RtsOff:                .res    1       ;
+Errors:                .res    1       ; Number of bytes received in error, low byte
+Turbo232:      .res    1       ; Flag indicating turbo-232
+HackedFlag:    .res    1       ; Flag indicating hacked-crystal swiftlink
+CpuSpeed:      .res    1       ; In MHz
+RecvHead:      .res    1       ; Head of receive buffer
+RecvTail:      .res    1       ; Tail of receive buffer
+RecvFreeCnt:   .res    1       ; Number of bytes in receive buffer
+SendHead:      .res    1       ; Head of send buffer
+SendTail:      .res    1       ; Tail of send buffer
+SendFreeCnt:   .res    1       ; Number of bytes free in send buffer
+BaudCode:      .res    1       ; Current baud in effect
+
+; Send and receive buffers: 256 bytes each
+RecvBuf:       .res    256
+SendBuf:       .res    256
+
+.data
+NmiContinue:   .byte   $4c     ; JMP instruction for NMI save -- continue
+NmiSave:       .res    2       ; normal NMI handler
+
+; Switftlink register offsets
+RegData                = 0     ; Data register
+RegStatus              = 1     ; Status register
+RegCommand             = 2     ; Command register
+RegControl             = 3     ; Control register
+RegClock               = 7     ; Turbo232 external baud-rate generator
+
+; Error codes. Beware: The codes must match the codes in the C header file
+ErrNotInitialized      = $01
+ErrBaudTooFast         = $02
+ErrBaudNotAvail        = $03
+ErrNoData              = $04
+ErrOverflow            = $05
+
+
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_init (char hacked);
+; /* Initialize the serial port, install the interrupt handler. The parameter
+;  * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+;  */
+;
+
+_rs232_init:
+       bit     Initialized     ;** shut down if started
+       bpl     @L1
+       pha
+       jsr     _rs232_done
+       pla
+
+;** set hacked-crystal
+
+@L1:   sta     HackedFlag
+
+;** check for turbo-232
+
+       lda     #$00
+               sta     ACIA+RegControl
+       tax
+               lda     ACIA+RegClock
+       beq     @L3
+       dex
+@L3:   stx     Turbo232
+
+;** get C128/C64 cpu speed
+.if useC64
+       lda     #1
+       sta     CpuSpeed
+.else
+       lda     $d030
+       and     #$01
+       clc
+       adc     #1
+       sta     CpuSpeed
+.endif
+
+;** check for super-cpu at 20 MHz
+
+       bit     $d0bc
+       bmi     @L4
+       bit     $d0b8
+       bvs     @L4
+       lda     #20
+       sta     CpuSpeed
+
+;** initialize buffers & control
+
+@L4:   lda     #0
+       sta     RecvHead
+       sta     SendHead
+       sta     RecvTail
+       sta     SendTail
+       sta     Errors
+       sta     Stopped
+       lda     #255
+               sta     RecvFreeCnt
+       sta     SendFreeCnt
+
+;** set up nmi's
+
+       lda     $318
+       ldy     $319
+       sta     NmiSave+0
+       sty     NmiSave+1
+       lda     #<NmiHandler
+       ldy     #>NmiHandler
+       sta     $318
+       sty     $319
+
+;** set default to 2400-8N1, enable interrupts
+
+       lda     ACIA+RegData
+       lda     ACIA+RegStatus
+       lda     #$18
+       bit     HackedFlag
+       bpl     @L5
+       lda     #$1a
+@L5:           sta     ACIA+RegControl
+
+       lda     #$01
+       sta     RtsOff
+       ora     #$08
+               sta     ACIA+RegCommand
+       lda     #$06
+       sta     BaudCode
+
+;** return
+       lda     #$ff
+       sta     Initialized
+       lda     #$00
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+; /* Set the port parameters. Use a combination of the #defined values above. */
+;
+; Set communication parameters.
+;
+; baud rates              stops     word    |   parity
+; ---------------------   -----     -----   |   ---------
+; $00=50     $08=9600     $00=1     $00=8   |   $00=none
+; $01=110    $09=19200    $80=2     $20=7   |   $20=odd
+; $02=134.5  $0a=38400              $40=6   |   $60=even
+; $03=300    $0b=57600              $60=5   |   $A0=mark
+; $04=600    $0c=115200                     |   $E0=space
+; $05=1200   $0d=230400
+; $06=2400   $0e=future
+; $07=4800   $0f=future
+;
+
+_rs232_params:
+               jsr     CheckInitialized        ;** check initialized
+               bcc     @L1
+       rts
+
+; Save new parity
+
+@L1:   and     #%11100000
+       ora     #%00000001
+       sta     tmp2
+
+; Check cpu speed against baud rate
+
+       jsr     popa
+               sta     tmp1
+       and     #$0f
+       cmp     #$0c
+       bcc     @L3
+       ldx     CpuSpeed
+       cpx     #1+1
+       bcc     @L2
+       cmp     #$0c
+       beq     @L3
+       cpx     #4
+       bcs     @L3
+@L2:   lda     #ErrBaudTooFast
+       bne     @L9
+
+; Set baud/parameters
+
+@L3:   lda     tmp1
+       and     #$0f
+       tax
+       lda     NormBauds,x
+       bit     HackedFlag
+       bpl     @L4
+       lda     HackBauds,x
+@L4:   cmp     #$ff
+       bne     @L5
+       lda     #ErrBaudNotAvail
+       bne     @L9
+
+@L5:   tax
+       and     #$30
+               beq     @L6
+       bit     Turbo232
+       bmi     @L6
+       lda     #ErrBaudNotAvail
+       bne     @L9
+
+@L6:   lda     tmp1
+       and     #$0f
+       sta     BaudCode
+       lda     tmp1
+       and     #%11100000
+       ora     #%00010000
+       sta     tmp1
+       txa
+       and     #$0f
+       ora     tmp1
+       sta     ACIA+RegControl
+       txa
+       and     #%00110000
+       beq     @L7
+       lsr
+       lsr
+       lsr
+       lsr
+       eor     #%00000011
+       sta     ACIA+RegClock
+
+; Set new parity
+
+@L7:   lda     tmp2
+       sta     RtsOff
+       ora     #%00001000
+       sta     ACIA+RegCommand
+       lda     #0
+@L9:   ldx     #0
+       rts
+
+.rodata
+
+NormBauds:
+   .byte $ff,$ff,$ff,$05,$06,$07,$08,$0a,$0c,$0e,$0f,$10,$20,$30,$ff,$ff
+HackBauds:
+   .byte $01,$03,$04,$06,$07,$08,$0a,$0c,$0e,$0f,$ff,$ff,$00,$ff,$ff,$ff
+     ;in:  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+     ;baud50 110 134   3   6  12  24  48  96  19  38  57 115 230 exp exp
+     ;out masks: $0F=Baud, val$FF=err
+     ;           $30=t232ExtBaud: $00=none, $10=57.6, $20=115.2, $30=230.4
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_done (void);
+; /* Close the port, deinstall the interrupt hander. You MUST call this function
+;  * before terminating the program, otherwise the machine may crash later. If
+;  * in doubt, install an exit handler using atexit(). The function will do
+;  * nothing, if it was already called.
+;  */
+;
+
+
+_rs232_done:
+       bit     Initialized             ;** check initialized
+               bpl     @L9
+
+; Stop interrupts, drop DTR
+
+       lda     RtsOff
+       and     #%11100010
+       ora     #%00000010
+       sta     ACIA+RegCommand
+
+; Restore NMI vector
+
+       lda     NmiSave+0
+       ldy     NmiSave+1
+       sta     $318
+       sty     $319
+
+; Flag uninitialized
+
+@L9:           lda     #$00
+       sta     Initialized
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_get (char* B);
+; /* Get a character from the serial port. If no characters are available, the
+;  * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+;  */
+;
+
+_rs232_get:
+       jsr     CheckInitialized        ; Check if initialized
+       bcc     @L1
+       rts
+
+; Check for bytes to send
+
+@L1:   sta     ptr1
+       stx     ptr1+1                  ; Store pointer to received char
+       ldx     SendFreeCnt
+       cpx     #$ff
+       beq     @L2
+       lda     #$00
+       jsr     TryToSend
+
+; Check for buffer empty
+
+@L2:   lda     RecvFreeCnt
+       cmp     #$ff
+       bne     @L3
+       lda     #ErrNoData
+       ldx     #0
+       rts
+
+; Check for flow stopped & enough free: release flow control
+
+@L3:   ldx     Stopped
+       beq     @L4
+       cmp     #63
+       bcc     @L4
+       lda     #$00
+       sta     Stopped
+       lda     RtsOff
+       ora     #%00001000
+       sta     ACIA+RegCommand
+
+; Get byte from buffer
+
+@L4:   ldx     RecvHead
+               lda     RecvBuf,x
+       inc     RecvHead
+       inc     RecvFreeCnt
+               ldx     #$00
+       sta     (ptr1,x)
+               txa                             ; Return code = 0
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_put (char B);
+; /* Send a character via the serial port. There is a transmit buffer, but
+;  * transmitting is not done via interrupt. The function returns
+;  * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+;  */
+;
+
+_rs232_put:
+       jsr     CheckInitialized        ; Check initialized
+       bcc     @L1
+       rts
+
+; Try to send
+
+@L1:   ldx     SendFreeCnt
+       cpx     #$ff
+       beq     @L2
+       pha
+       lda     #$00
+       jsr     TryToSend
+       pla
+
+; Put byte into send buffer & send
+
+@L2:   ldx     SendFreeCnt
+       bne     @L3
+       lda     #ErrOverflow
+       ldx     #$00
+       rts
+
+@L3:   ldx     SendTail
+       sta     SendBuf,x
+       inc     SendTail
+       dec     SendFreeCnt
+       lda     #$ff
+       jsr     TryToSend
+       lda     #$00
+       tax
+               rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_pause (void);
+; /* Assert flow control and disable interrupts. */
+;
+
+_rs232_pause:
+; Check initialized
+       jsr     CheckInitialized
+       bcc     @L1
+       rts
+
+; Assert flow control
+
+@L1:   lda     RtsOff
+       sta     Stopped
+       sta     ACIA+RegCommand
+
+; Delay for flow stop to be received
+
+       ldx     BaudCode
+       lda     PauseTimes,x
+       jsr     DelayMs
+
+; Stop rx interrupts
+
+       lda     RtsOff
+       ora     #$02
+       sta     ACIA+RegCommand
+       lda     #0
+       tax
+       rts
+
+
+.rodata
+; Delay times: 32 byte-receive times in milliseconds, or 100 max.
+; Formula = 320,000 / baud
+PauseTimes:
+               .byte 100,100,100,100,100,100,100,067,034,017,009,006,003,002,001,001
+          ;in:  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+          ;baud50 110 134   3   6  12  24  48  96  19  38  57 115 230 exp exp
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_unpause (void);
+; /* Re-enable interrupts and release flow control */
+;
+
+_rs232_unpause:
+; Check initialized
+       jsr     CheckInitialized
+       bcc     @L1
+       rts
+
+; Re-enable rx interrupts & release flow control
+
+@L1:   lda     #$00
+       sta     Stopped
+       lda     RtsOff
+       ora     #%00001000
+       sta     ACIA+RegCommand
+
+; Poll for stalled char & exit
+
+       jsr     PollReceive
+       lda     #0
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_status (unsigned char* status,
+;                                         unsigned char* errors);
+; /* Return the serial port status. */
+;
+
+_rs232_status:
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax
+       sta     ptr1
+       stx     ptr1+1
+       jsr     CheckInitialized
+               bcs     @L9
+
+; Get status
+
+       lda     ACIA+RegStatus
+       ldy     #0
+       sta     (ptr1),y
+       jsr     PollReceive             ; bug-recovery hack
+       lda     Errors
+               sta     (ptr2),y
+       tya
+       tax
+@L9:   rts
+
+;----------------------------------------------------------------------------
+;
+; NMI handler
+; C128 NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=33, ROMexit=30
+; C64  NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=34, ROMexit=29
+;
+; timing: normal=76+43+9=128 cycles, assertFlow=76+52+9=137 cycles
+;
+; C128 @ 115.2k: 177 cycles avail (fast)
+; C64  @  57.6k: 177 cycles avail, worstAvail=177-43? = 134
+; SCPU @ 230.4k: 868 cycles avail: for a joke!
+;
+
+NmiHandler:
+.if useC64
+       pha
+               lda     ACIA+RegStatus          ;(4) ;status ;check for byte received
+       and     #$08                    ;(2)
+               beq     @L9                     ;(2*)
+       cld
+       txa
+       pha
+       tya
+       pha
+.else
+               lda     ACIA+RegStatus          ;(4) ;status ;check for byte received
+       and     #$08                    ;(2)
+       beq     NmiNorm                 ;(2*)
+.endif
+               lda     ACIA+RegStatus          ;(4) opt ;status ;check for receive errors
+       and     #$07                    ;(2) opt
+               beq     @L1                     ;(3*)opt
+       inc     Errors                  ;(5^)opt
+@L1:   lda     ACIA+RegData            ;(4) ;data  ;get byte and put into receive buffer
+       ldy     RecvTail                ;(4)
+       ldx     RecvFreeCnt             ;(4)
+       beq     @L3                     ;(2*)
+       sta     RecvBuf,y               ;(5)
+       inc     RecvTail                ;(6)
+       dec     RecvFreeCnt             ;(6)
+       cpx     #33                     ;(2)  ;check for buffer space low
+               bcc     @L2                     ;(2*)
+       jmp     NmiExit                 ;(3)
+
+; Assert flow control
+
+@L2:   lda     RtsOff                  ;(3)  ;assert flow control if buffer space too low
+       sta     ACIA+RegCommand ;(4) ;command
+       sta     Stopped                 ;(3)
+       jmp     NmiExit                 ;(3)
+
+; Drop this char
+
+@L3:   inc     DropCnt+0               ;not time-critical
+       bne     @L4
+       inc     DropCnt+1
+       bne     @L4
+       inc     DropCnt+2
+       bne     @L4
+       inc     DropCnt+3
+@L4:           jmp     NmiExit
+
+@L9:
+.if useC64
+   pla
+.endif
+   jmp NmiContinue
+
+;----------------------------------------------------------------------------
+;
+; CheckInitialized  -  internal check if initialized
+; Set carry and an error code if not initialized, clear carry and do not
+; change any registers if initialized.
+;
+
+CheckInitialized:
+       bit     Initialized
+       bmi     @L1
+       lda     #ErrNotInitialized
+       ldx     #0
+       sec
+       rts
+
+@L1:   clc
+       rts
+
+;----------------------------------------------------------------------------
+; Try to send a byte. Internal routine. A = TryHard
+
+TryToSend:
+       sta     tmp1            ; Remember tryHard flag
+@L0:           lda     SendFreeCnt
+       cmp     #$ff
+       beq     @L3             ; Bail out
+
+; Check for flow stopped
+
+@L1:   lda     Stopped
+               bne     @L3             ; Bail out
+
+;** check that swiftlink is ready to send
+
+@L2:           lda     ACIA+RegStatus
+       and     #$10
+       bne     @L4
+       bit     tmp1            ;keep trying if must try hard
+               bmi     @L0
+@L3:   rts
+
+;** send byte and try again
+
+@L4:   ldx     SendHead
+       lda     SendBuf,x
+       sta     ACIA+RegData
+       inc     SendHead
+       inc     SendFreeCnt
+       jmp     @L0
+
+
+;----------------------------------------------------------------------------
+;
+; PollReceive - poll for rx char
+;   This function is useful in odd cases where the 6551 has a character in
+;   it but it fails to raise an NMI.  It might be edge-triggering conditions?
+;   Actually, I'm not entirely sure that this condition can still arrise, but
+;   calling this function does no harm.
+;
+
+PollReceive:
+       lda     #$08
+       and     ACIA+RegStatus
+       beq     @L9
+               and     ACIA+RegStatus
+       beq     @L9
+               lda     ACIA+RegData
+       ldx     RecvFreeCnt
+       beq     @L9
+       ldx     RecvTail
+       sta     RecvBuf,x
+       inc     RecvTail
+       dec     RecvFreeCnt
+@L9:   rts
+
+;----------------------------------------------------------------------------
+;
+;  DelayMs : delay for given number of milliseconds
+;    This implementation isn't very rigerous; it merely delays for the
+;    approximate number of clock cycles for the processor speed.
+;    Algorithm:
+;       repeat for number of milliseconds:
+;          repeat for number of MHz of cpu speed:
+;             delay for 1017 clock cycles
+;
+
+DelayMs:                       ;( .A=milliseconds )
+@L1:   ldy     CpuSpeed
+@L2:           ldx     #203            ;(2)
+@L3:           dex                     ;(2)
+       bne     @L3             ;(3) // 1017 cycles
+       dey
+       bne     @L2
+       sec
+       sbc     #1
+       bne     @L1
+       rts
+
+.end
+
+
+
diff --git a/libsrc/c64/write.s b/libsrc/c64/write.s
new file mode 100644 (file)
index 0000000..9a574f3
--- /dev/null
@@ -0,0 +1,47 @@
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int write (int fd, const void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+       .export         _write
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+       .include        "../cbm/cbm.inc"
+
+_write:        jsr     popax           ; get count
+               sta     ptr2
+       stx     ptr2+1          ; save it for later
+       sta     ptr3
+       stx     ptr3+1          ; save for function result
+       jsr     popax           ; get buf
+       sta     ptr1
+       stx     ptr1+1
+       jsr     popax           ; get fd and discard it
+
+L1:    lda     ptr2
+       ora     ptr2+1          ; count zero?
+       beq     L9
+       ldy     #0
+       lda     (ptr1),y
+       jsr     BSOUT
+       inc     ptr1
+       bne     L2
+       inc     ptr1+1
+L2:    lda     ptr2
+       bne     L3
+       dec     ptr2
+       dec     ptr2+1
+       jmp     L1
+L3:    dec     ptr2
+       jmp     L1
+
+; No error, return count
+
+L9:    lda     ptr3
+       ldx     ptr3+1
+       rts
+
diff --git a/libsrc/cbm/Makefile b/libsrc/cbm/Makefile
new file mode 100644 (file)
index 0000000..9093a8b
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = ctype.o getenv.o gotoxy.o gotox.o gotoy.o where.o\
+        clock.o chline.o cvline.o cclear.o revers.o\
+        c_readst.o c_close.o c_open.o c_ckout.o c_clrch.o c_bsout.o\
+        c_basin.o c_clall.o c_iobase.o c_setnam.o c_setlfs.o c_acptr.o\
+        c_ciout.o c_untlk.o c_unlsn.o c_listen.o c_talk.o c_load.o\
+        oserror.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f *~
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+
diff --git a/libsrc/cbm/c_acptr.s b/libsrc/cbm/c_acptr.s
new file mode 100644 (file)
index 0000000..d77d6f1
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned char __fastcall__ cbm_acptr (void);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_acptr
+
+_cbm_acptr:
+       jsr     ACPTR
+       ldx     #0
+       rts
+
+                    
diff --git a/libsrc/cbm/c_basin.s b/libsrc/cbm/c_basin.s
new file mode 100644 (file)
index 0000000..281f433
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned char __fastcall__ cbm_basin (void);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_basin
+
+_cbm_basin:
+       jsr     BASIN
+       ldx     #0
+       rts
+
+
diff --git a/libsrc/cbm/c_bsout.s b/libsrc/cbm/c_bsout.s
new file mode 100644 (file)
index 0000000..a2c682b
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_bsout (unsigned char C);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_bsout
+
+_cbm_bsout = BSOUT
+
+
+
diff --git a/libsrc/cbm/c_ciout.s b/libsrc/cbm/c_ciout.s
new file mode 100644 (file)
index 0000000..b2c149f
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_ciout (unsigned char C);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_ciout
+
+_cbm_ciout = CIOUT
+
+
diff --git a/libsrc/cbm/c_ckout.s b/libsrc/cbm/c_ckout.s
new file mode 100644 (file)
index 0000000..7fffe9f
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_ckout (unsigned char FN);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_ckout
+
+_cbm_ckout:
+       tax
+               jsr     CKOUT
+       ldx     #0
+       bcc     @Ok
+       inx
+       rts
+@Ok:   txa
+       rts
+
+
+
+
+
diff --git a/libsrc/cbm/c_clall.s b/libsrc/cbm/c_clall.s
new file mode 100644 (file)
index 0000000..d7c5625
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_clall (void);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_clall
+
+_cbm_clall = CLALL
+
+
diff --git a/libsrc/cbm/c_close.s b/libsrc/cbm/c_close.s
new file mode 100644 (file)
index 0000000..72cbded
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_close (unsigned char FN);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_close
+
+_cbm_close:
+               clc
+               jmp     CLOSE
+
+
diff --git a/libsrc/cbm/c_clrch.s b/libsrc/cbm/c_clrch.s
new file mode 100644 (file)
index 0000000..ba76b58
--- /dev/null
@@ -0,0 +1,12 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_clrch (void);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_clrch
+
+_cbm_clrch = CLRCH
+
diff --git a/libsrc/cbm/c_iobase.s b/libsrc/cbm/c_iobase.s
new file mode 100644 (file)
index 0000000..58fb159
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_iobase (void);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_iobase
+
+_cbm_iobase:
+       jsr     IOBASE
+       txa
+       pha
+       tya
+       tax
+       pla
+       rts
+
+
diff --git a/libsrc/cbm/c_listen.s b/libsrc/cbm/c_listen.s
new file mode 100644 (file)
index 0000000..a5cc4e0
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_listen (unsigned char dev);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_listen
+
+_cbm_listen = LISTEN
+
+
+
+
+
diff --git a/libsrc/cbm/c_load.s b/libsrc/cbm/c_load.s
new file mode 100644 (file)
index 0000000..16aec28
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_load (unsigned char flag, unsigned addr);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_load
+       .import         popa
+       .importzp       ptr1
+
+_cbm_load:
+       sta     ptr1
+       stx     ptr1+1      
+       jsr     popa            ; get flag
+       ldx     ptr1
+       ldy     ptr1+1
+       jsr     LOAD
+       ldx     #0
+       bcc     @Ok
+       inx
+       rts
+@Ok:   txa
+       rts
+
diff --git a/libsrc/cbm/c_open.s b/libsrc/cbm/c_open.s
new file mode 100644 (file)
index 0000000..559f907
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_open (void);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_open
+
+_cbm_open:
+       jsr     OPEN
+       ldx     #0
+       bcc     @Ok
+       inx
+       rts
+@Ok:   txa
+       rts
+
diff --git a/libsrc/cbm/c_readst.s b/libsrc/cbm/c_readst.s
new file mode 100644 (file)
index 0000000..bb1b42a
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_readst (void);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_readst
+
+_cbm_readst:
+       jsr     READST
+       ldx     #0
+       rts
+
diff --git a/libsrc/cbm/c_setlfs.s b/libsrc/cbm/c_setlfs.s
new file mode 100644 (file)
index 0000000..a8bc6f8
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_setlfs (unsigned char LFN,
+;                              unsigned char DEV,
+;                              unsigned char SA);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_setlfs
+       .import         popa
+       .importzp       tmp1
+
+_cbm_setlfs:
+       sta     tmp1            ; Save SA
+       jsr     popa            ; Get DEV
+       tax
+       jsr     popa            ; Get LFN
+       ldy     tmp1            ; Get SA
+       jmp     SETLFS
+
+
diff --git a/libsrc/cbm/c_setnam.s b/libsrc/cbm/c_setnam.s
new file mode 100644 (file)
index 0000000..ed59713
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_setnam (const char* Name);
+;
+
+               .include        "cbm.inc"
+
+               .export         _cbm_setnam
+       .importzp       ptr1
+
+_cbm_setnam:
+       sta     ptr1            ; Store pointer to file name
+       stx     ptr1+1
+       ldy     #$FF
+@Loop: iny                     ; Get length of name
+       lda     (ptr1),y
+       bne     @Loop
+
+       tya                     ; Length
+       ldx     ptr1
+       ldy     ptr1+1
+       jmp     SETNAM
+
diff --git a/libsrc/cbm/c_talk.s b/libsrc/cbm/c_talk.s
new file mode 100644 (file)
index 0000000..d9d7099
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_talk (unsigned char dev);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_talk
+
+_cbm_talk = TALK
+
+
+
+
+
+
+
diff --git a/libsrc/cbm/c_unlsn.s b/libsrc/cbm/c_unlsn.s
new file mode 100644 (file)
index 0000000..bcf4e0b
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_unlsn (void);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_unlsn
+
+_cbm_unlsn = UNLSN
+
+
+
+
+
diff --git a/libsrc/cbm/c_untlk.s b/libsrc/cbm/c_untlk.s
new file mode 100644 (file)
index 0000000..4417188
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_untlk (void);
+;
+
+       .include        "cbm.inc"
+
+               .export         _cbm_untlk
+
+_cbm_untlk = UNTLK
+
+
diff --git a/libsrc/cbm/cbm.inc b/libsrc/cbm/cbm.inc
new file mode 100644 (file)
index 0000000..26644c5
--- /dev/null
@@ -0,0 +1,46 @@
+;
+; Subroutines available in the CBM jump table
+;
+
+
+CINT           = $FF81
+IOINIT         = $FF84
+RAMTAS         = $FF87
+RESTOR         = $FF8A
+VECTOR         = $FF8D
+SETMSG         = $FF90
+SECOND         = $FF93
+TKSA           = $FF96
+MEMTOP         = $FF99
+MEMBOT         = $FF9C
+SCNKEY         = $FF9F
+SETTMO         = $FFA2
+ACPTR          = $FFA5
+CIOUT          = $FFA8
+UNTLK          = $FFAB
+UNLSN          = $FFAE
+LISTEN         = $FFB1
+TALK           = $FFB4
+READST         = $FFB7
+SETLFS         = $FFBA
+SETNAM         = $FFBD
+OPEN           = $FFC0
+CLOSE          = $FFC3
+CHKIN          = $FFC6
+CKOUT          = $FFC9
+CLRCH          = $FFCC
+BASIN          = $FFCF
+BSOUT          = $FFD2
+LOAD           = $FFD5
+SAVE           = $FFD8
+SETTIM         = $FFDB
+RDTIM          = $FFDE
+STOP           = $FFE1
+GETIN          = $FFE4
+CLALL          = $FFE7
+UDTIM          = $FFEA
+SCREEN         = $FFED
+PLOT           = $FFF0
+IOBASE         = $FFF3
+
+
diff --git a/libsrc/cbm/cclear.s b/libsrc/cbm/cclear.s
new file mode 100644 (file)
index 0000000..586459c
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+       .export         _cclearxy, _cclear
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_cclearxy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+               pla                     ; Restore the length and run into _cclear
+
+_cclear:
+               cmp     #0              ; Is the length zero?
+               beq     L9              ; Jump if done
+       sta     tmp1                                 
+L1:            lda     #$20            ; Blank - screen code
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/cbm/chline.s b/libsrc/cbm/chline.s
new file mode 100644 (file)
index 0000000..26be1c7
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+       .export         _chlinexy, _chline
+       .import         popa, _gotoxy, cputdirect
+       .importzp       tmp1
+
+_chlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length
+
+_chline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+L1:            lda     #64             ; Horizontal line, screen code
+       jsr     cputdirect      ; Direct output
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
+
diff --git a/libsrc/cbm/clock.s b/libsrc/cbm/clock.s
new file mode 100644 (file)
index 0000000..8df03dc
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 21.09.1998
+;
+; clock_t clock (void);
+;
+
+       .export         _clock
+       .importzp       sreg
+
+       .include        "cbm.inc"
+
+
+.proc  _clock
+
+       lda     #0              ; Byte 3 is always zero
+               sta     ::sreg+1
+       jsr     RDTIM
+       sty     ::sreg
+       rts                     ; Don't set CC, this has no meaning here
+
+.endproc
+
diff --git a/libsrc/cbm/ctype.s b/libsrc/cbm/ctype.s
new file mode 100644 (file)
index 0000000..e5f7703
--- /dev/null
@@ -0,0 +1,311 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to a lower case char to make it an upper case
+; char (example: for ASCII, this must be $E0).
+
+
+       .export         __cdiff
+
+__cdiff:
+       .byte   $80
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+;   * It is fast. If it were'nt for the slow parameter passing of cc65, one
+;     could even define macros for the isxxx functions (this is usually
+;     done on other platforms).
+;
+;   * It is highly portable. The only unportable part is the table itself,
+;     all real code goes into the common library.
+;
+;   * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+;   0 - Lower case char
+;   1 - Upper case char
+;   2 - Numeric digit
+;   3 - Hex digit (both, lower and upper)
+;   4 - Control character
+;   5 - The space character itself
+;   6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+;   7 - Space or tab character
+
+
+; The table is taken from Craig S. Bruce technical docs for the ACE os
+
+       .export         __ctype
+
+__ctype:
+       .byte   $10     ;   0/00 ___rvs_@___
+       .byte   $10     ;   1/01 ___rvs_a___
+       .byte   $10     ;   2/02 ___rvs_b___
+       .byte   $10     ;   3/03 ___rvs_c___
+       .byte   $10     ;   4/04 ___rvs_d___
+       .byte   $10     ;   5/05 ___rvs_e___
+       .byte   $10     ;   6/06 ___rvs_f___
+       .byte   $10     ;   7/07 _BEL/rvs_g_
+       .byte   $10     ;   8/08 ___rvs_h___
+               .byte   $D0     ;   9/09 _TAB/rvs_i_
+       .byte   $50     ;  10/0a _BOL/rvs_j_
+       .byte   $10     ;  11/0b ___rvs_k___
+       .byte   $10     ;  12/0c ___rvs_l___
+       .byte   $50     ;  13/0d _CR_/rvs_m_
+       .byte   $10     ;  14/0e ___rvs_n___
+       .byte   $10     ;  15/0f ___rvs_o___
+       .byte   $10     ;  16/10 ___rvs_p___
+       .byte   $50     ;  17/11 _VT_/rvs_q_
+       .byte   $10     ;  18/12 ___rvs_r___
+       .byte   $10     ;  19/13 ___rvs_s___
+       .byte   $50     ;  20/14 _BS_/rvs_t_
+       .byte   $10     ;  21/15 ___rvs_u___
+       .byte   $10     ;  22/16 ___rvs_v___
+       .byte   $10     ;  23/17 ___rvs_w___
+       .byte   $10     ;  24/18 ___rvs_x___
+       .byte   $10     ;  25/19 ___rvs_y___
+       .byte   $10     ;  26/1a ___rvs_z___
+       .byte   $10     ;  27/1b ___rvs_[___
+       .byte   $10     ;  28/1c ___rvs_\___
+       .byte   $10     ;  29/1d ___rvs_]___
+       .byte   $10     ;  30/1e ___rvs_^___
+       .byte   $10     ;  31/1f _rvs_under_
+               .byte   $A0     ;  32/20 ___SPACE___
+       .byte   $00     ;  33/21 _____!_____
+       .byte   $00     ;  34/22 _____"_____
+       .byte   $00     ;  35/23 _____#_____
+       .byte   $00     ;  36/24 _____$_____
+       .byte   $00     ;  37/25 _____%_____
+       .byte   $00     ;  38/26 _____&_____
+       .byte   $00     ;  39/27 _____'_____
+       .byte   $00     ;  40/28 _____(_____
+       .byte   $00     ;  41/29 _____)_____
+       .byte   $00     ;  42/2a _____*_____
+       .byte   $00     ;  43/2b _____+_____
+       .byte   $00     ;  44/2c _____,_____
+       .byte   $00     ;  45/2d _____-_____
+       .byte   $00     ;  46/2e _____._____
+       .byte   $00     ;  47/2f _____/_____
+       .byte   $0C     ;  48/30 _____0_____
+       .byte   $0C     ;  49/31 _____1_____
+       .byte   $0C     ;  50/32 _____2_____
+       .byte   $0C     ;  51/33 _____3_____
+       .byte   $0C     ;  52/34 _____4_____
+       .byte   $0C     ;  53/35 _____5_____
+       .byte   $0C     ;  54/36 _____6_____
+       .byte   $0C     ;  55/37 _____7_____
+       .byte   $0C     ;  56/38 _____8_____
+       .byte   $0C     ;  57/39 _____9_____
+       .byte   $00     ;  58/3a _____:_____
+       .byte   $00     ;  59/3b _____;_____
+       .byte   $00     ;  60/3c _____<_____
+       .byte   $00     ;  61/3d _____=_____
+       .byte   $00     ;  62/3e _____>_____
+       .byte   $00     ;  63/3f _____?_____
+
+       .byte   $00     ;  64/40 _____@_____
+               .byte   $09     ;  65/41 _____a_____
+       .byte   $09     ;  66/42 _____b_____
+       .byte   $09     ;  67/43 _____c_____
+       .byte   $09     ;  68/44 _____d_____
+       .byte   $09     ;  69/45 _____e_____
+       .byte   $09     ;  70/46 _____f_____
+       .byte   $01     ;  71/47 _____g_____
+       .byte   $01     ;  72/48 _____h_____
+       .byte   $01     ;  73/49 _____i_____
+       .byte   $01     ;  74/4a _____j_____
+       .byte   $01     ;  75/4b _____k_____
+       .byte   $01     ;  76/4c _____l_____
+       .byte   $01     ;  77/4d _____m_____
+       .byte   $01     ;  78/4e _____n_____
+       .byte   $01     ;  79/4f _____o_____
+       .byte   $01     ;  80/50 _____p_____
+       .byte   $01     ;  81/51 _____q_____
+       .byte   $01     ;  82/52 _____r_____
+       .byte   $01     ;  83/53 _____s_____
+       .byte   $01     ;  84/54 _____t_____
+       .byte   $01     ;  85/55 _____u_____
+       .byte   $01     ;  86/56 _____v_____
+       .byte   $01     ;  87/57 _____w_____
+       .byte   $01     ;  88/58 _____x_____
+       .byte   $01     ;  89/59 _____y_____
+       .byte   $01     ;  90/5a _____z_____
+       .byte   $00     ;  91/5b _____[_____
+       .byte   $00     ;  92/5c _____\_____
+       .byte   $00     ;  93/5d _____]_____
+       .byte   $00     ;  94/5e _____^_____
+       .byte   $00     ;  95/5f _UNDERLINE_
+       .byte   $00     ;  96/60 _A`_grave__
+       .byte   $00     ;  97/61 _A'_acute__
+       .byte   $00     ;  98/62 _A^_circum_
+       .byte   $00     ;  99/63 _A~_tilde__
+       .byte   $00     ; 100/64 _A"_dieres_
+       .byte   $00     ; 101/65 _A__ring___
+       .byte   $00     ; 102/66 _AE________
+       .byte   $00     ; 103/67 _C,cedilla_
+       .byte   $00     ; 104/68 _E`_grave__
+       .byte   $00     ; 105/69 _E'_acute__
+       .byte   $00     ; 106/6a _E^_circum_
+       .byte   $00     ; 107/6b _E"_dieres_
+       .byte   $00     ; 108/6c _I`_grave__
+       .byte   $00     ; 109/6d _I'_acute__
+       .byte   $00     ; 110/6e _I^_circum_
+       .byte   $00     ; 111/6f _I"_dieres_
+       .byte   $00     ; 112/70 _D-_Eth_lr_
+       .byte   $00     ; 113/71 _N~_tilde__
+       .byte   $00     ; 114/72 _O`_grave__
+       .byte   $00     ; 115/73 _O'_acute__
+       .byte   $00     ; 116/74 _O^_circum_
+       .byte   $00     ; 117/75 _O~_tilde__
+       .byte   $00     ; 118/76 _O"_dieres_
+       .byte   $00     ; 119/77 __multiply_
+       .byte   $00     ; 120/78 _O/_slash__
+       .byte   $00     ; 121/79 _U`_grave__
+       .byte   $00     ; 122/7a _U'_acute__
+       .byte   $00     ; 123/7b _U^_circum_
+       .byte   $00     ; 124/7c _U"_dieres_
+       .byte   $00     ; 125/7d _Y'_acute__
+       .byte   $00     ; 126/7e _cap_thorn_
+       .byte   $00     ; 127/7f _Es-sed_B__
+
+       .byte   $00     ; 128/80 __bullet___
+       .byte   $00     ; 129/81 __v_line___
+       .byte   $00     ; 130/82 __h_line___
+       .byte   $00     ; 131/83 ___cross___
+       .byte   $00     ; 132/84 _tl_corner_
+       .byte   $00     ; 133/85 _tr_corner_
+       .byte   $00     ; 134/86 _bl_corner_
+       .byte   $00     ; 135/87 _br_corner_
+       .byte   $00     ; 136/88 ___l_tee___
+       .byte   $00     ; 137/89 ___r_tee___
+       .byte   $00     ; 138/8a ___t_tee___
+       .byte   $00     ; 139/8b ___b_tee___
+       .byte   $00     ; 140/8c ___heart___
+       .byte   $00     ; 141/8d __diamond__
+       .byte   $00     ; 142/8e ___club____
+       .byte   $00     ; 143/8f ___spade___
+       .byte   $00     ; 144/90 _s_circle__
+       .byte   $00     ; 145/91 __circle___
+       .byte   $00     ; 146/92 ___pound___
+       .byte   $10     ; 147/93 _CLS/check_
+       .byte   $00     ; 148/94 ____pi_____
+       .byte   $00     ; 149/95 ____+/-____
+       .byte   $00     ; 150/96 __divide___
+       .byte   $00     ; 151/97 __degree___
+       .byte   $00     ; 152/98 _c_checker_
+       .byte   $00     ; 153/99 _f_checker_
+       .byte   $00     ; 154/9a _solid_sq__
+       .byte   $00     ; 155/9b __cr_char__
+       .byte   $00     ; 156/9c _up_arrow__
+       .byte   $00     ; 157/9d _down_arro_
+       .byte   $00     ; 158/9e _left_arro_
+       .byte   $00     ; 159/9f _right_arr_
+       .byte   $00     ; 160/a0 _req space_
+       .byte   $00     ; 161/a1 _!_invertd_
+       .byte   $00     ; 162/a2 ___cent____
+       .byte   $00     ; 163/a3 ___pound___
+       .byte   $00     ; 164/a4 __currency_
+       .byte   $00     ; 165/a5 ____yen____
+       .byte   $00     ; 166/a6 _|_broken__
+       .byte   $00     ; 167/a7 __section__
+       .byte   $00     ; 168/a8 __umulaut__
+       .byte   $00     ; 169/a9 _copyright_
+       .byte   $00     ; 170/aa __fem_ord__
+       .byte   $00     ; 171/ab _l_ang_quo_
+       .byte   $00     ; 172/ac ____not____
+       .byte   $00     ; 173/ad _syl_hyphn_
+       .byte   $00     ; 174/ae _registerd_
+       .byte   $00     ; 175/af _overline__
+       .byte   $00     ; 176/b0 __degrees__
+       .byte   $00     ; 177/b1 ____+/-____
+       .byte   $00     ; 178/b2 _2_supersc_
+       .byte   $00     ; 179/b3 _3_supersc_
+       .byte   $00     ; 180/b4 ___acute___
+       .byte   $00     ; 181/b5 ____mu_____
+       .byte   $00     ; 182/b6 _paragraph_
+       .byte   $00     ; 183/b7 __mid_dot__
+       .byte   $00     ; 184/b8 __cedilla__
+       .byte   $00     ; 185/b9 _1_supersc_
+       .byte   $00     ; 186/ba __mas_ord__
+       .byte   $00     ; 187/bb _r_ang_quo_
+       .byte   $00     ; 188/bc ____1/4____
+       .byte   $00     ; 189/bd ____1/2____
+       .byte   $00     ; 190/be ____3/4____
+       .byte   $00     ; 191/bf _?_invertd_
+
+       .byte   $00     ; 192/c0 _____`_____
+       .byte   $0A     ; 193/c1 _____A_____
+       .byte   $0A     ; 194/c2 _____B_____
+       .byte   $0A     ; 195/c3 _____C_____
+       .byte   $0A     ; 196/c4 _____D_____
+       .byte   $0A     ; 197/c5 _____E_____
+       .byte   $0A     ; 198/c6 _____F_____
+       .byte   $02     ; 199/c7 _____G_____
+       .byte   $02     ; 200/c8 _____H_____
+       .byte   $02     ; 201/c9 _____I_____
+       .byte   $02     ; 202/ca _____J_____
+       .byte   $02     ; 203/cb _____K_____
+       .byte   $02     ; 204/cc _____L_____
+       .byte   $02     ; 205/cd _____M_____
+       .byte   $02     ; 206/ce _____N_____
+       .byte   $02     ; 207/cf _____O_____
+       .byte   $02     ; 208/d0 _____P_____
+       .byte   $02     ; 209/d1 _____Q_____
+       .byte   $02     ; 210/d2 _____R_____
+       .byte   $02     ; 211/d3 _____S_____
+       .byte   $02     ; 212/d4 _____T_____
+       .byte   $02     ; 213/d5 _____U_____
+       .byte   $02     ; 214/d6 _____V_____
+       .byte   $02     ; 215/d7 _____W_____
+       .byte   $02     ; 216/d8 _____X_____
+       .byte   $02     ; 217/d9 _____Y_____
+       .byte   $02     ; 218/da _____Z_____
+       .byte   $00     ; 219/db _____{_____
+       .byte   $00     ; 220/dc _____|_____
+       .byte   $00     ; 221/dd _____}_____
+       .byte   $00     ; 222/de _____~_____
+       .byte   $00     ; 223/df ___HOUSE___
+       .byte   $00     ; 224/e0 _a`_grave__
+       .byte   $00     ; 225/e1 _a'_acute__
+       .byte   $00     ; 226/e2 _a^_circum_
+       .byte   $00     ; 227/e3 _a~_tilde__
+       .byte   $00     ; 228/e4 _a"_dieres_
+       .byte   $00     ; 229/e5 _a__ring___
+       .byte   $00     ; 230/e6 _ae________
+       .byte   $00     ; 231/e7 _c,cedilla_
+       .byte   $00     ; 232/e8 _e`_grave__
+       .byte   $00     ; 233/e9 _e'_acute__
+       .byte   $00     ; 234/ea _e^_circum_
+       .byte   $00     ; 235/eb _e"_dieres_
+       .byte   $00     ; 236/ec _i`_grave__
+       .byte   $00     ; 237/ed _i'_acute__
+       .byte   $00     ; 238/ee _i^_circum_
+       .byte   $00     ; 239/ef _i"_dieres_
+       .byte   $00     ; 240/f0 _o^x_Eth_s_
+       .byte   $00     ; 241/f1 _n~_tilda__
+       .byte   $00     ; 242/f2 _o`_grave__
+       .byte   $00     ; 243/f3 _o'_acute__
+       .byte   $00     ; 244/f4 _o^_circum_
+       .byte   $00     ; 245/f5 _o~_tilde__
+       .byte   $00     ; 246/f6 _o"_dieres_
+       .byte   $00     ; 247/f7 __divide___
+       .byte   $00     ; 248/f8 _o/_slash__
+       .byte   $00     ; 249/f9 _u`_grave__
+       .byte   $00     ; 250/fa _u'_acute__
+       .byte   $00     ; 251/fb _u^_circum_
+       .byte   $00     ; 252/fc _u"_dieres_
+       .byte   $00     ; 253/fd _y'_acute__
+       .byte   $00     ; 254/fe _sm_thorn__
+       .byte   $00     ; 255/ff _y"_dieres_
+
diff --git a/libsrc/cbm/cvline.s b/libsrc/cbm/cvline.s
new file mode 100644 (file)
index 0000000..151a492
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+       .export         _cvlinexy, _cvline
+       .import         popa, _gotoxy, putchar, newline
+       .importzp       tmp1
+
+_cvlinexy:
+               pha                     ; Save the length
+       jsr     popa            ; Get y
+               jsr     _gotoxy         ; Call this one, will pop params
+       pla                     ; Restore the length and run into _cvline
+
+_cvline:
+       cmp     #0              ; Is the length zero?
+       beq     L9              ; Jump if done
+       sta     tmp1
+L1:    lda     #93             ; Vertical bar
+       jsr     putchar         ; Write, no cursor advance
+       jsr     newline         ; Advance cursor to next line
+       dec     tmp1
+       bne     L1
+L9:    rts
+
+
+
diff --git a/libsrc/cbm/getenv.s b/libsrc/cbm/getenv.s
new file mode 100644 (file)
index 0000000..ea527dd
--- /dev/null
@@ -0,0 +1,11 @@
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; char* getenv (const char* name);
+;
+
+       .export         _getenv
+       .import         return0
+
+_getenv        = return0               ; "not found"
+
diff --git a/libsrc/cbm/gotox.s b/libsrc/cbm/gotox.s
new file mode 100644 (file)
index 0000000..25de6c3
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; void gotox (unsigned char x);
+;
+
+       .export         _gotox
+       .import         plot           
+       .importzp       CURS_X
+
+_gotox:        sta     CURS_X          ; Set new position
+       jmp     plot            ; And activate it
+
+
+
diff --git a/libsrc/cbm/gotoxy.s b/libsrc/cbm/gotoxy.s
new file mode 100644 (file)
index 0000000..cce95ae
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+
+       .export         _gotoxy
+       .import         popa, plot
+       .importzp       CURS_X, CURS_Y
+
+_gotoxy:
+       sta     CURS_Y          ; Set Y
+       jsr     popa            ; Get X
+       sta     CURS_X          ; Set X
+       jmp     plot            ; Set the cursor position
+
+
diff --git a/libsrc/cbm/gotoy.s b/libsrc/cbm/gotoy.s
new file mode 100644 (file)
index 0000000..7779b54
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 0.08.1998
+;
+; void gotoy (unsigned char y);
+;
+
+       .export         _gotoy
+       .import         plot
+       .importzp       CURS_Y
+
+_gotoy:        sta     CURS_Y          ; Set the new position
+       jmp     plot            ; And activate it
+
diff --git a/libsrc/cbm/oserror.s b/libsrc/cbm/oserror.s
new file mode 100644 (file)
index 0000000..0a7ed6e
--- /dev/null
@@ -0,0 +1,77 @@
+;
+; Ullrich von Bassewitz, 17.05.2000
+;
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+; /* Map a system specific error into a system independent code */
+;
+
+       .export         __osmaperrno
+       .include        "../common/errno.inc"
+
+.code
+
+__osmaperrno:
+       ldx     #ErrTabSize
+@L1:   cmp     ErrTab-2,x      ; Search for the error code
+       beq     @L2             ; Jump if found
+       dex
+       dex
+       bne     @L1             ; Next entry
+
+; Code not found, return EINVAL
+
+       lda     #<EINVAL
+       ldx     #>EINVAL
+       rts
+
+; Found the code
+
+@L2:   lda     ErrTab-1,x
+       ldx     #$00            ; High byte always zero
+       rts
+
+.rodata
+
+ErrTab:
+       .byte   1, EMFILE       ; Too many open files
+       .byte   2, EINVAL       ; File is open
+       .byte   3, EINVAL       ; File not open
+       .byte   4, ENOENT       ; File not found
+       .byte   5, ENODEV       ; Device not present
+       .byte   6, EINVAL       ; File not input
+       .byte   7, EINVAL       ; File not output
+       .byte   8, EINVAL       ; Filename missing
+       .byte   9, ENODEV       ; Ilegal device
+;      .byte  20,              ; Read error
+;              .byte  21,              ; Read error
+;      .byte  22,              ; Read error
+;              .byte  23,              ; Read error
+;              .byte  24,              ; Read error
+;              .byte  25,              ; Write error
+       .byte  26, EACCES       ; Write protect on
+;              .byte  27,              ; Read error
+;              .byte  28,              ; Write error
+;              .byte  29,              ; Disk ID mismatch
+;              .byte  30,              ; Syntax error
+;              .byte  31,              ; Syntax error
+;              .byte  32,              ; Syntax error
+               .byte  33, EINVAL       ; Syntax error (invalid file name)
+               .byte  34, EINVAL       ; Syntax error (no file given)
+;              .byte  39,              ; Syntax error
+;              .byte  50,              ; Record not present
+;              .byte  51,              ; Overflow in record
+;      .byte  52,              ; File too large
+       .byte  60, EINVAL       ; Write file open
+       .byte  61, EINVAL       ; File not open
+       .byte  62, ENOENT       ; File not found
+       .byte  63, EEXIST       ; File exists
+       .byte  64, EINVAL       ; File type mismatch
+;      .byte  65,              ; No block
+;      .byte  66,              ; Illegal track or sector
+;              .byte  67,              ; Illegal system track or sector
+       .byte  70, EBUSY        ; No channel
+;              .byte  71,              ; Directory error
+;      .byte  72,              ; Disk full
+;              .byte  73,              ; DOS version mismatch
+
+ErrTabSize = (* - ErrTab)
diff --git a/libsrc/cbm/revers.s b/libsrc/cbm/revers.s
new file mode 100644 (file)
index 0000000..64a0029
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned char revers (unsigned char onoff);
+;
+
+       .export         _revers
+       .export         revers
+
+_revers:
+       ldx     #$00            ; Assume revers off
+       tay                     ; Test onoff
+       beq     L1              ; Jump if off
+       ldx     #$80            ; Load on value
+L1:    ldy     #$00            ; Assume old value is zero
+       lda     revers          ; Load old value
+       stx     revers          ; Set new value
+       beq     L2              ; Jump if old value zero
+       iny                     ; Make old value = 1
+L2:    ldx     #$00            ; Load high byte of result
+       tya                     ; Load low byte, set CC
+       rts
+
+.bss
+
+revers:        .res    1
diff --git a/libsrc/cbm/where.s b/libsrc/cbm/where.s
new file mode 100644 (file)
index 0000000..d9c0b61
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char wherex (void);
+; unsigned char wherey (void);
+
+       .export         _wherex, _wherey
+       
+       .include        "cbm.inc"
+
+_wherex:
+       sec
+       jsr     PLOT            ; Get cursor position
+       tya
+       rts
+
+_wherey:
+       sec
+       jsr     PLOT            ; Get cursor position
+       txa
+       rts
+
+
+
+
+
diff --git a/libsrc/cbm610/Makefile b/libsrc/cbm610/Makefile
new file mode 100644 (file)
index 0000000..cdc5f65
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o\
+                color.o break.o banking.o crtc.o pokesys.o\
+        kscnkey.o kplot.o kudtim.o kirq.o rs232.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/cbm610/banking.s b/libsrc/cbm610/banking.s
new file mode 100644 (file)
index 0000000..57c4754
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Banking routines for the 610.
+;
+
+       .export         set_bank, sys_bank, restore_bank
+       .importzp       ptr1
+
+       .include        "zeropage.inc"
+
+.code
+
+.proc  sys_bank
+       pha
+       lda     IndReg
+       sta     IndSegSave
+       lda     #$0F
+       sta     IndReg
+       pla
+       rts
+.endproc
+
+.proc  set_bank
+       pha
+       lda     IndReg
+       sta     IndSegSave
+       pla
+       sta     IndReg
+       rts
+.endproc
+
+.proc  restore_bank
+       pha
+       lda     IndSegSave
+       sta     IndReg
+       pla
+       rts
+.endproc
+
+
diff --git a/libsrc/cbm610/break.s b/libsrc/cbm610/break.s
new file mode 100644 (file)
index 0000000..66492be
--- /dev/null
@@ -0,0 +1,117 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+               .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+                     
+       .include        "zeropage.inc"
+       .include        "page3.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+_brk_01:       .res    1
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     BRKVec
+       lda     #>brk_handler
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       pla
+       sta     _brk_y
+       pla
+       sta     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+       lda     IndReg
+       sta     _brk_01
+       lda     ExecReg
+       sta     IndReg
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_01
+       sta     IndReg
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
diff --git a/libsrc/cbm610/cbm610.inc b/libsrc/cbm610/cbm610.inc
new file mode 100644 (file)
index 0000000..a7430ab
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; CBM610 generic definitions.
+;
+
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+FUNKEY_VEC     = $03B5
+
+; ---------------------------------------------------------------------------
+; I/O
+
+CRTC           = $D800
+CRTC_ADDR      = $00
+CRTC_DATA      = $01
+
diff --git a/libsrc/cbm610/cgetc.s b/libsrc/cbm610/cgetc.s
new file mode 100644 (file)
index 0000000..c801c3a
--- /dev/null
@@ -0,0 +1,49 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+       .export         _cgetc
+       .import         plot, write_crtc
+       .import         cursor
+
+       .include        "zeropage.inc"
+       .include        "page3.inc"
+
+
+_cgetc:        lda     KeyIndex        ; Get number of characters
+       bne     L2              ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+               lda     cursor
+               beq     L1              ; Jump if no cursor
+
+               jsr     plot            ; Set the current cursor position
+               ldy     #10
+               lda     Config          ; Cursor format
+               jsr     write_crtc      ; Set the cursor formar
+
+L1:            lda     KeyIndex
+               beq     L1
+
+               ldy     #10
+               lda     #$20            ; Cursor off
+               jsr     write_crtc
+
+L2:            ldx     #$00            ; Get index
+               ldy     KeyBuf          ; Get first character in the buffer
+               sei
+L3:            lda     KeyBuf+1,x      ; Move up the remaining chars
+               sta     KeyBuf,x
+               inx
+               cpx     KeyIndex
+               bne     L3
+               dec     KeyIndex
+               cli
+
+               ldx     #$00            ; High byte
+               tya                     ; First char from buffer
+               rts
+
diff --git a/libsrc/cbm610/clrscr.s b/libsrc/cbm610/clrscr.s
new file mode 100644 (file)
index 0000000..22ca5e9
--- /dev/null
@@ -0,0 +1,42 @@
+;
+; Ullrich von Bassewitz, 22.09.1998
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+       .import         plot
+
+       .include        "zeropage.inc"
+
+.proc  _clrscr
+
+       lda     #0
+       sta     CURS_X
+       sta     CURS_Y
+               jsr     plot            ; Set cursor to top left corner
+
+       lda     IndReg
+       pha
+       lda     #$0F
+       sta     IndReg          ; Switch to the system bank
+
+       ldx     #8
+       ldy     #$00
+       lda     #$20            ; Screencode for blank
+L1:    sta     (CharPtr),y
+       iny
+       bne     L1
+       inc     CharPtr+1
+       dex
+       bne     L1
+
+       pla
+       sta     IndReg          ; Restore old indirect segment
+
+       jmp     plot            ; Set screen pointer again
+
+.endproc
+
+
+
diff --git a/libsrc/cbm610/color.s b/libsrc/cbm610/color.s
new file mode 100644 (file)
index 0000000..f36fdf1
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+       .export         _textcolor, _bgcolor, _bordercolor
+       .import         return0, return1
+
+       .include        "cbm610.inc"
+
+_textcolor     = return1
+
+_bgcolor       = return0
+
+_bordercolor   = return0
+
+
diff --git a/libsrc/cbm610/conio.s b/libsrc/cbm610/conio.s
new file mode 100644 (file)
index 0000000..c1c58ef
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; Ullrich von Bassewitz, 22.09.1998
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio
+       .import         xsize, ysize
+
+       .include        "cbm610.inc"
+
+initconio:
+       lda     #80
+       sta     xsize
+       lda     #25
+       sta     ysize
+       rts
+
+
diff --git a/libsrc/cbm610/cputc.s b/libsrc/cbm610/cputc.s
new file mode 100644 (file)
index 0000000..4e8d942
--- /dev/null
@@ -0,0 +1,102 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc, cputdirect, putchar
+       .export         advance, newline, plot
+       .exportzp       CURS_X, CURS_Y
+       .import         _gotoxy
+       .import         popa
+       .import         xsize, revers
+
+       .include        "cbm610.inc"
+       .include        "zeropage.inc"
+       .include        "../cbm/cbm.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     CURS_X
+               beq     plot            ; Recalculate pointers
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       ldy     CURS_Y
+       iny
+       bne     newline         ; Recalculate pointers
+
+; Printable char of some sort
+
+L2:            cmp     #' '
+       bcc     cputdirect      ; Other control char
+       tay
+       bmi     L10
+       cmp     #$60
+       bcc     L3
+       and     #$DF
+       bne     cputdirect      ; Branch always
+L3:    and     #$3F
+
+cputdirect:
+       jsr     putchar         ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+       iny
+       cpy     xsize
+       bne     L9
+       ldy     #0              ; new line
+newline:
+       clc
+       lda     xsize
+       adc     CharPtr
+       sta     CharPtr
+       bcc     L4
+       inc     CharPtr+1
+L4:    inc     CURS_Y
+L9:            sty     CURS_X
+       rts
+
+; Handle character if high bit set
+
+L10:   and     #$7F
+               cmp     #$7E            ; PI?
+       bne     L11
+       lda     #$5E            ; Load screen code for PI
+       bne     cputdirect
+L11:   ora     #$40
+       bne     cputdirect      ; Branch always
+
+; Set cursor position, calculate RAM pointers
+
+plot:  ldy     CURS_X
+       ldx     CURS_Y
+       clc
+       jmp     PLOT
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+       ldx     IndReg
+       ldy     #$0F
+       sty     IndReg
+       ora     revers          ; Set revers bit
+               ldy     CURS_X
+       sta     (CharPtr),y     ; Set char
+       stx     IndReg
+       rts
+
+                        
diff --git a/libsrc/cbm610/crt0.s b/libsrc/cbm610/crt0.s
new file mode 100644 (file)
index 0000000..3ab5257
--- /dev/null
@@ -0,0 +1,411 @@
+;
+; Startup code for cc65 (Plus/4 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+       .import         __hinit, push0, doatexit, _main
+       .import         initconio
+       .import         __BSS_RUN__, __BSS_SIZE__
+       .import         irq, nmi
+               .import         k_irq, k_nmi, k_plot, k_udtim, k_scnkey
+
+       .include        "zeropage.inc"
+       .include        "io.inc"
+
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the CBM610 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+       .exportzp       crtc, sid, IPCcia, cia, acia, tpi1, tpi2
+       .exportzp       ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
+
+sp             =       $02             ; stack pointer
+sreg   =       $04             ; secondary register/high 16 bit for longs
+regsave        =       $06             ; slot to save/restore (E)AX into
+ptr1   =       $0A             ;
+ptr2   =       $0C
+ptr3   =       $0E
+ptr4   =       $10
+tmp1   =       $12
+tmp2   =       $13
+tmp3   =       $14
+tmp4   =       $15
+regbank        =       $16             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header and a small BASIC program. Since it is not possible to start
+; programs in other banks using SYS, the BASIC program will write a small
+; machine code program into memory at $100 and start that machine code
+; program. The machine code program will then start the machine language
+; code in bank 1, which will initialize the system by copying stuff from
+; the system bank, and start the application.
+;
+; Here's the basic program that's in the following lines:
+;
+; 10 for i=0 to 4
+; 20 read j
+; 30 poke 256+i,j
+; 40 next i
+; 50 sys 256
+; 60 data 120,169,1,133,0
+;
+; The machine program in the data lines is:
+;
+; sei
+; lda    #$01
+; sta     $00          <-- Switch to bank 1 after this command
+;
+; Initialization is not only complex because of the jumping from one bank
+; into another. but also because we want to save memory, and because of
+; this, we will use the system memory ($00-$3FF) for initialization stuff
+; that is overwritten later.
+;
+
+; To make things more simple, make the code of this module absolute.
+
+       .org    $0001
+Head:  .byte   $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
+       .byte   $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
+       .byte   $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
+       .byte   $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
+       .byte   $30,$2c,$31,$36,$39,$2c,$31,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
+
+; Since we need some vectors to access stuff in the system bank for our own,
+; we will include them here, starting from $60:
+
+       .res    $60-*
+
+crtc:                  .word   $d800
+sid:           .word   $da00
+IPCcia:                .word   $db00
+cia:                   .word   $dc00
+acia:                  .word   $dd00
+tpi1:          .word   $de00
+tpi2:                  .word   $df00
+ktab1:         .word   $ea29
+ktab2:         .word   $ea89
+ktab3:         .word   $eae9
+ktab4:         .word   $eb49
+time:          .dword  $0000
+RecvBuf:       .word   $0100           ; RS232 received buffer
+SendBuf:       .word   $0200           ; RS232 send buffer
+
+
+; The code in the target bank when switching back will be put at the bottom
+; of the stack. We will jump here to switch segments. The range $F2..$FF is
+; not used by any kernal routine.
+
+       .res    $F8-*
+Back:  ldx     spsave
+       txs
+       lda     IndReg
+       sta     ExecReg
+
+; The following code is a copy of the code that is poked in the system bank
+; memory by the basic header program, it's only for documentation and not
+; actually used here:
+
+       sei
+       lda     #$01
+       sta     ExecReg
+
+; This is the actual starting point of our code after switching banks for
+; startup. Beware: The following code will get overwritten as soon as we
+; use the stack (since it's in page 1)!
+
+       tsx
+               stx     spsave          ; Save the system stackpointer
+       ldx     #$FF
+       txs                     ; Set up our own stack
+
+; Set the interrupt, NMI and other vectors
+
+       ldy     #vectable_size
+L0:    lda     vectable-1,y
+       sta     $FF80,y
+       dey
+               bne     L0
+
+; Switch the indirect segment to the system bank
+
+       lda     #$0F
+       sta     IndReg
+
+; Copy the kernal zero page ($90-$F2) from the system bank
+
+       lda     #$90
+       sta     ptr1
+       lda     #$00
+       sta     ptr1+1
+       ldy     #$62-1
+L1:    lda     (ptr1),y
+       sta     $90,y
+       dey
+       bpl     L1
+
+; Copy the page 3 vectors in place
+
+       ldy     #$00
+L2:    lda     p3vectable,y
+       sta     $300,y
+       iny
+       cpy     #p3vectable_size
+               bne     L2
+
+; Copy the rest of page 3 from the system bank
+
+       lda     #$00
+       sta     ptr1
+       lda     #$03
+       sta     ptr1+1
+L3:    lda     (ptr1),y
+       sta     $300,y
+       iny
+       bne     L3
+
+; Set the indirect segment to bank we're executing in
+
+       lda     ExecReg
+       sta     IndReg
+
+; Zero the BSS segment. We will do that here instead calling the routine
+; in the common library, since we have the memory anyway, and this way,
+; it's reused later.
+
+       lda     #<__BSS_RUN__
+       sta     ptr1
+       lda     #>__BSS_RUN__
+       sta     ptr1+1
+       lda     #0
+       tay
+
+; Clear full pages
+
+       ldx     #>__BSS_SIZE__
+       beq     Z2
+Z1:    sta     (ptr1),y
+       iny
+       bne     Z1
+       inc     ptr1+1                  ; Next page
+       dex
+       bne     Z1
+
+; Clear the remaining page
+
+Z2:    ldx     #<__BSS_SIZE__
+       beq     Z4
+Z3:    sta     (ptr1),y
+       iny
+       dex
+       bne     Z3
+Z4:
+
+; Setup the C stack
+
+       lda     #<$FF81
+       sta     sp
+               lda     #>$FF81
+       sta     sp+1
+
+; We expect to be in page 2 now
+
+.if    (* < $1FD)
+       jmp     $200
+       .res    $200-*
+.endif
+.if    (* < $200)
+       .res    $200-*,$EA
+.endif
+.if            (* >= $2F0)
+.error "Code range invalid"
+.endif
+
+; This code is in page 2, so we may now start calling subroutines safely,
+; since the code we execute is no longer in the stack page.
+
+       jsr     __hinit                 ; Initialize the heap
+       jsr     initconio               ; Initialize conio stuff
+
+; Create the (empty) command line for the program
+
+               jsr     push0           ; argc
+               jsr     push0           ; argv
+
+; Execute the program code
+
+       jmp     Start
+
+; ------------------------------------------------------------------------
+; Additional data that we need for initialization and that's overwritten
+; later
+
+vectable:
+       jmp     $0000           ; CINT
+       jmp     $0000           ; IOINIT
+       jmp     $0000           ; RAMTAS
+       jmp     $0000           ; RESTOR
+       jmp     $0000           ; VECTOR
+       jmp     $0000           ; SETMSG
+       jmp     $0000           ; SECOND
+       jmp     $0000           ; TKSA
+       jmp     $0000           ; MEMTOP
+       jmp     $0000           ; MEMBOT
+       jmp     k_scnkey        ; SCNKEY
+       jmp     $0000           ; SETTMO
+       jmp     $0000           ; ACPTR
+       jmp     $0000           ; CIOUT
+       jmp     $0000           ; UNTLK
+       jmp     $0000           ; UNLSN
+       jmp     $0000           ; LISTEN
+       jmp     $0000           ; TALK
+       jmp     $0000           ; READST
+               jmp     k_setlfs        ; SETLFS
+               jmp     k_setnam        ; SETNAM
+       jmp     $0000           ; OPEN
+       jmp     $0000           ; CLOSE
+       jmp     $0000           ; CHKIN
+       jmp     $0000           ; CKOUT
+       jmp     $0000           ; CLRCH
+       jmp     $0000           ; BASIN
+       jmp     $0000           ; BSOUT
+       jmp     $0000           ; LOAD
+       jmp     $0000           ; SAVE
+       jmp     k_settim        ; SETTIM
+               jmp     k_rdtim         ; RDTIM
+       jmp     $0000           ; STOP
+       jmp     $0000           ; GETIN
+       jmp     $0000           ; CLALL
+       jmp     k_udtim         ; UDTIM
+       jmp     k_screen        ; SCREEN
+       jmp     k_plot          ; PLOT
+       jmp     k_iobase        ; IOBASE
+       sta     ExecReg
+       rts
+       .byte   $01             ; Filler
+               .word   nmi
+               .word   0               ; Reset - not used
+               .word   irq
+vectable_size  = * - vectable
+
+p3vectable:
+       .word   k_irq           ; IRQ user vector
+       .word   k_brk           ; BRK user vector
+       .word   k_nmi           ; NMI user vector
+p3vectable_size        = * - p3vectable
+
+
+; ------------------------------------------------------------------------
+; This is the program code after setup. It starts at $400
+
+       .res    $400-*
+
+Start:
+
+; Enable interrupts
+
+       cli
+
+; Call the user code
+
+               ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; Fall thru to exit.
+
+_exit:         jsr     doatexit        ; call exit functions
+
+; Clear the start of the zero page, since it will be interpreted as a
+; (garbage) BASIC program otherwise. This is also the default entry for
+; the break vector.
+
+k_brk: sei
+       lda     #$00
+       ldx     #$3E
+Clear: sta     $02,x
+       dex
+       bne     Clear
+
+; Setup the welcome code at the stack bottom in the system bank. Use
+; the F4/F5 vector to access the system bank
+
+       lda     #$0F
+       sta     IndReg
+       ldy     #$00
+               sty     $F4
+       iny
+       sty     $F5
+       ldy     #reset_size-1
+@L1:   lda     reset,y
+       sta     ($F4),y
+       dey
+       bne     @L1
+       jmp     Back
+
+; ------------------------------------------------------------------------
+; Code that is copied into the system bank at $100 when switching back
+
+reset: cli
+       jmp     $8000                   ; BASIC cold start
+reset_size = * - reset
+
+; ------------------------------------------------------------------------
+; Code for a few simpler kernal calls goes here
+
+k_iobase:
+       ldx     cia
+       ldy     cia+1
+       rts
+
+k_screen:
+       ldx     #80             ; Columns
+       ldy     #25             ; Lines
+       rts
+
+k_setlfs:
+        sta     LogicalAdr
+        stx     FirstAdr
+        sty     SecondAdr
+        rts
+
+k_setnam:
+        sta     FileNameLen
+        lda     $00,x
+        sta     FileNameAdrLo
+        lda     $01,x
+        sta     FileNameAdrHi
+        lda     $02,x
+        sta     FileNameAdrSeg
+        rts
+
+k_rdtim:
+       sei
+       lda     time+0
+       ldx     time+1
+       ldy     time+2
+       cli
+       rts
+
+k_settim:
+       sei
+       sta     time+0
+       stx     time+1
+       sty     time+2
+       cli
+       rts
+
+; -------------------------------------------------------------------------
+; Data area - switch back to relocatable mode
+
+       .reloc
+
+.data
+spsave:        .res    1
+
+
diff --git a/libsrc/cbm610/crtc.s b/libsrc/cbm610/crtc.s
new file mode 100644 (file)
index 0000000..18670b9
--- /dev/null
@@ -0,0 +1,58 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Write to the CRTC.
+;
+
+       .export         write_crtc, read_crtc
+       .importzp       crtc
+
+       .include        "cbm610.inc"
+       .include        "zeropage.inc"
+
+
+; Write a value to the CRTC. The index is in Y, the value in A
+
+.proc  write_crtc
+       sta     sedt1
+       lda     IndReg
+       pha
+       lda     #$0F
+       sta     IndReg
+       tya
+       ldy     #$00
+       sei
+       sta     (crtc),y
+       iny
+       lda     sedt1
+       sta     (crtc),y
+       cli
+       pla
+       sta     IndReg
+       lda     sedt1
+       rts
+.endproc
+
+
+.proc  read_crtc
+       sty     sedt1
+       lda     IndReg
+       pha
+       lda     #$0F
+       sta     IndReg
+       lda     sedt1
+       ldy     #$00
+       sei
+       sta     (crtc),y
+       iny
+               lda     (crtc),y
+       cli
+       tay
+       pla
+       sta     IndReg
+       tya
+       ldy     sedt1
+       rts
+.endproc
+
+
diff --git a/libsrc/cbm610/io.inc b/libsrc/cbm610/io.inc
new file mode 100644 (file)
index 0000000..4d7d29b
--- /dev/null
@@ -0,0 +1,108 @@
+;
+; I/O definitions for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+; I/O  $d800: CRTC 6545
+
+;      crtc            =       $d800
+
+       CAdrReg         =       $00
+       CDataReg        =       $01
+
+
+
+; I/O  $da00: SID 6581
+
+;      sid             =       $da00
+
+       Osc1            =       $00
+       Osc2            =       $07
+       Osc3            =       $0e
+
+       FreqLo          =       $00
+       FreqHi          =       $01
+       PulseF          =       $02
+       PulseC          =       $03
+       OscCtl          =       $04
+       AtkDcy          =       $05
+       SusRel          =       $06
+
+       FiCtlLo         =       $15
+       FiCtlHi         =       $16
+       Resonance       =       $17
+       Volume          =       $18
+       PotX            =       $19
+       PotY            =       $1A
+       Random          =       $1B
+       Env3            =       $1C
+
+
+
+; I/O  $db00: CIA 6526 Inter Process Communication
+
+;      IPCcia          =       $db00
+
+       PortA           =       $00
+       PortB           =       $01
+       DDRA            =       $02
+       DDRB            =       $03
+       TimALo          =       $04
+       TimAHi          =       $05
+       TimBLo          =       $06
+       TimBHi          =       $07
+       TOD10           =       $08
+       TODsec          =       $09
+       TODmin          =       $0A
+       TODhour         =       $0B
+       SerDataReg      =       $0C
+       IntCtrReg       =       $0D
+       CtrlA           =       $0E
+       CtrlB           =       $0F
+
+
+
+; I/O  $dc00: CIA 6526
+
+;      cia             =       $dc00
+
+
+
+; I/O  $dd00: ACIA 6551
+
+;      acia            =       $dd00
+
+       ADataReg        =       $00
+       AStatusReg      =       $01
+       ACmdReg         =       $02
+       ACtrlReg        =       $03
+
+
+
+; I/O  $de00: Triport #1 6525
+
+;      tpi1            =       $de00
+
+       tpiPortA        =       $00
+       tpiPortB        =       $01
+       tpiPortC        =       $02
+       tpiIntLatch     =       $02
+       tpiDDRA         =       $03
+       tpiDDRB         =       $04
+       tpiDDRC         =       $05
+       tpiIntMask      =       $05
+       tpiCtrlReg      =       $06
+       tpiActIntReg    =       $07
+
+
+
+; I/O  $df00: Triport #2 6525
+
+;      tpi2            =       $df00
+
+
+
+
diff --git a/libsrc/cbm610/kbhit.s b/libsrc/cbm610/kbhit.s
new file mode 100644 (file)
index 0000000..5ef5e63
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+
+       .include        "zeropage.inc"
+
+.proc  _kbhit
+       lda     KeyIndex        ; Get number of characters
+       bne     L1
+       jmp     return0
+L1:    jmp     return1
+.endproc
+
+
+
+
+
+
diff --git a/libsrc/cbm610/kirq.s b/libsrc/cbm610/kirq.s
new file mode 100644 (file)
index 0000000..6363072
--- /dev/null
@@ -0,0 +1,100 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; IRQ routine for the 610.
+;
+
+       .export         irq, nmi, k_irq, k_nmi
+       .import         k_scnkey, k_udtim, k_rs232
+       .importzp       tpi1
+
+       .include        "zeropage.inc"
+       .include        "io.inc"
+       .include        "page3.inc"
+
+
+; -------------------------------------------------------------------------
+; This is the mapping of the active irq register of the        6525 (tpi1):
+;
+; Bit   7       6       5       4       3       2       1       0
+;                               |       |       |       |       ^ 50 Hz
+;                               |       |       |       ^ SRQ IEEE 488
+;                               |       |       ^ cia
+;                               |       ^ IRQB ext. Port
+;                               ^ acia
+
+
+
+; -------------------------------------------------------------------------
+; IRQ entry point
+
+.proc  irq
+
+       pha
+        txa
+        pha
+        tya
+        pha
+       tsx
+       lda     $104,x                  ; Get the flags from the stack
+       and     #$10                    ; Test break flag
+       bne     L1
+       jmp     (IRQVec)
+L1:    jmp     (BRKVec)
+
+.endproc
+
+; -------------------------------------------------------------------------
+; NMI entry point
+
+.proc  nmi
+
+       jmp     (NMIVec)
+
+.endproc
+
+
+; -------------------------------------------------------------------------
+; Kernal irq entry point. The IRQvec points here (usually).
+
+k_irq:
+       lda     IndReg                  ; Ind. Segment retten
+        pha
+        cld
+       lda     #$0F
+       sta     IndReg
+       ldy     #tpiActIntReg
+       lda     (tpi1),y                ; Interrupt Register 6525
+       beq     noirq
+
+; -------------------------------------------------------------------------
+; 50/60Hz interrupt
+
+       cmp     #%00000001              ; ticker irq?
+       bne     irq1
+       jsr     k_scnkey                ; Poll the keyboard
+        jsr    k_udtim                 ; Bump the time
+
+; -------------------------------------------------------------------------
+; UART interrupt
+
+irq1:  cmp     #%00010000              ; interrupt from uart?
+       bne     irqend
+       jsr     k_rs232                 ; Read character from uart
+
+; -------------------------------------------------------------------------
+; Done
+
+irqend:        ldy     #tpiActIntReg
+               sta     (tpi1),y                ; Clear interrupt
+
+noirq: pla
+        sta     IndReg
+        pla
+        tay
+        pla
+        tax
+        pla
+k_nmi: rti
+
+
diff --git a/libsrc/cbm610/kplot.s b/libsrc/cbm610/kplot.s
new file mode 100644 (file)
index 0000000..e7f633d
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; PLOT routine for the 610.
+;
+
+       .export         k_plot
+       .importzp       crtc
+
+       .include        "zeropage.inc"
+
+
+.proc  k_plot
+
+       bcc     set
+       ldx     CURS_Y
+       ldy     CURS_X
+       rts
+
+set:           stx     CURS_Y
+       sty     CURS_X
+       lda     LineLSBTab,x
+       sta     CharPtr
+       lda     LineMSBTab,x
+       sta     CharPtr+1
+
+       lda     IndReg
+       pha
+       lda     #$0F
+       sta     IndReg
+
+       ldy     #$00
+       clc
+       sei
+       sta     (crtc),y
+       lda     CharPtr
+       adc     CURS_X
+       iny
+       sta     (crtc),y
+       dey
+       lda     #$0E
+       sta     (crtc),y
+       iny
+       lda     (crtc),y
+       and     #$F8
+       sta     sedt1
+       lda     CharPtr+1
+       adc     #$00
+       and     #$07
+       ora     sedt1
+       sta     (crtc),y
+       cli
+
+       pla
+       sta     IndReg
+       rts
+.endproc
+
+; -------------------------------------------------------------------------
+; Low bytes of the start address of the screen lines
+
+.rodata
+
+LineLSBTab:
+        .byte   $00,$50,$A0,$F0,$40,$90,$E0,$30
+        .byte   $80,$D0,$20,$70,$C0,$10,$60,$B0
+        .byte   $00,$50,$A0,$F0,$40,$90,$E0,$30
+        .byte   $80
+; -------------------------------------------------------------------------
+; High bytes of the start address of the screen lines
+
+LineMSBTab:
+        .byte   $D0,$D0,$D0,$D0,$D1,$D1,$D1,$D2
+        .byte   $D2,$D2,$D3,$D3,$D3,$D4,$D4,$D4
+        .byte   $D5,$D5,$D5,$D5,$D6,$D6,$D6,$D7
+        .byte   $D7
diff --git a/libsrc/cbm610/kscnkey.s b/libsrc/cbm610/kscnkey.s
new file mode 100644 (file)
index 0000000..8d04479
--- /dev/null
@@ -0,0 +1,146 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Keyboard polling stuff for the 610.
+;
+
+       .export         k_scnkey
+       .importzp       tpi2, ktab1, ktab2, ktab3, ktab4
+
+       .include        "zeropage.inc"
+       .include        "io.inc"
+       .include        "page3.inc"
+
+
+.proc  k_scnkey
+
+        lda     #$FF
+        sta     ModKey
+        sta     NorKey
+        lda    #$00
+       sta     KbdScanBuf
+       ldy     #tpiPortB
+       sta     (tpi2),y
+       ldy     #tpiPortA
+       sta     (tpi2),y
+        jsr     Poll
+        and     #$3F
+        eor     #$3F
+        bne     L1
+        jmp     NoKey
+
+L1:    lda     #$FF
+       ldy     #tpiPortA
+       sta     (tpi2),y
+        asl     a
+       ldy     #tpiPortB
+       sta     (tpi2),y
+        jsr     Poll
+        pha
+        sta     ModKey
+        ora     #$30
+        bne     L3             ; Branch always
+
+L2:    jsr     Poll
+L3:    ldx     #$05
+       ldy     #$00
+L4:    lsr     a
+        bcc     L5
+        inc    KbdScanBuf
+        dex
+        bpl     L4
+        sec
+       ldy     #tpiPortB
+       lda     (tpi2),y
+       rol     a
+       sta     (tpi2),y
+               ldy     #tpiPortA
+       lda     (tpi2),y
+       rol     a
+       sta     (tpi2),y
+        bcs     L2
+        pla
+        bcc     NoKey          ; Branch always
+
+L5:    ldy     KbdScanBuf
+       sty     NorKey
+        pla
+        asl     a
+        asl     a
+        asl     a
+        bcc     L6
+        bmi     L7
+        lda     (ktab2),y              ; Shifted normal key
+        ldx     GrafMode
+        beq     L8
+        lda     (ktab3),y              ; Shifted key in graph mode
+        bne     L8
+
+L6:    lda     (ktab4),y               ; Key with ctrl pressed
+       bne     L8
+L7:    lda     (ktab1),y               ; Normal key
+L8:    tax
+       cpx     #$FF                    ; Valid key?
+        beq     Done
+        cpy     LastIndex
+        beq     Repeat
+        ldx     #$13
+        stx     RepeatDelay
+        ldx     KeyIndex
+        cpx     #$09
+        beq     NoKey
+        cpy     #$59
+        bne     PutKey
+        cpx     #$08
+        beq     NoKey
+        sta     KeyBuf,x
+        inx
+        bne     PutKey
+
+NoKey: ldy     #$FF
+Done:          sty     LastIndex
+End:   lda     #$7F
+       ldy     #tpiPortA
+       sta     (tpi2),y
+       ldy     #tpiPortB
+       lda     #$FF
+       sta     (tpi2),y
+        rts
+
+Repeat:        dec     RepeatDelay
+        bpl     End
+        inc     RepeatDelay
+        dec     RepeatCount
+        bpl     End
+        inc     RepeatCount
+        ldx     KeyIndex
+        bne     End
+
+PutKey:        sta     KeyBuf,x
+        inx
+        stx     KeyIndex
+        ldx     #$03
+        stx     RepeatCount
+        bne     Done
+
+.endproc
+
+
+; Poll the keyboard port until it's stable
+
+.proc  Poll
+       ldy     #tpiPortC
+L1:    lda     (tpi2),y
+       sta     KeySave
+       lda     (tpi2),y
+       cmp     KeySave
+       bne     L1
+       rts
+.endproc
+
+
+.bss
+
+KeySave:       .res    1
+
+
diff --git a/libsrc/cbm610/kudtim.s b/libsrc/cbm610/kudtim.s
new file mode 100644 (file)
index 0000000..e100a84
--- /dev/null
@@ -0,0 +1,25 @@
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; udtim routine for the 610. We will not check for the stop key here, since
+; C programs will not use it.
+;
+
+       .export         k_udtim
+       .importzp       time
+
+
+.proc  k_udtim
+
+       inc     time
+       bne     L9
+       inc     time+1
+       bne     L9
+       inc     time+2
+       bne     L9
+       inc     time+3
+L9:    rts
+
+.endproc
+
+                
diff --git a/libsrc/cbm610/page3.inc b/libsrc/cbm610/page3.inc
new file mode 100644 (file)
index 0000000..7095a13
--- /dev/null
@@ -0,0 +1,94 @@
+;
+; Page 3 variables for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+;
+; system ram vectors
+;
+
+IRQVec              = $0300
+BRKVec              = $0302
+NMIVec              = $0304
+openVec                     = $0306
+closeVec            = $0308
+chkinVec            = $030A
+ckoutVec            = $030C
+clrchVec            = $030E
+basinVec            = $0310
+bsoutVec            = $0312
+stopVec                     = $0314
+getinVec            = $0316
+clallVec            = $0318
+loadVec                     = $031A
+saveVec                     = $031C
+usrcmd              = $031E
+escvec              = $0320
+ctrlvec                     = $0322
+secndVec            = $0324
+tksaVec                     = $0326
+acptrVec            = $0328
+cioutVec            = $032A
+untlkVec            = $032C
+unlsnVec            = $032E
+listnVec            = $0330
+talkVec                     = $0332
+
+;
+;
+;
+
+LogicalAdrTable      = $0334
+FirstAdrTable       = $033E
+SecondAdrTable      = $0348
+SysMemBot           = $0352
+SysMemTop           = $0355
+UsrMemBot           = $0358
+UsrMemTop           = $035B
+TimOut              = $035E
+VerifyFlag          = $035F
+DevTabIndex         = $0360
+MsgFlag                     = $0361
+CassBufPtr          = $0362
+t1                  = $0363
+t2                  = $0364
+XSave               = $0365
+SaveX               = $0366
+SaveXt              = $0367
+temp                = $0368
+alarm               = $0369
+TapeVec                     = $036A
+LoadStAdr           = $036F
+CassMotFlag         = $0375
+m6551Ctrl           = $0376
+m6551Cmd            = $0377
+rs232status         = $037A
+dcddsr              = $037B
+rs232head           = $037C
+rs232tail           = $037D
+PgmKeyEnd           = $0380
+PgmKeySeg           = $0382
+PgmKeySize          = $0383
+rvsFlag                     = $0397
+linetmp                     = $0398
+LastPrtChar         = $0399
+InsertFlag          = $039A
+ScrollFlag          = $039B
+FktTemp                     = $039C
+PgmKeyIdx           = $039D
+LogScrollFlag       = $039E
+BellMode            = $039F    ; Bell on/off 00 = an
+SegSave                     = $03A0
+TabStopTable        = $03A1    ; 80 bits for tabstops
+KeyBuf              = $03AB    ; Keyboard buffer
+funvec              = $03B5    ; Vector for function key handline
+FunKeyTmp           = $03B7
+sedt3               = $03B9
+MoniSegSave         = $03f0
+wstvec              = $03F8
+WstFlag                     = $03FA    ; Warm start flag
+
+
diff --git a/libsrc/cbm610/pokesys.s b/libsrc/cbm610/pokesys.s
new file mode 100644 (file)
index 0000000..ebd4ec5
--- /dev/null
@@ -0,0 +1,38 @@
+;
+; Ullrich von Bassewitz, 29.09.1998
+;
+; void pokebsys (unsigned Addr, unsigned char Val);
+; void pokewsys (unsigned Addr, unsigned Val);
+
+       .export         _pokebsys, _pokewsys
+       .import         popsreg
+       .importzp       sreg, tmp1
+
+       .include        "zeropage.inc"
+
+
+_pokebsys:
+       jsr     popsreg         ; Get the address
+       ldx     IndReg
+               ldy     #$0F
+       sty     IndReg          ; Switch to the system bank
+       ldy     #$00
+       sta     (sreg),y
+       stx     IndReg
+       rts
+
+_pokewsys:
+       stx     tmp1            ; Save high byte
+               jsr     popsreg         ; Get the address
+       ldx     IndReg
+               ldy     #$0F
+       sty     IndReg          ; Switch to the system bank
+       ldy     #$00
+       sta     (sreg),y
+       iny
+       lda     tmp1
+       sta     (sreg),y
+       stx     IndReg
+       rts
+
+
diff --git a/libsrc/cbm610/rs232.s b/libsrc/cbm610/rs232.s
new file mode 100644 (file)
index 0000000..1ed4c61
--- /dev/null
@@ -0,0 +1,631 @@
+;
+; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
+;
+; This software is Public Domain.  It is in Buddy assembler format.
+;
+; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
+; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
+; Serial Cartridge.  Both devices are based on the 6551 ACIA chip.  It also
+; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
+;
+; The code assumes that the kernal + I/O are in context.  On the C128, call
+; it from Bank 15.  On the C64, don't flip out the Kernal unless a suitable
+; NMI catcher is put into the RAM under then Kernal.  For the SuperCPU, the
+; interrupt handling assumes that the 65816 is in 6502-emulation mode.
+;
+;--------------------------------------------------------------------------
+;
+; Adapted for the use with the cc65 runtime library by
+; Ullrich von Bassewitz (uz@musoftware.de) 02-May-1999.
+;
+; All external functions are C callable, the return value is an error code.
+;
+
+
+       .importzp       ptr1, ptr2, tmp1, tmp2
+       .importzp       acia, RecvBuf, SendBuf
+       .import         popa, popax
+       .import         sys_bank, restore_bank
+       .export         _rs232_init, _rs232_params, _rs232_done, _rs232_get
+       .export         _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
+       .export         k_rs232
+
+       .include        "zeropage.inc"
+
+
+;----------------------------------------------------------------------------
+;
+; Global variables
+;
+
+.bss
+DropCnt:       .res    4       ; Number of bytes lost from rx buffer full
+Initialized:   .res    1       ; Flag indicating driver is initialized
+Stopped:       .res    1       ; Flow-stopped flag
+RtsOff:                .res    1       ;
+Errors:                .res    1       ; Number of bytes received in error, low byte
+BaudCode:      .res    1       ; Current baud in effect
+
+; Segment, the RS232 buffers are in
+BufferSeg              = 2
+
+; UART register offsets
+RegData                = 0     ; Data register
+RegStatus              = 1     ; Status register
+RegCommand             = 2     ; Command register
+RegControl             = 3     ; Control register
+
+; Error codes. Beware: The codes must match the codes in the C header file
+ErrNotInitialized      = $01
+ErrBaudTooFast         = $02
+ErrBaudNotAvail        = $03
+ErrNoData              = $04
+ErrOverflow            = $05
+
+
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_init (char hacked);
+; /* Initialize the serial port, install the interrupt handler. The parameter
+;  * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+;  */
+;
+
+_rs232_init:
+               bit     Initialized     ;** shut down if started
+               bpl     @L1
+               pha
+               jsr     _rs232_done
+               pla
+
+; Initialize buffers & control
+
+@L1:   lda     #0
+       sta     RecvHead
+       sta     SendHead
+       sta     RecvTail
+       sta     SendTail
+       sta     Errors
+       sta     Stopped
+       lda     #255
+               sta     RecvFreeCnt
+       sta     SendFreeCnt
+
+; Set default to 2400-8N1, enable interrupts
+
+       jsr     sys_bank                ; Switch indirect to system bank
+
+       ldy     #RegData
+       lda     (acia),y
+       ldy     #RegStatus
+       lda     (acia),y
+       lda     #$18
+       ldy     #RegControl
+       sta     (acia),y
+
+       lda     #$01
+       sta     RtsOff
+       ora     #$08
+       ldy     #RegCommand
+               sta     (acia),y
+       lda     #$06
+       sta     BaudCode
+
+       jsr     restore_bank
+
+       lda     #$ff
+       sta     Initialized
+       lda     #$00
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+; /* Set the port parameters. Use a combination of the #defined values above. */
+;
+; Set communication parameters.
+;
+; baud rates              stops     word    |   parity
+; ---------------------   -----     -----   |   ---------
+; $00=50     $08=9600     $00=1     $00=8   |   $00=none
+; $01=110    $09=19200    $80=2     $20=7   |   $20=odd
+; $02=134.5  $0a=38400              $40=6   |   $60=even
+; $03=300    $0b=57600              $60=5   |   $A0=mark
+; $04=600    $0c=115200                     |   $E0=space
+; $05=1200   $0d=230400
+; $06=2400   $0e=future
+; $07=4800   $0f=future
+;
+
+_rs232_params:
+               jsr     CheckInitialized        ;** check initialized
+               bcc     @L1
+       rts
+
+; Save new parity
+
+@L1:           and     #%11100000
+               ora     #%00000001
+               sta     tmp2
+
+; Set baud/parameters
+
+               jsr     popa
+               sta     tmp1
+               and     #$0f
+               tax
+               lda     Bauds,x
+               cmp     #$ff
+               bne     @L5
+               lda     #ErrBaudNotAvail
+               bne     @L9
+
+@L5:           jsr     sys_bank                ; Indirect segment to system bank
+               tax
+               lda     tmp1
+               and     #$0f
+               sta     BaudCode
+               lda     tmp1
+               and     #%11100000
+               ora     #%00010000
+               sta     tmp1
+               txa
+               and     #$0f
+               ora     tmp1
+               ldy     #RegControl
+               sta     (acia),y
+
+; Set new parity
+
+@L7:           lda     tmp2
+               sta     RtsOff
+               ora     #%00001000
+               ldy     #RegCommand
+               sta     (acia),y
+               jsr     restore_bank            ; Restore indirect bank
+               lda     #0
+@L9:           ldx     #0
+               rts
+
+.rodata
+Bauds:
+   .byte $01,$03,$04,$06,$07,$08,$0a,$0c,$0e,$0f,$ff,$ff,$ff,$ff,$ff,$ff
+     ;in:  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+     ;baud50 110 134   3   6  12  24  48  96  19  38  57 115 230 exp exp
+     ;out masks: $0F=Baud, val$FF=err
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_done (void);
+; /* Close the port, deinstall the interrupt hander. You MUST call this function
+;  * before terminating the program, otherwise the machine may crash later. If
+;  * in doubt, install an exit handler using atexit(). The function will do
+;  * nothing, if it was already called.
+;  */
+;
+
+
+_rs232_done:
+       bit     Initialized             ;** check initialized
+               bpl     @L9
+
+; Stop interrupts, drop DTR
+
+       lda     RtsOff
+       and     #%11100010
+       ora     #%00000010
+       ldx     IndReg
+       ldy     #$0F
+       sty     IndReg                  ; Set indirect to system bank
+       ldy     #RegCommand
+       sta     (acia),y
+       stx     IndReg                  ; Restore old indirect bank
+
+; Flag uninitialized
+
+@L9:           lda     #$00
+       sta     Initialized
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_get (char* B);
+; /* Get a character from the serial port. If no characters are available, the
+;  * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+;  */
+;
+
+_rs232_get:
+       jsr     CheckInitialized        ; Check if initialized
+       bcc     @L1
+       rts
+
+; Check for bytes to send
+
+@L1:   sta     ptr1
+       stx     ptr1+1                  ; Store pointer to received char
+       ldx     SendFreeCnt
+       cpx     #$ff
+       beq     @L2
+       lda     #$00
+       jsr     TryToSend
+
+; Check for buffer empty
+
+@L2:   lda     RecvFreeCnt
+       cmp     #$ff
+       bne     @L3
+       lda     #ErrNoData
+       ldx     #0
+       rts
+
+; Check for flow stopped & enough free: release flow control
+
+@L3:   ldx     Stopped
+       beq     @L4
+       cmp     #63
+       bcc     @L4
+       lda     #$00
+       sta     Stopped
+       lda     RtsOff
+       ora     #%00001000
+       ldx     IndReg
+       ldy     #$0F                    ; Set indirect to system bank
+       sty     IndReg
+       ldy     #RegCommand
+       sta     (acia),y
+       stx     IndReg
+
+; Get byte from buffer
+
+@L4:   ldx     IndReg
+       lda     #BufferSeg              ; Set indirect to buffer bank
+       sta     IndReg
+       ldy     RecvHead
+       lda     (RecvBuf),y
+       stx     IndReg                  ; Restore indirect bank
+       inc     RecvHead
+       inc     RecvFreeCnt
+               ldx     #$00
+       sta     (ptr1,x)
+               txa                             ; Return code = 0
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_put (char B);
+; /* Send a character via the serial port. There is a transmit buffer, but
+;  * transmitting is not done via interrupt. The function returns
+;  * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+;  */
+;
+
+_rs232_put:
+       jsr     CheckInitialized        ; Check initialized
+       bcc     @L1
+       rts
+
+; Try to send
+
+@L1:   ldx     SendFreeCnt
+       cpx     #$ff
+       beq     @L2
+       pha
+       lda     #$00
+       jsr     TryToSend
+       pla
+
+; Put byte into send buffer & send
+
+@L2:   ldx     SendFreeCnt
+       bne     @L3
+       lda     #ErrOverflow
+       ldx     #$00
+       rts
+         
+; There is enough room (character still in A)
+
+@L3:   ldx     IndReg
+               ldy     #BufferSeg              ; Set indirect to buffer segment
+       sty     IndReg
+       ldy     SendTail
+       sta     (SendBuf),y
+       stx     IndReg                  ; Restore indirect bank
+       inc     SendTail
+       dec     SendFreeCnt
+       lda     #$ff
+       jsr     TryToSend
+       lda     #$00
+       tax
+               rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_pause (void);
+; /* Assert flow control and disable interrupts. */
+;
+
+_rs232_pause:
+; Check initialized
+       jsr     CheckInitialized
+       bcc     @L1
+       rts
+
+; Assert flow control
+
+@L1:   lda     RtsOff
+       sta     Stopped
+       jsr     sys_bank                ; Set indirect to system bank
+       ldy     #RegCommand
+       sta     (acia),y
+
+; Delay for flow stop to be received
+
+       ldx     BaudCode
+       lda     PauseTimes,x
+       jsr     DelayMs
+
+; Stop rx interrupts
+
+       lda     RtsOff
+       ora     #$02
+       ldy     #RegCommand
+       sta     (acia),y
+               jsr     restore_bank            ; Restore indirect segment
+       lda     #0
+       tax
+       rts
+
+
+.rodata
+; Delay times: 32 byte-receive times in milliseconds, or 100 max.
+; Formula = 320,000 / baud
+PauseTimes:
+               .byte 100,100,100,100,100,100,100,067,034,017,009,006,003,002,001,001
+          ;in:  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
+          ;baud50 110 134   3   6  12  24  48  96  19  38  57 115 230 exp exp
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_unpause (void);
+; /* Re-enable interrupts and release flow control */
+;
+
+_rs232_unpause:
+; Check initialized
+       jsr     CheckInitialized
+       bcc     @L1
+       rts
+
+; Re-enable rx interrupts & release flow control
+
+@L1:   lda     #$00
+       sta     Stopped
+       lda     RtsOff
+       ora     #%00001000
+       ldx     IndReg
+       ldy     #$0F
+       sty     IndReg                  ; Set indirect to system bank
+       ldy     #RegCommand
+       sta     (acia),y
+       stx     IndReg                  ; Restore indirect bank
+
+; Poll for stalled char & exit
+
+       jsr     PollReceive
+       lda     #0
+       tax
+       rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_status (unsigned char* status,
+;                                         unsigned char* errors);
+; /* Return the serial port status. */
+;
+
+_rs232_status:
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax
+       sta     ptr1
+       stx     ptr1+1
+       jsr     CheckInitialized
+               bcs     @L9
+
+; Get status
+
+       ldx     IndReg                  ; Save indirect segment
+       lda     #$0F
+       sta     IndReg                  ; Set system bank as indirect segment
+       ldy     #RegStatus
+       lda     (acia),y                ; Read status register
+       stx     IndReg
+       ldy     #0
+       sta     (ptr1),y
+       jsr     PollReceive             ; bug-recovery hack
+       lda     Errors
+       ldy     #0
+               sta     (ptr2),y
+               tya
+       tax
+@L9:   rts
+
+;----------------------------------------------------------------------------
+;
+; RS232 interrupt handler.
+; The RS232 handler will be called with        the system bank as indirect bank
+; and all registers saved.
+;
+
+k_rs232:
+       ldy     #RegStatus
+               lda     (acia),y                ; check for byte received
+       and     #$08
+       beq     @L9                     ; Nothing to receive
+               lda     (acia),y                ; check for receive errors
+       and     #$07
+               beq     @L1
+       inc     Errors
+@L1:           ldy     #RegData
+       lda     (acia),y                ; get byte and put into receive buffer
+       ldx     RecvFreeCnt
+       beq     @L3
+       ldy     #BufferSeg
+       sty     IndReg
+               ldy     RecvTail
+       sta     (RecvBuf),y             ; Store received character
+       lda     #$0F
+       sta     IndReg                  ; Restore indirect segment
+       inc     RecvTail
+       dec     RecvFreeCnt
+       cpx     #33                     ; check for buffer space low
+               bcs     @L9
+
+; Assert flow control
+
+@L2:   lda     RtsOff                  ; assert flow control if buffer space too low
+       ldy     #RegCommand
+       sta     (acia),y
+       sta     Stopped
+       rts
+
+; Drop this char
+
+@L3:   inc     DropCnt+0               ;not time-critical
+       bne     @L9
+       inc     DropCnt+1
+       bne     @L9
+       inc     DropCnt+2
+       bne     @L9
+       inc     DropCnt+3
+@L9:           rts
+
+
+;----------------------------------------------------------------------------
+;
+; CheckInitialized  -  internal check if initialized
+; Set carry and an error code if not initialized, clear carry and do not
+; change any registers if initialized.
+;
+
+CheckInitialized:
+       bit     Initialized
+       bmi     @L1
+       lda     #ErrNotInitialized
+       ldx     #0
+       sec
+       rts
+
+@L1:   clc
+       rts
+
+;----------------------------------------------------------------------------
+; Try to send a byte. Internal routine. A = TryHard
+
+TryToSend:
+       sta     tmp1            ; Remember tryHard flag
+       ldx     IndReg          ; Save indirect segment
+       lda     #$0F
+       sta     IndReg          ; Set system segment as indirect segment
+@L0:           lda     SendFreeCnt
+       cmp     #$ff
+       beq     @L3             ; Bail out
+
+; Check for flow stopped
+
+@L1:   lda     Stopped
+               bne     @L3             ; Bail out
+
+; Check that the UART is ready to send
+
+@L2:           ldy     #RegStatus
+       lda     (acia),y
+       and     #$10
+       bne     @L4
+       bit     tmp1            ; Keep trying if must try hard
+               bmi     @L0
+@L3:           stx     IndReg          ; Restore indirect segment
+       rts
+
+; Send byte and try again
+
+@L4:           lda     #BufferSeg
+       sta     IndReg
+       ldy     SendHead
+       lda     (SendBuf),y
+       ldy     #$0F
+       sty     IndReg
+       ldy     #RegData
+       sta     (acia),y
+       inc     SendHead
+       inc     SendFreeCnt
+       jmp     @L0
+
+
+;----------------------------------------------------------------------------
+;
+; PollReceive - poll for rx char
+;   This function is useful in odd cases where the 6551 has a character in
+;   it but it fails to raise an NMI.  It might be edge-triggering conditions?
+;   Actually, I'm not entirely sure that this condition can still arrise, but
+;   calling this function does no harm.
+;
+
+PollReceive:
+       ldx     IndReg                  ; Save indirect segment
+       lda     #$0F
+       sta     IndReg                  ; Set system bank as indirect segment
+       ldy     #RegStatus
+       lda     (acia),y
+       and     #$08
+       beq     @L9
+       lda     (acia),y                ; Read a second time? ###
+       and     #$08
+       beq     @L9
+       ldy     #RegData
+       lda     (acia),y
+               ldy     RecvFreeCnt
+       beq     @L9
+       ldy     #BufferSeg
+       sty     IndReg
+               ldy     RecvTail
+       sta     (RecvBuf),y
+       inc     RecvTail
+       dec     RecvFreeCnt
+@L9:   stx     IndReg                  ; Restore indirect segment
+       rts
+
+;----------------------------------------------------------------------------
+;
+;  DelayMs : delay for given number of milliseconds
+;    This implementation isn't very rigerous; it merely delays for the
+;    approximate number of clock cycles for the processor speed.
+;    Algorithm:
+;       repeat for number of milliseconds:
+;          repeat for number of MHz of cpu speed:
+;             delay for 1017 clock cycles
+;
+
+DelayMs:                       ;( .A=milliseconds )
+@L1:           ldy     #2              ; 2MHz
+@L2:           ldx     #203            ;(2)
+@L3:           dex                     ;(2)
+       bne     @L3             ;(3) // 1017 cycles
+       dey
+       bne     @L2
+       sec
+       sbc     #1
+       bne     @L1
+       rts
+
+.end
+
+
+
diff --git a/libsrc/cbm610/zeropage.inc b/libsrc/cbm610/zeropage.inc
new file mode 100644 (file)
index 0000000..5e9ba5d
--- /dev/null
@@ -0,0 +1,100 @@
+;
+; Zero page variables for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+ExecReg                = $0000
+IndReg         = $0001
+
+; Up to $20 and $60-8F used by runtime and fixed values
+; -----------------------------------
+
+KbdScanBuf             = $20           ; Intermediate for keyboard scan
+; RS232 stuff
+RecvHead       = $21           ; Head of receive buffer
+RecvTail       = $22           ; Tail of receive buffer
+RecvFreeCnt    = $23           ; Number of bytes in receive buffer
+SendHead       = $24           ; Head of send buffer
+SendTail       = $25           ; Tail of send buffer
+SendFreeCnt    = $26           ; Number of bytes free in send buffer
+
+FileNameAdrLo          = $90
+FileNameAdrHi          = $91
+FileNameAdrSeg         = $92
+SaveAdrLow             = $93
+SaveAdrHi              = $94
+SaveAdrSeg             = $95
+EndAdrLow              = $96
+EndAdrHi               = $97
+EndAdrSeg              = $98
+StartAdrLow            = $99
+StartAdrHi             = $9A
+StartAdrSeg            = $9B
+Status                 = $9C
+FileNameLen            = $9D
+LogicalAdr             = $9E
+FirstAdr               = $9F
+SecondAdr              = $A0
+DefInpDev              = $A1
+DefOutDev              = $A2
+TapeBufPtr             = $A3
+TapeBufPtrSeg          = $A5
+rs232BufPtr            = $A6
+rs232BufPtrSeg         = $A8
+StopKeyFlag            = $A9
+CTemp                  = $AA
+snsw1                  = $AB
+SegChgPtr              = $AC
+PChighSave             = $AE
+PClowSave              = $AF
+SRSave                 = $B0
+ACSave                 = $B1
+XRSave                 = $B2
+YRSave                 = $B3
+SPSave                 = $B4
+IndSegSave             = $B5
+IRQSaveHi              = $B7
+IRQSaveLo              = $B8
+Adr1                   = $B9
+Adr2                   = $BB
+MoniCntr               = $BD
+MoniTmp                = $BE
+MoniDevNr              = $BF
+PgmKeyBuf              = $C0
+PgmKeyPtr              = $C2
+sedsal                 = $C4
+sedeal                 = $C6
+CharPtr                = $C8
+CURS_Y                 = $CA
+CURS_X                 = $CB
+GrafMode               = $CC
+LastIndex              = $CD
+LastLine               = $CE
+LastCol                = $CF
+crsw                   = $D0
+KeyIndex               = $D1
+QuoteSw                = $D2
+Insrt                  = $D3
+Config                 = $D4
+LastLinePos            = $D5
+PgmKeyIndex            = $D6
+RepeatCount            = $D7
+RepeatDelay            = $D8
+sedt1                  = $D9           ; Temp
+sedt2                  = $DA           ; Temp, frequently used
+PrtData                = $DB
+ScreenTop              = $DC
+ScreenBot              = $DD
+ScreenLeft             = $DE
+ScreenRight            = $DF
+ModKey                 = $E0
+NorKey                 = $E1
+BitTable               = $E2
+
+
+
+
+
diff --git a/libsrc/common/.cvsignore b/libsrc/common/.cvsignore
new file mode 100644 (file)
index 0000000..1f88d30
--- /dev/null
@@ -0,0 +1,40 @@
+fclose.s
+fgets.s
+fprintf.s
+strdup.s
+calloc.s
+_fopen.s
+fputs.s
+fread.s
+fwrite.s
+gets.s
+realloc.s
+bsearch.s
+printf.s
+_hextab.s
+malloc.s
+free.s
+vfprintf.s
+fdopen.s
+_afailed.s
+fopen.s
+fgetc.s
+fputc.s
+puts.s
+_printf.s
+vprintf.s
+vsprintf.s
+sprintf.s
+abort.s
+errormsg.s
+_hadd.s
+cprintf.s
+vcprintf.s
+freopen.s
+perror.s
+qsort.s
+strxfrm.s
+strtok.s
+locale.s
+putchar.s
+getchar.s
diff --git a/libsrc/common/Makefile b/libsrc/common/Makefile
new file mode 100644 (file)
index 0000000..2bbeede
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -g -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS = fclose.o fgets.o fprintf.o strdup.o calloc.o _fopen.o\
+        fputs.o fread.o fwrite.o gets.o realloc.o bsearch.o strxfrm.o\
+        printf.o _hextab.o malloc.o free.o vfprintf.o fdopen.o strtok.o\
+        _afailed.o fopen.o fgetc.o fputc.o puts.o gets.o perror.o getchar.o\
+        _printf.o vprintf.o vsprintf.o sprintf.o abort.o qsort.o putchar.o\
+        errormsg.o _hadd.o cprintf.o vcprintf.o freopen.o locale.o
+
+S_OBJS = isalpha.o isdigit.o _file.o fmisc.o strlower.o strchr.o tolower.o\
+        toupper.o errno.o strcpy.o strlen.o strcat.o strcmp.o itoa.o\
+        strupper.o isalpha.o isalnum.o isgraph.o islower.o isupper.o\
+                isprint.o ispunct.o isspace.o isxdigit.o isblank.o strrchr.o\
+        _stksize.o _heap.o stricmp.o strncmp.o strncpy.o atoi.o setjmp.o\
+        longjmp.o rand.o atexit.o memset.o memcpy.o memchr.o memcmp.o\
+        ltoa.o strcspn.o strncat.o strpbrk.o strspn.o abs.o labs.o jmpvec.o\
+        _fdesc.o stkcheck.o zerobss.o copydata.o _swap.o strstr.o strcoll.o\
+        _sys.o getcpu.o _oserror.o strerror.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f *~
+       @rm -f $(C_OBJS:.o=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
diff --git a/libsrc/common/_afailed.c b/libsrc/common/_afailed.c
new file mode 100644 (file)
index 0000000..6600bf8
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * _afailed.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+void _afailed (char* file, unsigned line)
+{
+    fprintf (stderr, "ASSERTION FAILED IN %s(%u)\n", file, line);
+    exit (2);
+}
+
+
+
diff --git a/libsrc/common/_fdesc.s b/libsrc/common/_fdesc.s
new file mode 100644 (file)
index 0000000..2ffadd5
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; int _fdesc (void);
+; /* Find a free descriptor slot */
+
+
+               .export         __fdesc
+       .import         return0, __filetab
+       .importzp       tmp1
+
+__fdesc:
+       ldy     #0
+L1:    lda     __filetab+1,y   ; load flags
+       beq     L2              ; jump if empty (== CLOSED)
+       iny
+       iny
+       cpy     #16             ; Done?
+       bne     L1
+
+; File table is full
+
+       jmp     return0
+
+; Free slot found
+
+L2:            sty     tmp1            ; Offset
+       lda     #<__filetab
+       ldx     #>__filetab
+       clc
+       adc     tmp1
+       tay
+       txa
+       adc     #0
+       tax
+       tya
+       rts
+
+
diff --git a/libsrc/common/_file.h b/libsrc/common/_file.h
new file mode 100644 (file)
index 0000000..8a27796
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * _file.h
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ *
+ */
+
+
+
+#ifndef __FILE_H
+#define __FILE_H
+
+
+
+#include <stdio.h>
+
+
+
+/* Definition of struct _FILE */
+struct _FILE {
+    char       f_fd;
+    char       f_flags;
+};
+
+/* File table. Beware: FOPEN_MAX is hardcoded in the ASM files! */
+extern FILE _filetab [FOPEN_MAX];
+
+/* Flags field */
+#define _FCLOSED       0x00
+#define        _FOPEN          0x01
+#define _FEOF          0x02
+#define _FERROR                0x04
+
+
+
+FILE* _fopen (const char* name, const char* mode, FILE* f);
+/* Open the specified file and fill the descriptor values into f */
+
+FILE* _fdesc (void);
+/* Find a free FILE descriptor */
+
+
+
+/* End of _file.h */
+#endif
+
+
+
diff --git a/libsrc/common/_file.s b/libsrc/common/_file.s
new file mode 100644 (file)
index 0000000..19e6ac2
--- /dev/null
@@ -0,0 +1,28 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; Data for the stdio file stream.
+;
+
+       .export         __filetab, _stdin, _stdout, _stderr
+
+.data
+
+__filetab:
+in:    .byte   0, 1            ; stdin
+out:   .byte   1, 1            ; stdout
+err:   .byte   2, 1            ; stderr
+       .byte   0, 0            ; free slot
+       .byte   0, 0            ; free slot
+       .byte   0, 0            ; free slot
+       .byte   0, 0            ; free slot
+       .byte   0, 0            ; free slot
+
+_stdin:
+       .word   in
+
+_stdout:
+       .word   out
+
+_stderr:
+       .word   err
diff --git a/libsrc/common/_fopen.c b/libsrc/common/_fopen.c
new file mode 100644 (file)
index 0000000..3ae53a5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * _fopen.c
+ *
+ * Ullrich von bassewitz, 17.06.1997
+ */
+
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+static unsigned char amode_to_bmode (const char* mode)
+/* Convert ASCII mode (like for fopen) to binary mode (for open) */
+{
+    char         c;
+    char         flag = 0;
+    unsigned char binmode = 0;
+
+    while (c = *mode++) {
+        switch(c) {
+            case 'w':
+                binmode = O_WRONLY;
+                break;
+            case 'r':
+                binmode = O_RDONLY;
+                break;
+            case '+':
+                binmode = O_RDWR;
+                break;
+            /* a,b missing */
+        }
+    }
+    if (binmode == 0) {
+       _errno = EINVAL;
+    }
+    return binmode;
+}
+
+
+
+FILE* _fopen (const char* name, const char* mode, FILE* f)
+/* Open the specified file and fill the descriptor values into f */
+{
+    int          fd;
+    unsigned char binmode;
+
+
+    /* Convert ASCII mode to binary mode */
+    if ((binmode = amode_to_bmode (mode)) == 0) {
+       /* Invalid mode, _errno already set */
+        return 0;
+    }
+
+    /* Open the file */
+    fd = open (name, binmode);
+    if (fd == -1) {
+               /* Error - _oserror is set */
+               return 0;
+    }
+
+    /* Remember fd, mark the file as opened */
+    f->f_fd    = fd;
+    f->f_flags = _FOPEN;
+
+    /* Return the file descriptor */
+    return f;
+}
+
+
+
diff --git a/libsrc/common/_hadd.c b/libsrc/common/_hadd.c
new file mode 100644 (file)
index 0000000..190875d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * _hadd.c
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#include <stddef.h>
+#include "_heap.h"
+
+
+
+void _hadd (void* mem, size_t size)
+/* Add an arbitrary memory block to the heap. This function is used by
+ * free(), but it does also allow usage of otherwise unused memory
+ * blocks as heap space. The given block is entered in the free list
+ * without any checks, so beware!
+ */
+{
+    struct freeblock* f;
+    struct freeblock* left;
+    struct freeblock* right;
+
+    if (size >= sizeof (struct freeblock)) {
+
+       /* Set the admin data */
+       f = (struct freeblock*) mem;
+       f->size = size;
+
+       /* Check if the freelist is empty */
+       if (_hfirst == 0) {
+
+           /* The freelist is empty until now, insert the block */
+           f->prev = 0;
+           f->next = 0;
+           _hfirst = f;
+           _hlast  = f;
+
+       } else {
+
+           /* We have to search the free list. As we are doing so, we check
+            * if it is possible to combine this block with another already
+            * existing block. Beware: The block may be the "missing link"
+             * between *two* other blocks.
+            */
+           left = 0;
+           right = _hfirst;
+           while (right && f > right) {
+               left = right;
+               right = right->next;
+           }
+
+
+           /* Ok, the current block must be inserted between left and right (but
+            * beware: one of the two may be zero!). Also check for the condition
+            * that we have to merge two or three blocks.
+            */
+           if (right) {
+               /* Check if we must merge the block with the right one */
+               if (((int) f) + size == (int) right) {
+                   /* Merge with the right block */
+                   f->size += right->size;
+                   if (f->next = right->next) {
+                               f->next->prev = f;
+                   } else {
+                       /* This is now the last block */
+                       _hlast = f;
+                   }
+               } else {
+                   /* No merge, just set the link */
+                   f->next = right;
+                   right->prev = f;
+               }
+           } else {
+               f->next = 0;
+               /* Special case: This is the new freelist end */
+               _hlast = f;
+           }
+           if (left) {
+               /* Check if we must merge the block with the left one */
+               if ((int) f == ((int) left) + left->size) {
+                   /* Merge with the left block */
+                   left->size += f->size;
+                   if (left->next = f->next) {
+                       left->next->prev = left;
+                   } else {
+                       /* This is now the last block */
+                       _hlast = left;
+                   }
+               } else {
+                   /* No merge, just set the link */
+                   left->next = f;
+                   f->prev = left;
+               }
+           } else {
+               f->prev = 0;
+               /* Special case: This is the new freelist start */
+               _hfirst = f;
+           }
+       }
+    }
+}
+
+
+
diff --git a/libsrc/common/_heap.h b/libsrc/common/_heap.h
new file mode 100644 (file)
index 0000000..3f8d780
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * _heap.h
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ *
+ */
+
+
+
+#ifndef __HEAP_H
+#define __HEAP_H
+
+
+
+/* Space needed for administering used blocks */
+#define HEAP_ADMIN_SPACE        sizeof (unsigned)
+
+/* The data type used to implement the free list. 
+ * Beware: Field order is significant!
+ */
+struct freeblock {
+    unsigned           size;
+    struct freeblock*          next;
+    struct freeblock*          prev;
+};
+
+
+
+/* Variables that describe the heap */
+extern unsigned*                 _horg;        /* Bottom of heap */
+extern unsigned*         _hptr;        /* Current top */
+extern unsigned*         _hend;        /* Upper limit */
+extern struct freeblock*  _hfirst;     /* First free block in list */
+extern struct freeblock*  _hlast;      /* Last free block in list */
+
+
+
+/* End of _heap.h */
+
+#endif
+
+
+
diff --git a/libsrc/common/_heap.s b/libsrc/common/_heap.s
new file mode 100644 (file)
index 0000000..427ecae
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; Heap variables and initialization.
+;
+
+       .export         __horg, __hptr, __hend, __hfirst, __hlast
+       .export         __hinit
+               .import         __BSS_RUN__, __BSS_SIZE__, __stksize
+       .importzp       sp
+
+.data
+
+__horg:
+               .word   __BSS_RUN__+__BSS_SIZE__        ; Linker calculates this symbol
+__hptr:
+       .word   __BSS_RUN__+__BSS_SIZE__        ; Dito
+__hend:
+               .word   __BSS_RUN__+__BSS_SIZE__
+__hfirst:               
+       .word   0
+__hlast:
+       .word   0
+
+
+;
+; Initialization. Must be called from startup!
+;
+
+.code
+
+__hinit:
+       sec
+       lda     sp
+       sbc     __stksize
+       sta     __hend
+       lda     sp+1
+       sbc     __stksize+1
+       sta     __hend+1
+       rts
+
+
+
+
+
diff --git a/libsrc/common/_hextab.c b/libsrc/common/_hextab.c
new file mode 100644 (file)
index 0000000..fc82f17
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * Hex conversion table. Must be in C since the compiler will convert
+ * to the correct character set for the target platform.
+ */
+
+
+
+/* Data in this module is read-only, put it into the RODATA segment */
+#pragma dataseg ("RODATA")
+
+const unsigned char _hextab [16] = {
+    '0', '1', '2', '3', '4', '5', '6', '7',
+    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+
diff --git a/libsrc/common/_oserror.s b/libsrc/common/_oserror.s
new file mode 100644 (file)
index 0000000..1907393
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 16.05.2000
+;
+; extern unsigned char _oserror;
+; /* Operating system specific errors from the low level functions */
+
+
+               .export         __oserror
+
+.bss
+
+__oserror:
+       .res    1
+
diff --git a/libsrc/common/_printf.c b/libsrc/common/_printf.c
new file mode 100644 (file)
index 0000000..5bb72e3
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Helper function for the printf family.
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "_printf.h"
+
+
+
+/* Use static variables for locals */
+#pragma staticlocals (1);
+
+
+
+int _printf (struct outdesc* d, char* f, va_list ap)
+{
+    outfunc fout;              /* Output function */
+    unsigned char type;                /* variable argument type */
+    char str [20];             /* string buffer */
+    char c;                            /* Current format char */
+    char leftjust;             /* left justify string */
+    char addsign;                      /* always add + or - */
+    char addblank;             /* add blank instead of + */
+    char altform;                      /* alternate form? */
+    char padchar;              /* pad with space or zeroes? */
+    char islong;                       /* l modifier found */
+    unsigned arglen;           /* length of argument string */
+    unsigned prec;             /* Precision */
+    unsigned width;            /* Width of output field */
+    int  i;                    /* Integer value */
+    long l;                    /* Long value */
+    char* sptr;                        /* pointer to argument string */
+    register char* s;                  /* work pointer to argument string */
+
+    /* Remember the format string in a register variable for shorter code */
+    register char* format = f;
+
+    /* Remember the output function in a local variable for speed and size */
+    fout = d->fout;
+
+    /* */
+    d->ccount = 0;
+    while (c = *format++) {
+
+       if (c != '%') {
+                   fout (d, &c, 1);
+           continue;
+       }
+
+       /* %%? */
+       if (*format == '%') {
+                   fout (d, format, 1);
+           ++format;
+           continue;
+       }
+
+       /* format is: %[flags][width][.precision][mod]type */
+
+       /* flags */
+       leftjust = addsign = addblank = altform = 0;
+               do {
+           switch (c = *format) {
+
+                       case '-':
+                   leftjust = 1;
+                   break;
+
+               case '+':
+                   addsign = 1;
+                   break;
+
+               case '#':
+                   altform = 1;
+                   break;
+
+               case ' ':
+                   addblank = 1;
+                   break;
+
+               default:
+                   goto flags_done;
+
+           }
+           ++format;
+       } while (1);
+flags_done:
+
+       /* width */
+       padchar = ' ';
+       if (*format == '0') {
+           padchar = '0';
+           ++format;
+       }
+       if (*format == '*') {
+           width = va_arg (ap, int);
+           ++format;
+       } else {
+            width = 0;
+           while (isdigit (c = *format)) {
+               width = width * 10 + (c - '0');
+               ++format;
+           }
+       }
+
+       /* precision */
+        prec = 0;
+       if (*format == '.') {
+           ++format;
+           if (*format == '*') {
+               prec = va_arg (ap, int);
+               ++format;
+           } else {
+               while (isdigit (c = *format)) {
+                   prec = prec * 10 + (c - '0');
+                   ++format;
+               }
+           }
+       }
+
+       /* modifiers */
+       islong = 0;
+               while (strchr ("FNhlL", c = *format)) {
+           switch (c) {
+
+               case 'l':
+                   islong = 1;
+                   break;
+
+           }
+           ++format;
+       }
+
+       /* Check the format specifier */
+       sptr = s = str;
+       type = *format++;
+               switch (type) {
+
+                   case 'c':
+               str [0] = va_arg (ap, char);
+               str [1] = 0;
+               break;
+
+                   case 'd':
+                   case 'i':
+               if (addsign) {
+                   *s++ = '+';
+               } else if (addblank) {
+                   *s++ = ' ';
+               }
+               if (islong) {
+                   ltoa (va_arg (ap, long), s, 10);
+               } else {
+                   itoa (va_arg (ap, int), s, 10);
+               }
+               break;
+
+            case 'n':
+               *va_arg (ap, int*) = d->ccount;
+               continue;
+
+                   case 'o':
+               if (islong) {
+                   l = va_arg (ap, unsigned long);
+                   if (altform && (l || prec)) {
+                       *s++ = '0';
+                   }
+                           ultoa (l, s, 8);
+               } else {
+                   i = va_arg (ap, unsigned);
+                   if (altform && (i || prec)) {
+                       *s++ = '0';
+                   }
+                   utoa (i, s, 8);
+               }
+               break;
+
+                   case 's':
+               sptr = va_arg (ap, char*);
+               break;
+
+           case 'u':
+               if (islong) {
+                   ultoa (va_arg (ap, unsigned long), str, 10);
+               } else {
+                   utoa (va_arg (ap, unsigned), str, 10);
+               }
+               break;
+
+           case 'x':
+           case 'X':
+               if (altform) {
+                   *s++ = '0';
+                   *s++ = 'X';
+               }
+               if (islong) {
+                           ultoa (va_arg (ap, unsigned long), s, 16);
+               } else {
+                   utoa (va_arg (ap, unsigned), s, 16);
+               }
+               if (type == 'x') {
+                   strlower (str);
+               }
+               break;
+
+           default:
+               /* Unknown type char - skip it */
+               continue;
+
+       }
+
+       /* Do argument string formatting */
+       arglen = strlen (sptr);
+       if (prec && prec < arglen) {
+           arglen = prec;
+       }
+               if (width > arglen) {
+           width -= arglen;            /* padcount */
+       } else {
+           width = 0;
+       }
+
+       /* Do padding on the left side if needed */
+       if (!leftjust) {
+           /* argument right justified */
+           while (width) {
+               fout (d, &padchar, 1);
+               --width;
+           }
+               }
+
+       /* Output the argument string */
+       fout (d, sptr, arglen);
+
+       /* Output right padding bytes if needed */
+       if (leftjust) {
+           /* argument left justified */
+           while (width) {
+                       fout (d, &padchar, 1);
+               --width;
+           }
+       }
+
+    }
+}
+
+
+
diff --git a/libsrc/common/_printf.h b/libsrc/common/_printf.h
new file mode 100644 (file)
index 0000000..d4d5ed6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * _printf.h
+ *
+ * (C) Copyright 1998 Ullrich von Bassewitz (uz@ibb.schwaben.com)
+ *
+ */
+
+
+
+#ifndef __PRINTF_H
+#define __PRINTF_H
+
+
+
+/* Forward */
+struct outdesc;
+
+/* Type of the function that is called to output data */
+typedef void (*outfunc) (struct outdesc* desc, char* buf, unsigned count);
+
+
+
+struct outdesc {
+    outfunc            fout;           /* Routine used to output data */
+    int                ccount;         /* Character counter */
+    void*      ptr;            /* Data internal to print routine */
+    unsigned   uns;            /* Data internal to print routine */
+};
+
+
+
+/* Internal formatting routine */
+int _printf (struct outdesc* d, char* format, va_list ap);
+
+
+
+/* End of _printf.h */
+#endif
+
+
+
diff --git a/libsrc/common/_stksize.s b/libsrc/common/_stksize.s
new file mode 100644 (file)
index 0000000..9d8d607
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; Stack default size definition
+;
+
+       .export         __stksize
+
+.data
+
+__stksize:
+               .word   $800            ; 2K
+
+
+
diff --git a/libsrc/common/_swap.s b/libsrc/common/_swap.s
new file mode 100644 (file)
index 0000000..7f3f98f
--- /dev/null
@@ -0,0 +1,62 @@
+;
+; Ullrich von Bassewitz, 09.12.1998
+;
+; void __fastcall__ _swap (void* p, void* q, size_t size);
+;
+
+       .export         __swap
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+
+__swap:        sta     ptr3            ; Save size
+       stx     ptr3+1
+
+       jsr     popax           ; Get q
+       sta     ptr2
+       stx     ptr2+1
+
+       jsr     popax           ; Get p
+       sta     ptr1
+       stx     ptr1+1
+
+; Prepare for swap
+
+       ldy     #$00
+
+; Swap 256 byte blocks
+
+       ldx     ptr3+1
+       beq     @L2
+
+@L1:   lda     (ptr1),y
+       tax
+       lda     (ptr2),y
+       sta     (ptr1),y
+       txa
+       sta     (ptr2),y
+       iny
+       bne     @L1
+       dec     ptr3+1
+       bne     @L1
+
+; Swap remaining bytes (Y is zero)
+
+@L2:   ldx     ptr3
+       beq     @L9
+
+@L3:           lda     (ptr1),y
+       tax
+       lda     (ptr2),y
+       sta     (ptr1),y
+       txa
+       sta     (ptr2),y
+       iny
+       dec     ptr3
+       bne     @L3
+
+; Done
+
+@L9:   rts
+
+
diff --git a/libsrc/common/_sys.s b/libsrc/common/_sys.s
new file mode 100644 (file)
index 0000000..c92c1d8
--- /dev/null
@@ -0,0 +1,72 @@
+;
+; void __fastcall__ _sys (struct regs* r);
+;
+; Ullrich von Bassewitz, 16.12.1998
+;
+
+       .export         __sys
+       .import         jmpvec
+       .importzp       ptr1
+
+
+__sys: sta     ptr1
+       stx     ptr1+1          ; Save the pointer to r
+
+; Fetch the PC and store it into the jump vector
+
+       ldy     #5
+       lda     (ptr1),y
+       sta     jmpvec+2
+       dey     
+       lda     (ptr1),y
+       sta     jmpvec+1
+
+; Get the flags, mask unnecessary bits and push them. Push a
+
+       dey
+       lda     (ptr1),y
+       and     #%11001011
+       pha
+       ldy     #0
+       lda     (ptr1),y
+       pha
+
+; Get and assign X and Y
+
+       iny
+       lda     (ptr1),y
+       tay
+       iny
+       lda     (ptr1),y
+       tay
+
+; Set a and the flags, call the machine code routine
+
+       pla
+       plp
+       jsr     jmpvec
+
+; Back from the routine. Save the flags and a
+
+       php
+       pha
+
+; Put the register values into the regs structure
+
+       tya
+       ldy     #2
+       sta     (ptr1),y
+       dey
+       txa
+       sta     (ptr1),y
+       dey
+       pla
+       sta     (ptr1),y
+       ldy     #3
+       pla
+       sta     (ptr1),y
+
+; Done
+
+       rts
+
diff --git a/libsrc/common/abort.c b/libsrc/common/abort.c
new file mode 100644 (file)
index 0000000..6af3a59
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * abort.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+void abort (void)
+{
+    fputs ("ABNORMAL PROGRAM TERMINATION\n", stderr);
+    exit (3);
+}
+
+
+
diff --git a/libsrc/common/abs.s b/libsrc/common/abs.s
new file mode 100644 (file)
index 0000000..89161ab
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; int abs (int x);
+;
+
+       .export         _abs
+       .import         negax
+
+_abs:  dex
+       inx                     ; test hi byte
+       bpl     L1
+       jmp     negax           ; Negate if negative
+L1:    rts
+
+
+
diff --git a/libsrc/common/atexit.s b/libsrc/common/atexit.s
new file mode 100644 (file)
index 0000000..5d94d36
--- /dev/null
@@ -0,0 +1,69 @@
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int atexit (void (*f) (void));
+;
+
+; The exit functions
+
+       .export         _atexit, doatexit
+       .import         __errno, jmpvec
+
+.bss
+ecount:        .byte   0               ; Really an index, inc'ed by 2
+efunc:         .word   0,0,0,0,0       ; 5 exit functions
+maxcount = * - efunc
+
+
+.code
+
+_atexit:
+       ldy     ecount
+       cpy     #maxcount       ; slot available?
+       beq     E0              ; jump if no
+
+; Enter the function into the table
+
+       sta     efunc,y
+       iny
+       txa
+       sta     efunc,y
+       iny
+       sty     ecount
+
+; Done, return zero
+
+       lda     #0
+       tax
+       rts
+
+; Error, no space left
+
+E0:    lda     #$FF
+               sta     __errno         ; Use -1 until codes are defined ###
+       sta     __errno+1
+       tax
+       rts
+
+; Function called from exit
+
+doatexit:
+       ldy     ecount          ; get index
+       beq     L9              ; jump if done
+       dey
+       lda     efunc,y
+       sta     jmpvec+2
+       dey
+       lda     efunc,y
+       sta     jmpvec+1
+       sty     ecount
+       ldy     #0              ; number of function parms
+       jsr     jmpvec
+       jmp     doatexit        ; next one
+
+L9:    rts
+
+
+
+
+
diff --git a/libsrc/common/atoi.s b/libsrc/common/atoi.s
new file mode 100644 (file)
index 0000000..cb2a72b
--- /dev/null
@@ -0,0 +1,156 @@
+;
+; Ullrich von Bassewitz, 05.06.1998
+;
+; int atoi (const char* s);
+; long atol (const char* s);
+;
+
+       .export         _atoi, _atol
+               .import         __ctype
+       .importzp       sreg, ptr1, ptr2, tmp1
+
+;
+; Conversion routine (32 bit)
+;
+
+_atoi:
+_atol: sta     ptr1            ; Store s
+       stx     ptr1+1
+       ldy     #0
+               sty     ptr2
+       sty     ptr2+1          ; initial value (32 bit)
+       sty     sreg
+       sty     sreg+1
+
+; Skip whitespace
+
+L1:    lda     (ptr1),y
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$80            ; tab or space?
+       beq     L2              ; jump if no
+       iny
+       bne     L1
+       inc     ptr1+1
+       bne     L1              ; branch always
+
+; Check for a sign. The character is in X
+
+L2:    txa                     ; get char
+       ldx     #0              ; flag: positive
+       cmp     #'+'            ; ### portable?
+               beq     L3
+       cmp     #'-'            ; ### portable?
+       bne     L5
+       dex                     ; flag: negative
+L3:     iny
+       bne     L5
+       inc     ptr1+1
+
+; Store the sign flag and setup for conversion
+
+L5:    stx     tmp1            ; remember sign flag
+
+L6:    lda     (ptr1),y        ; get next char
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$04            ; digit?
+               beq     L8              ; done
+
+; Multiply ptr2 (the converted value) by 10
+
+               jsr     mul2            ; * 2
+
+       lda     sreg+1
+       pha
+       lda     sreg
+       pha
+       lda     ptr2+1
+       pha
+       lda     ptr2
+       pha                     ; Save value
+
+               jsr     mul2            ; * 4
+               jsr     mul2            ; * 8
+
+       clc
+       pla
+       adc     ptr2
+       sta     ptr2
+       pla
+       adc     ptr2+1
+       sta     ptr2+1
+       pla
+       adc     sreg
+       sta     sreg
+       pla
+       adc     sreg+1
+       sta     sreg+1          ; x*2 + x*8 = x*10
+
+; Get the character back and add it
+
+       txa                     ; get char back
+       sec
+       sbc     #'0'            ; make numeric value
+       clc
+       adc     ptr2
+       sta     ptr2
+       bcc     L7
+       inc     ptr2+1
+       bne     L7
+       inc     sreg
+       bne     L7
+       inc     sreg+1
+
+; Next character
+
+L7:    iny
+       bne     L6
+       inc     ptr1+1
+       bne     L6
+
+; Conversion done. Be shure to negate the value if needed.
+
+L8:    lda     ptr2
+       ldx     ptr2+1
+       ldy     tmp1            ; sign
+       beq     L9
+
+; Negate the 32 bit value in ptr2/sreg
+
+       sec
+       lda     ptr2
+       eor     #$FF
+       adc     #0
+       sta     ptr2
+       lda     ptr2+1
+       eor     #$FF
+       adc     #0
+       sta     ptr2+1
+       lda     sreg
+       eor     #$FF
+       adc     #0
+       sta     sreg
+       lda     sreg+1
+       eor     #$FF
+       adc     #0
+       sta     sreg+1
+
+; Done, load the low 16 bit into A/X
+
+L9:    lda     ptr2
+       ldx     ptr2+1          ; get value
+       rts
+
+;
+; Helper functions
+;
+
+mul2:
+       asl     ptr2
+       rol     ptr2+1
+       rol     sreg
+       rol     sreg+1          ; * 2
+       rts
+
+
diff --git a/libsrc/common/bsearch.c b/libsrc/common/bsearch.c
new file mode 100644 (file)
index 0000000..47cbc4e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * bsearch.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdlib.h>
+
+
+
+void* bsearch (void* key, void* base, size_t n, size_t size, int (*cmp) (void*, void*))
+{
+    int current;               
+    int result;
+    int found = 0;
+    int first = 0;
+    int last = n - 1;
+
+    /* Binary search */
+    while (first <= last) {
+
+       /* Set current to mid of range */
+       current = (last + first) / 2;
+
+       /* Do a compare */
+               result = cmp ((void*) (((int) base) + current*size), key);
+        if (result < 0) {
+           first = current + 1;
+       } else {
+           last = current - 1;
+           if (result == 0) {
+               /* Found one entry that matches the search key. However there may be
+                * more than one entry with the same key value and ANSI guarantees
+                * that we return the first of a row of items with the same key.
+                */
+               found = 1;
+           }
+       }
+    }
+
+    /* Did we find the entry? */
+    return (void*) (found? ((int) base) + first*size : 0);
+}
+
+
+
diff --git a/libsrc/common/calloc.c b/libsrc/common/calloc.c
new file mode 100644 (file)
index 0000000..70b9849
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * calloc.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+void* calloc (size_t count, size_t size)
+{
+    void* mem;
+    size *= count;
+    if (mem = malloc (size)) {
+       memset (mem, 0, size);
+    }
+    return mem;
+}
+
+
+
diff --git a/libsrc/common/copydata.s b/libsrc/common/copydata.s
new file mode 100644 (file)
index 0000000..b554540
--- /dev/null
@@ -0,0 +1,53 @@
+;
+; Ullrich von Bassewitz, 07.12.1998
+;
+; Copy the data segment from the LOAD to the RUN location
+;
+
+       .export         copydata
+       .import         __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__
+       .importzp       ptr1, ptr2
+
+
+copydata:
+       lda     #<__DATA_LOAD__ ; Source pointer
+       sta     ptr1
+       lda     #>__DATA_LOAD__
+       sta     ptr1+1
+
+       lda     #<__DATA_RUN__  ; Target pointer
+       sta     ptr2
+       lda     #>__DATA_RUN__
+       sta     ptr2+1
+
+       ldy     #$00
+       ldx     #>__DATA_SIZE__ ; Get page count
+       beq     @L2             ; No full pages
+
+; Copy full pages
+
+@L1:   lda     (ptr1),y
+       sta     (ptr2),y
+       iny
+       bne     @L1
+       inc     ptr1+1
+       inc     ptr2+2          ; Bump pointers
+       dex
+       bne     @L1
+
+; Copy last page (remember: y contains zero)
+
+@L2:   ldx     #<__DATA_SIZE__ ; Get remaining bytes
+       beq     @L4
+          
+@L3:   lda     (ptr1),y
+       sta     (ptr2),y
+       iny
+       dex
+       bne     @L3
+
+; Done
+
+@L4:   rts
+
+
diff --git a/libsrc/common/cprintf.c b/libsrc/common/cprintf.c
new file mode 100644 (file)
index 0000000..a9d46ec
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * cprintf.c
+ *
+ * Ullrich von Bassewitz. 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <conio.h>
+
+
+
+int cprintf (char* format, ...)
+{
+    va_list ap;
+    va_start (ap, format);
+
+    /* Do formatting and output. Since we know, that va_end is empty, we don't
+     * call it here, saving an extra variable and some code.
+     */
+    return vcprintf ((char*) va_fix (ap, 1), ap);
+}
+
+
+
diff --git a/libsrc/common/errno.inc b/libsrc/common/errno.inc
new file mode 100644 (file)
index 0000000..197a355
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 16.05.2000
+;
+
+; Error codes, must match the values in the C headers
+
+ENOENT         =       1       ; No such file or directory
+ENOMEM         =       2       ; Out of memory
+EACCES         =       3       ; Permission denied
+ENODEV         =       4       ; No such device
+EMFILE         =       5       ; Too many open files
+EBUSY          =       6       ; Device or resource busy
+EINVAL         =       7       ; Invalid argument
+ENOSPC         =       8       ; No space left on device
+EEXIST         =       9       ; File exists
+EAGAIN         =       10      ; Try again
+EIO            =       11      ; I/O error
+EINTR          =       12      ; Interrupted system call
+ENOSYS         =       13      ; Function not implemented
+ESPIPE         =       14      ; Illegal seek
+EUNKNOWN               =       15      ; Unknown OS specific error - must be last!
+
+EMAX           =       15      ; Highest error code
+
diff --git a/libsrc/common/errno.s b/libsrc/common/errno.s
new file mode 100644 (file)
index 0000000..1ab8453
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int _errno;
+;
+; void _maperrno(void);
+; /* Map an OS error to a system independent error code */
+;
+
+       .export         __maperrno
+       .export         __errno
+       .import         __oserror
+       .import         __osmaperrno
+
+
+.code
+
+__maperrno:
+       lda     __oserror               ; Get the error code
+       beq     @L1                     ; Jump if no error
+       ldx     #$00                    ; Clear error
+       stx     __oserror
+       jsr     __osmaperrno            ; Map the code
+               sta     __errno
+       stx     __errno+1
+@L1:   rts
+
+
+.bss
+
+__errno:
+       .word   0
+
diff --git a/libsrc/common/errormsg.c b/libsrc/common/errormsg.c
new file mode 100644 (file)
index 0000000..4c15ac4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * errormsg.c
+ *
+ * Ullrich von Bassewitz, 17.05.2000
+ *
+ * Must be a C function, since we have otherwise problems with the different
+ * character sets.
+ */
+
+
+
+/* Place the following data into the readonly data segment */
+#pragma dataseg ("RODATA")
+
+const char* _sys_errlist[] = {
+    "Unknown error",                /*  0 */
+    "No such file or directory",    /*  1 */
+    "Out of memory",                /*  2 */
+    "Permission denied",            /*  3 */
+    "No such device",               /*  4 */
+    "Too many open files",          /*  5 */
+    "Device or resource busy",      /*  6 */
+    "Invalid argument",             /*  7 */
+    "No space left on device",      /*  8 */
+    "File exists",                  /*  9 */
+    "Try again",                    /* 10 */
+    "I/O error",                    /* 11 */
+    "Interrupted system call",      /* 12 */
+    "Function not implemented",     /* 13 */
+    "Illegal seek",                 /* 14 */
+};
+
+
diff --git a/libsrc/common/fclose.c b/libsrc/common/fclose.c
new file mode 100644 (file)
index 0000000..0ab2d42
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * int fclose (FILE* f);
+ */
+
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+int fclose (FILE* f)
+{
+    if ((f->f_flags & _FOPEN) == 0) {
+       /* File is not open */
+               _errno = EINVAL;                /* File not input */
+       return -1;
+    }
+
+    /* Reset the flags and close the file */
+    f->f_flags = _FCLOSED;
+    return close (f->f_fd);
+}
+
+
+
diff --git a/libsrc/common/fdopen.c b/libsrc/common/fdopen.c
new file mode 100644 (file)
index 0000000..896c983
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* fdopen (int handle, char* /*mode*/)
+{
+    FILE* f;
+
+    /* Find a free file slot */
+    if (!(f = _fdesc ())) {
+               /* No slots */
+               errno = EMFILE;                 /* Too many files */
+               return 0;
+    }
+
+    /* Insert the handle, and return the descriptor */
+    f->f_fd    = handle;
+    f->f_flags = _FOPEN;
+
+    /* Return the file descriptor */
+    return f;
+}
+
+
+
+
diff --git a/libsrc/common/fgetc.c b/libsrc/common/fgetc.c
new file mode 100644 (file)
index 0000000..97e6dcb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * int fgetc (FILE* f);
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+int fgetc (FILE* f)
+{
+    char c;
+
+    /* Check if the file is open or if there is an error condition */
+    if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+       return -1;
+    }
+
+    /* Read the byte */
+    switch (read (f->f_fd, &c, 1)) {
+
+        case -1:
+           /* Error */
+           f->f_flags |= _FERROR;
+           return -1;
+
+        case 0:
+           /* EOF */
+           f->f_flags |= _FEOF;
+           return -1;
+
+        default:
+           /* Char read */
+           return ((int) c) & 0xFF;
+
+    }
+}
+
+
+
diff --git a/libsrc/common/fgets.c b/libsrc/common/fgets.c
new file mode 100644 (file)
index 0000000..10c32bd
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * char* fgets (char* s, int size, FILE* f);
+ */
+
+
+
+#include <stdio.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+char* fgets (char* s, unsigned size, FILE* f)
+{
+    int i, c;
+
+    /* We do not handle the case "size == 0" here */
+    i = 0; --size;
+    while (i < size) {
+
+               /* Get next character */
+               c = fgetc (f);
+               if (c == -1) {
+                   s [i] = 0;
+                   /* Error or EOF */
+                   if (f->f_flags & _FERROR) {
+                       /* ERROR */
+                       return 0;
+                   } else {
+                       /* EOF */
+               if (i) {
+                   return s;
+               } else {
+                   return 0;
+               }
+           }
+               }
+
+               /* One char more */
+               s [i++] = c;
+
+       /* Stop at end of line */
+       if (c == '\n') {
+           break;
+       }
+    }
+
+    /* Replace newline by NUL */
+    s [i-1] = '\0';
+
+    /* Done */
+    return s;
+}
+
+
+
+
diff --git a/libsrc/common/fmisc.s b/libsrc/common/fmisc.s
new file mode 100644 (file)
index 0000000..185a4ec
--- /dev/null
@@ -0,0 +1,81 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; Several small file stream functions
+;
+
+       .export         _clearerr, _feof, _ferror, _fileno, _fflush
+       .import         return0
+       .import         __errno
+       .importzp       ptr1
+
+;
+; Get the FILE* parameter, check if the file is open
+;
+
+getf:  sta     ptr1
+       stx     ptr1+1
+       ldy     #1
+       lda     (ptr1),y        ; get f->f_flags
+       and     #$01            ; file open?
+       beq     @L1             ; jump if no
+       clc                     ; ok
+       rts
+@L1:   sec
+       rts
+
+;
+; void clearerr (FILE* f);
+;
+
+_clearerr:
+               jsr     getf
+               bcs     err
+               lda     (ptr1),y
+               and     #$F9
+               sta     (ptr1),y
+err:   rts
+
+;
+; int feof (FILE* f);
+;
+
+_feof:
+       jsr     getf
+;      bcs     err
+       lda     (ptr1),y
+       and     #$02
+       ldx     #0
+       rts
+
+;
+; int ferror (FILE* f);
+;
+
+_ferror:
+       jsr     getf
+;      bcs     err
+       lda     (ptr1),y
+       and     #$04
+       ldx     #0
+       rts
+
+;
+; int fileno (FILE* f);
+;
+
+_fileno:
+       jsr     getf
+;      bcs     err
+       dey
+       lda     (ptr1),y
+       ldx     #0
+       rts
+
+;
+; int __fastcall__ fflush (FILE* f);
+;
+
+_fflush        = return0
+
+
diff --git a/libsrc/common/fmode.inc b/libsrc/common/fmode.inc
new file mode 100644 (file)
index 0000000..2ec1090
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 05.06.1999
+;
+
+; File mode constants, must match the values in the C headers
+
+
+O_RDONLY       = $01
+O_WRONLY       = $02
+O_RDWR         = $03
+O_CREAT                = $04
+O_TRUNC                = $10
+O_APPEND       = $20
+
+
diff --git a/libsrc/common/fopen.c b/libsrc/common/fopen.c
new file mode 100644 (file)
index 0000000..f5c3652
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * fopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* fopen (const char* name, const char* mode)
+{
+    FILE* f;
+
+    /* Find a free file slot */
+    if (!(f = _fdesc ())) {
+               /* No slots */
+               _errno = EMFILE;                /* Too many files */
+               return 0;
+    }
+
+    /* Open the file and return the descriptor */
+    return _fopen (name, mode, f);
+}
+
+
+
diff --git a/libsrc/common/fprintf.c b/libsrc/common/fprintf.c
new file mode 100644 (file)
index 0000000..afa111f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * fprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int fprintf (FILE* /*F*/, char* format, ...)
+{
+    va_list ap;
+    va_start (ap, format);
+
+    /* Do formatting and output. Since we know, that va_end is empty, we don't
+     * call it here, saving an extra variable and some code.
+     */
+    return vfprintf ((FILE*) va_fix (ap, 1), (char*) va_fix (ap, 2), ap);
+}
+
+
+
diff --git a/libsrc/common/fputc.c b/libsrc/common/fputc.c
new file mode 100644 (file)
index 0000000..012cc05
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * fputc.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int fputc (int c, FILE* f)
+{
+    /* Check if the file is open or if there is an error condition */
+    if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+       return -1;
+    }
+
+    /* Write the byte (knows about byte order!) */
+    if (write (f->f_fd, &c, 1) <= 0) {
+       /* Error */
+       f->f_flags |= _FERROR;
+       return -1;
+    }
+
+    /* Return the byte written */
+    return c & 0xFF;
+}
+
+
+
diff --git a/libsrc/common/fputs.c b/libsrc/common/fputs.c
new file mode 100644 (file)
index 0000000..f4dcbbf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * int fputs (const char* s, FILE* f);
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int fputs (char* s, FILE* f)
+{
+    /* Check if the file is open or if there is an error condition */
+    if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+       return -1;
+    }
+
+    /* Write the string */
+    return write (f->f_fd, s, strlen (s));
+}
+
+
+
diff --git a/libsrc/common/fread.c b/libsrc/common/fread.c
new file mode 100644 (file)
index 0000000..a8b402a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * fread.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+size_t fread (void* buf, size_t size, size_t count, FILE* f)
+{
+    int bytes;
+
+    /* Is the file open? */
+    if ((f->f_flags & _FOPEN) == 0) {
+               _errno = EINVAL;                /* File not open */
+       return (size_t) -1;
+    }
+
+    /* Did we have an error or EOF? */
+    if ((f->f_flags & (_FERROR | _FEOF)) != 0) {
+               /* Cannot read from stream */
+               return 0;
+    }
+
+    /* How many bytes to read? */
+    bytes = size * count;
+
+    if (bytes) {
+       /* Read the data. */
+       bytes = read (f->f_fd, buf, bytes);
+       if (bytes == -1) {
+           /* Read error */
+           f->f_flags |= _FERROR;
+           return (size_t) -1;
+       }
+       if (bytes == 0) {
+           /* End of file */
+           f->f_flags |= _FEOF;
+           return (size_t) -1;
+       }
+
+        /* Unfortunately, we cannot avoid the divide here... */
+        return bytes / size;
+
+    } else {
+
+       /* 0 bytes read */
+       return count;
+
+    }
+}
+
+
+
diff --git a/libsrc/common/free.c b/libsrc/common/free.c
new file mode 100644 (file)
index 0000000..686f460
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * free.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdlib.h>
+#include "_heap.h"
+
+
+
+void free (void* block)
+/* Release an allocated memory block. The function will accept NULL pointers
+ * (and do nothing in this case).
+ */
+{
+    unsigned* b;
+    unsigned size;
+    struct freeblock* f;
+
+
+    /* Allow NULL arguments */
+    if (block == 0) {
+        return;
+    }
+
+    /* Get a pointer to the real memory block, then get the size */
+    b = (unsigned*) block;
+    size = *--b;
+
+    /* Check if the block is at the top of the heap */
+    if (((int) b) + size == (int) _hptr) {
+
+        /* Decrease _hptr to release the block */
+        _hptr = (unsigned*) (((int) _hptr) - size);
+
+        /* Check if the last block in the freelist is now at heap top. If so,
+         * remove this block from the freelist.
+         */
+        if (f = _hlast) {
+            if (((int) f) + f->size == (int) _hptr) {
+                /* Remove the last block */
+                _hptr = (unsigned*) (((int) _hptr) - f->size);
+                if (_hlast = f->prev) {
+                   /* Block before is now last block */
+                    f->prev->next = 0;
+                } else {
+                    /* The freelist is empty now */
+                    _hfirst = 0;
+                }
+            }
+        }
+
+    } else {
+
+               /* Not at heap top, enter the block into the free list */
+       _hadd (b, size);
+
+    }
+}
+
+
+
diff --git a/libsrc/common/freopen.c b/libsrc/common/freopen.c
new file mode 100644 (file)
index 0000000..bbad5b3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * freopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* freopen (char* name, char* mode, FILE* f)
+{
+    /* Check if the file is open, if so, close it */
+    if ((f->f_flags & _FOPEN) == 0) {
+       /* File is not open */
+       _errno = EINVAL;                /* File not input */
+       return 0;
+    }
+
+    /* Close the file. Don't bother setting the flag, it will get
+     * overwritten by _fopen.
+     */
+    if (close (f->f_fd) < 0) {
+       /* An error occured, _oserror is set */
+       return 0;
+    }
+
+    /* Open the file and return the descriptor */
+    return _fopen (name, mode, f);
+}
+
+
+
diff --git a/libsrc/common/fwrite.c b/libsrc/common/fwrite.c
new file mode 100644 (file)
index 0000000..7978d2d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * fwrite.c
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+size_t fwrite (void* buf, size_t size, size_t count, FILE* f)
+{
+    int bytes;
+
+    /* Is the file open? */
+    if ((f->f_flags & _FOPEN) == 0) {
+               _errno = EINVAL;                /* File not open */
+       return -1;
+    }
+
+    /* Did we have an error */
+    if ((f->f_flags & _FERROR) != 0) {
+       /* Cannot write to stream */
+               return 0;
+    }
+
+    /* How many bytes to write? */
+    bytes = size * count;
+
+    if (bytes) {
+       /* Write the data. */
+               if (write (f->f_fd, buf, bytes) == -1) {
+           /* Write error */
+           f->f_flags |= _FERROR;
+           return -1;
+       }
+    }
+
+    /* Don't waste time with expensive calculations, assume the write was
+     * complete and return the count of items.
+     */
+    return count;
+}
+
+
+
diff --git a/libsrc/common/getchar.c b/libsrc/common/getchar.c
new file mode 100644 (file)
index 0000000..a058ab0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * getchar.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <stdio.h>
+
+/* This is usually declared as a macro */
+#undef getchar
+
+
+
+int getchar (void)
+{
+    return fgetc (stdin);
+}
+
+
+
diff --git a/libsrc/common/getcpu.s b/libsrc/common/getcpu.s
new file mode 100644 (file)
index 0000000..a65aac3
--- /dev/null
@@ -0,0 +1,37 @@
+;
+; Ullrich von Bassewitz, 02.04.1999
+;
+; unsigned char getcpu (void);
+;
+
+       .export         _getcpu
+
+; ---------------------------------------------------------------------------
+; Subroutine to detect an 816. Returns
+;
+;   - carry clear and 0 in A for a NMOS 6502 CPU
+;   - carry set and 1 in A for some CMOS 6502 CPU
+;   - carry set and 2 in A for a 65816
+;
+; This function uses a $1A opcode which is a INA on the 816 and ignored
+; (interpreted as a NOP) on a NMOS 6502. There are several CMOS versions
+; of the 6502, but all of them interpret unknown opcodes as NOP so this is
+; just what we want.
+
+.p816                          ; Enable 65816 instructions
+
+_getcpu:
+       lda     #0
+       inc     a               ; .byte $1A
+       cmp     #1
+               bcc     @L9
+
+; This is at least a 65C02, check for a 65816
+
+       xba                     ; .byte $eb, put $01 in B accu
+       dec     a               ; .byte $3a, A=$00 if 65C02
+               xba                     ; .byte $eb, get $01 back if 65816
+               inc     a               ; .byte $1a, make $01/$02
+@L9:           ldx     #0              ; Load high byte of word
+       rts
+
diff --git a/libsrc/common/gets.c b/libsrc/common/gets.c
new file mode 100644 (file)
index 0000000..4177522
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * gets.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include "_file.h"
+
+
+
+char* gets (char* s)
+{
+    int i, c;
+
+    i = 0;
+    do {
+
+               /* Get next character */
+               c = fgetc (stdin);
+               if (c == -1) {
+                   /* Error or EOF */
+                   s [i] = 0;
+                   if (stdin->f_flags & _FERROR) {
+                       /* ERROR */
+                       return 0;
+                   } else {
+                       /* EOF */
+               if (i) {
+                   return s;
+               } else {
+                   return 0;
+               }
+           }
+               }
+
+               /* One char more */
+               s [i++] = c;
+
+    } while (c != '\n');
+
+    /* Replace newline by NUL */
+    s [i-1] = '\0';
+
+    /* Done */
+    return s;
+}
+
+
+
diff --git a/libsrc/common/isalnum.s b/libsrc/common/isalnum.s
new file mode 100644 (file)
index 0000000..e8654ad
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isalnum (int c);
+;
+
+       .export         _isalnum
+       .import         __ctype
+
+_isalnum:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$07            ; Mask character/digit bits
+       rts
+
diff --git a/libsrc/common/isalpha.s b/libsrc/common/isalpha.s
new file mode 100644 (file)
index 0000000..420d6b3
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isalpha (int c);
+;
+
+       .export         _isalpha
+       .import         __ctype
+
+_isalpha:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$03            ; Mask character bits
+       rts
+
diff --git a/libsrc/common/isblank.s b/libsrc/common/isblank.s
new file mode 100644 (file)
index 0000000..f3564ec
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isblank (int c);
+;
+; cc65 (and GNU) extension.
+;
+
+       .export         _isblank
+       .import         __ctype
+
+_isblank:
+       tay
+       lda     __ctype,y       ; Get character classification
+               and     #$80            ; Mask blank bit
+       rts
+
diff --git a/libsrc/common/iscntrl.s b/libsrc/common/iscntrl.s
new file mode 100644 (file)
index 0000000..6d29cb5
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int iscntrl (int c);
+;
+
+       .export         _iscntrl
+       .import         __ctype
+
+_iscntrl:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$10            ; Mask control character bit
+       rts
+
+
diff --git a/libsrc/common/isdigit.s b/libsrc/common/isdigit.s
new file mode 100644 (file)
index 0000000..d8cc6d5
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isdigit (int c);
+;
+
+       .export         _isdigit
+       .import         __ctype
+
+_isdigit:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$04            ; Mask digit bit
+       rts
+
diff --git a/libsrc/common/isgraph.s b/libsrc/common/isgraph.s
new file mode 100644 (file)
index 0000000..91f482c
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isgraph (int c);
+;
+
+       .export         _isgraph
+       .import         __ctype
+
+_isgraph:
+       tay
+       lda     __ctype,y       ; Get character classification
+       eor     #$30            ; NOT control and NOT space
+       and     #$30            ; Mask character bits
+       rts
+
diff --git a/libsrc/common/islower.s b/libsrc/common/islower.s
new file mode 100644 (file)
index 0000000..565f0f8
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int islower (int c);
+;
+
+       .export         _islower
+       .import         __ctype
+
+_islower:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$01            ; Mask lower char bit
+       rts
+
diff --git a/libsrc/common/isprint.s b/libsrc/common/isprint.s
new file mode 100644 (file)
index 0000000..e82e613
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isprint (int c);
+;
+
+       .export         _isprint
+       .import         __ctype
+
+_isprint:
+       tay
+       lda     __ctype,y       ; Get character classification
+       eor     #$10            ; NOT a control char
+               and     #$10            ; Mask control char bit
+       rts
+
diff --git a/libsrc/common/ispunct.s b/libsrc/common/ispunct.s
new file mode 100644 (file)
index 0000000..71664f0
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int ispunct (int c);
+;
+
+       .export         _ispunct
+       .import         __ctype
+
+_ispunct:
+       tay
+       lda     __ctype,y       ; Get character classification
+               eor     #$37            ; NOT (space | control | digit | char)
+               and     #$37            ; Mask relevant bits
+       rts
+
diff --git a/libsrc/common/isspace.s b/libsrc/common/isspace.s
new file mode 100644 (file)
index 0000000..1c6cc2e
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isspace (int c);
+;
+
+       .export         _isspace
+       .import         __ctype
+
+_isspace:
+       tay
+       lda     __ctype,y       ; Get character classification
+               and     #$60            ; Mask space bits
+       rts
+
diff --git a/libsrc/common/isupper.s b/libsrc/common/isupper.s
new file mode 100644 (file)
index 0000000..bb5ad07
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isupper (int c);
+;
+
+       .export         _isupper
+       .import         __ctype
+
+_isupper:
+       tay
+       lda     __ctype,y       ; Get character classification
+       and     #$02            ; Mask upper char bit
+       rts
+
diff --git a/libsrc/common/isxdigit.s b/libsrc/common/isxdigit.s
new file mode 100644 (file)
index 0000000..a3184d1
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isxdigit (int c);
+;
+
+       .export         _isxdigit
+       .import         __ctype
+
+_isxdigit:
+       tay
+       lda     __ctype,y       ; Get character classification
+               and     #$08            ; Mask xdigit bit
+       rts
+
diff --git a/libsrc/common/itoa.s b/libsrc/common/itoa.s
new file mode 100644 (file)
index 0000000..37544c4
--- /dev/null
@@ -0,0 +1,146 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* itoa (int value, char* s, int radix);
+; char* utoa (unsigned value, char* s, int radix);
+;
+
+       .export         _itoa, _utoa
+       .import         addysp1
+       .import         __hextab
+       .importzp       sp, sreg, ptr2, ptr3, tmp1
+
+.rodata
+specval:
+               .byte   '-', '3', '2', '7', '6', '8', 0
+.code
+
+;
+; Common subroutine to pop the parameters and put them into core
+;
+
+dopop:         sta     tmp1            ; will loose high byte
+       ldy     #0
+       lda     (sp),y
+       sta     ptr2
+       sta     ptr3
+       iny
+       lda     (sp),y
+       sta     ptr2+1
+       sta     ptr3+1
+       iny
+       lda     (sp),y
+       sta     sreg
+       iny
+       lda     (sp),y
+       sta     sreg+1
+       jmp     addysp1         ; Bump stack pointer
+
+;
+; itoa
+;
+
+_itoa: jsr     dopop           ; pop the arguments
+
+; We must handle $8000 in a special way, since it is the only negative
+; number that has no positive 16-bit counterpart
+
+       ldy     tmp1            ; get radix
+       cpy     #10
+       bne     utoa
+       cmp     #$00
+       bne     L2
+       cpx     #$80
+       bne     L2
+
+       ldy     #6
+L1:    lda     specval,y       ; copy -32768
+       sta     (ptr2),y
+       dey
+       bpl     L1
+       jmp     L10
+
+; Check if the value is negative. If so, write a - sign and negate the
+; number.
+
+L2:            lda     sreg+1          ; get high byte
+       bpl     utoa
+       lda     #'-'
+       ldy     #0
+       sta     (ptr2),y        ; store sign
+       inc     ptr2
+       bne     L3
+               inc     ptr2+1
+
+L3:    lda     sreg
+       eor     #$FF
+       clc
+       adc     #$01
+       sta     sreg
+       lda     sreg+1
+       eor     #$FF
+       adc     #$00
+       sta     sreg+1
+       jmp     utoa
+
+;
+; utoa
+;
+
+_utoa: jsr     dopop           ; pop the arguments
+
+; Convert to string by dividing and push the result onto the stack
+
+utoa:  lda     #$00
+       pha                     ; sentinel
+
+; Divide sreg/tmp1 -> sreg, remainder in a
+
+L5:    ldy     #16             ; 16 bit
+       lda     #0              ; remainder
+L6:    asl     sreg
+       rol     sreg+1
+       rol     a
+       cmp     tmp1
+       bcc     L7
+       sbc     tmp1
+       inc     sreg
+L7:    dey
+       bne     L6
+
+       tay                     ; get remainder into y
+       lda     __hextab,y      ; get hex character
+       pha                     ; save char value on stack
+
+       lda     sreg
+       ora     sreg+1
+       bne     L5
+
+; Get the characters from the stack into the string
+
+       ldy     #0
+L9:    pla
+       sta     (ptr2),y
+       beq     L10             ; jump if sentinel
+       iny
+       bne     L9              ; jump always
+
+; Done! Return the target string
+
+L10:   lda     ptr3
+               ldx     ptr3+1
+       rts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/common/jmpvec.s b/libsrc/common/jmpvec.s
new file mode 100644 (file)
index 0000000..d963158
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; General purpose jump vector in the data segment that is patched at
+; runtime and used by several routines.
+;
+; Ullrich von Bassewitz, 16.12.1998
+;
+
+       .export         jmpvec
+
+
+.data
+
+jmpvec:        jmp     $FFFF
+
diff --git a/libsrc/common/labs.s b/libsrc/common/labs.s
new file mode 100644 (file)
index 0000000..d73617b
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; long labs (long x);
+;
+
+       .export         _labs
+       .import         negeax, tsteax
+       .importzp       sreg
+
+_labs:         ldy     sreg+1          ; test hi byte
+       bpl     L1
+       jmp     negeax          ; Negate if negative
+L1:            rts
+
diff --git a/libsrc/common/locale.c b/libsrc/common/locale.c
new file mode 100644 (file)
index 0000000..ad5fe1c
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * locale.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <locale.h>
+#include <limits.h>
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Data in this module is read-only, put it into the RODATA segment */
+#pragma dataseg ("RODATA");
+
+/* For memory efficiency use a separate empty string */
+static const char EmptyString [] = "";
+
+static struct lconv lc = {
+    EmptyString,       /* currency_symbol */
+    ".",               /* decimal_point */
+    EmptyString,       /* grouping */
+    EmptyString,       /* int_curr_symbol */
+    EmptyString,       /* mon_decimal_point */
+    EmptyString,       /* mon_grouping */
+    EmptyString,       /* mon_thousands_sep */
+    EmptyString,       /* negative_sign */
+    EmptyString,       /* positive_sign */
+    EmptyString,       /* thousands_sep */
+    CHAR_MAX,          /* frac_digits */
+    CHAR_MAX,          /* int_frac_digits */
+    CHAR_MAX,          /* n_cs_precedes */
+    CHAR_MAX,          /* n_sep_by_space */
+    CHAR_MAX,          /* n_sign_posn */
+    CHAR_MAX,          /* p_cs_precedes */
+    CHAR_MAX,          /* p_sep_by_space */
+    CHAR_MAX,          /* p_sign_posn */
+};
+
+/* Restore the old data segment name */
+#pragma dataseg ("DATA");
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+struct lconv* localeconv (void)
+{
+    return &lc;
+}
+
+
+
+char* setlocale (int, const char* locale)
+{
+    if (locale == 0 || (locale [0] == 'C' && locale [1] == '\0') || locale [0] == '\0') {
+       /* No change, or value already set, our locale is the "C" locale */
+       return "C";
+    } else {
+       /* Cannot set this one */
+       return 0;
+    }
+}
+
+
+
+                 
diff --git a/libsrc/common/longjmp.s b/libsrc/common/longjmp.s
new file mode 100644 (file)
index 0000000..6f74f73
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; void longjmp (jmp_buf buf, int retval);
+;
+
+       .export         _longjmp
+       .import         popax
+       .importzp       sp, ptr1, ptr2
+
+_longjmp:
+       sta     ptr2            ; Save retval
+       stx     ptr2+1
+       jsr     popax           ; get buf
+       sta     ptr1
+       stx     ptr1+1
+       ldy     #0
+          
+; Get the old parameter stack
+
+               lda     (ptr1),y
+       iny
+               sta     sp
+       lda     (ptr1),y
+       iny
+       sta     sp+1
+
+; Get the old stack pointer
+
+       lda     (ptr1),y
+       iny
+       tax
+       txs
+
+; Get the return address and push it on the stack
+
+       lda     (ptr1),y
+       iny
+       pha
+       lda     (ptr1),y
+       pha
+
+; Load the return value and return to the caller
+
+       lda     ptr2
+       ldx     ptr2+1
+       rts
+
diff --git a/libsrc/common/ltoa.s b/libsrc/common/ltoa.s
new file mode 100644 (file)
index 0000000..c0a3420
--- /dev/null
@@ -0,0 +1,160 @@
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; char* ltoa (long value, char* s, int radix);
+; char* ultoa (unsigned long value, char* s, int radix);
+;
+
+       .export         _ltoa, _ultoa
+       .import         popax
+       .import         __hextab
+       .importzp       sreg, ptr1, ptr2, ptr3, tmp1
+
+
+
+.rodata
+specval:
+               .byte   '-', '2', '1', '4', '7', '4', '8', '3', '6', '4', '8', 0
+.code
+
+;
+; Common subroutine to pop the parameters and put them into core
+;
+                            
+dopop:         sta     tmp1            ; will loose high byte
+       jsr     popax           ; get s
+       sta     ptr1
+       stx     ptr1+1
+               sta     sreg            ; save for return
+       stx     sreg+1
+       jsr     popax           ; get low word of value
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax           ; get high word of value
+       sta     ptr3
+       stx     ptr3+1
+       rts
+
+;
+; ltoa
+;
+
+_ltoa: jsr     dopop           ; pop the arguments
+
+; We must handle $80000000 in a special way, since it is the only negative
+; number that has no positive 32-bit counterpart
+
+       ldx     ptr3+1          ; get high byte
+       ldy     tmp1            ; get radix
+       cpy     #10
+       bne     ultoa
+       lda     ptr3
+       ora     ptr2+1
+       ora     ptr2
+       bne     L2
+               cpx     #$80
+       bne     L2
+
+       ldy     #11
+L1:    lda     specval,y       ; copy -2147483648
+       sta     (ptr1),y
+       dey
+       bpl     L1
+       jmp     L10
+
+; Check if the value is negative. If so, write a - sign and negate the
+; number.
+
+L2:            txa                     ; get high byte
+       bpl     ultoa
+       lda     #'-'
+       ldy     #0
+       sta     (ptr1),y        ; store sign
+       inc     ptr1
+       bne     L3
+               inc     ptr1+1
+
+L3:    lda     ptr2            ; negate val
+       eor     #$FF
+       clc
+       adc     #$01
+       sta     ptr2
+       lda     ptr2+1
+       eor     #$FF
+       adc     #$00
+       sta     ptr2+1
+               lda     ptr3
+       eor     #$FF
+       adc     #$00
+       sta     ptr3
+               lda     ptr3+1
+       eor     #$FF
+       adc     #$00
+       sta     ptr3+1
+               jmp     ultoa
+
+;
+; utoa
+;
+
+_ultoa:        jsr     dopop           ; pop the arguments
+
+; Convert to string by dividing and push the result onto the stack
+
+ultoa: lda     #$00
+       pha                     ; sentinel
+
+; Divide val/tmp1 -> val, remainder in a
+
+L5:    ldy     #32             ; 32 bit
+       lda     #0              ; remainder
+L6:    asl     ptr2
+       rol     ptr2+1
+       rol     ptr3
+       rol     ptr3+1
+       rol     a
+       cmp     tmp1
+       bcc     L7
+       sbc     tmp1
+       inc     ptr2
+L7:    dey
+       bne     L6
+
+       tay                     ; get remainder into y
+       lda     __hextab,y      ; get hex character
+       pha                     ; save char value on stack
+
+       lda     ptr2
+       ora     ptr2+1
+       ora     ptr3
+       ora     ptr3+1
+       bne     L5
+
+; Get the characters from the stack into the string
+
+       ldy     #0
+L9:    pla
+       sta     (ptr1),y
+       beq     L10             ; jump if sentinel
+       iny
+       bne     L9              ; jump always
+
+; Done! Return the target string
+
+L10:   lda     sreg
+               ldx     sreg+1
+       rts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/common/malloc.c b/libsrc/common/malloc.c
new file mode 100644 (file)
index 0000000..d7722d5
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * malloc.c
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ */
+
+
+
+#include <stddef.h>
+#include "_heap.h"
+
+
+
+void* malloc (size_t size)
+/* Allocate memory from the given heap. The function returns a pointer to the
+ * allocated memory block or a NULL pointer if not enough memory is available.
+ * Allocating a zero size block is not allowed.
+ */
+{
+    struct freeblock* f;
+    unsigned* p;
+
+
+    /* Check for a size of zero, then add the administration space and round
+     * up the size if needed.
+     */
+    if (size == 0) {
+       return 0;
+    }
+    size += HEAP_ADMIN_SPACE;
+    if (size < sizeof (struct freeblock)) {
+        size = sizeof (struct freeblock);
+    }
+
+    /* Search the freelist for a block that is big enough */
+    f = _hfirst;
+    while (f && f->size < size) {
+        f = f->next;
+    }
+
+    /* Did we find one? */
+    if (f) {
+
+        /* We found a block big enough. If the block can hold just the
+         * requested size, use the block in full. Beware: When slicing blocks,
+         * there must be space enough to create a new one! If this is not the
+         * case, then use the complete block.
+         */
+        if (f->size - size < sizeof (struct freeblock)) {
+
+            /* Use the actual size */
+            size = f->size;
+
+            /* Remove the block from the free list */
+            if (f->prev) {
+                /* We have a previous block */
+                f->prev->next = f->next;
+            } else {
+                /* This is the first block, correct the freelist pointer */
+                _hfirst = f->next;
+            }
+            if (f->next) {
+                /* We have a next block */
+                f->next->prev = f->prev;
+            } else {
+                /* This is the last block, correct the freelist pointer */
+                _hlast = f->prev;
+            }
+
+        } else {
+
+            /* We must slice the block found */
+            struct freeblock* newblock;
+                   newblock = (struct freeblock*) ((unsigned) f) + size;
+
+            /* Insert the new block (the remaining space) instead of the
+             * old one.
+             */
+            newblock->size = f->size - size;         /* Remaining size */
+            newblock->next = f->next;
+            newblock->prev = f->prev;
+            if (f->prev) {
+                /* We have a previous block */
+                f->prev->next = newblock;
+            } else {
+                /* This is the first block, correct the freelist pointer */
+                _hfirst = newblock;
+            }
+            if (f->next) {
+                /* We have a next block */
+                f->next->prev = newblock;
+            } else {
+                /* This is the last block, correct the freelist pointer */
+                _hlast = newblock;
+            }
+
+        }
+
+        /* Setup the pointer for the bock */
+        p = (unsigned*) f;
+
+    } else {
+
+        /* We did not find a block big enough. Try to use new space from the
+         * heap top.
+         */
+       if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
+            /* Out of heap space */
+            return 0;
+       }
+
+
+       /* There is enough space left, take it from the heap top */
+       p = _hptr;
+               _hptr = (unsigned*) (((unsigned) _hptr) + size);
+
+    }
+
+    /* New block is now in p. Fill in the size and return the user pointer */
+    *p++ = size;
+    return p;
+}
+
+
+
diff --git a/libsrc/common/memchr.s b/libsrc/common/memchr.s
new file mode 100644 (file)
index 0000000..59186ae
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; Ullrich von Bassewitz, 09.06.1998
+;
+; void* memchr (const void* p, int c, size_t n);
+;
+
+       .export         _memchr
+       .import         popax, return0
+       .importzp       ptr1, ptr2, tmp1
+
+
+_memchr:
+               sta     ptr2            ; Save n
+       stx     ptr2+1
+       jsr     popax           ; get c
+       sta     tmp1
+               jsr     popax           ; get p
+               sta     ptr1
+               stx     ptr1+1
+
+               ldy     #0
+       lda     tmp1            ; get c
+       ldx     ptr2            ; use X as low counter byte
+       beq     L3              ; check high byte
+
+; Search for the char
+
+L1:    cmp     (ptr1),y
+               beq     L5              ; jump if found
+       iny
+       bne     L2
+       inc     ptr1+1
+L2:    cpx     #0
+       beq     L3
+       dex
+       jmp     L1
+L3:    ldx     ptr2+1          ; Check high byte
+       beq     L4              ; Jump if counter off
+       dec     ptr2+1
+       ldx     #$FF
+       bne     L1              ; branch always
+
+; Character not found, return zero
+
+L4:    jmp     return0
+
+; Character found, calculate pointer
+
+L5:    ldx     ptr1+1          ; get high byte of pointer
+               tya                     ; low byte offset
+               clc
+               adc     ptr1
+               bcc     L6
+               inx
+L6:    rts
+
+
diff --git a/libsrc/common/memcmp.s b/libsrc/common/memcmp.s
new file mode 100644 (file)
index 0000000..4647c31
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; Ullrich von Bassewitz, 09.06.1998
+;
+; int memcmp (const void* p1, const void* p2, size_t count);
+;
+
+       .export         _memcmp
+       .import         popax, return0
+       .importzp       ptr1, ptr2, ptr3
+
+_memcmp:
+       sta     ptr3            ; Save count
+       sta     ptr3+1
+               jsr     popax           ; get p2
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax           ; get p1
+       sta     ptr1
+       stx     ptr1+1
+
+       ldy     #0
+       ldx     ptr3            ; use X as low counter byte
+       beq     L3
+
+L1:    lda     (ptr1),y
+       cmp     (ptr2),y
+       bne     L5
+       iny
+       bne     L2
+       inc     ptr1+1
+       inc     ptr2+1
+L2:            txa
+       beq     L3
+       dex
+       jmp     L1
+L3:    lda     ptr3+1          ; check high byte
+       beq     L4
+       dec     ptr3+1
+       dex                     ; X = $FF
+       bne     L1              ; branch always
+
+; Memory areas are equal
+
+L4:    jmp     return0
+
+; Not equal, check which one is greater
+
+L5:    bcs     L6
+       ldx     #$FF
+       rts
+
+L6:    ldx     #$01
+       rts
+
diff --git a/libsrc/common/memcpy.s b/libsrc/common/memcpy.s
new file mode 100644 (file)
index 0000000..4ef141d
--- /dev/null
@@ -0,0 +1,113 @@
+;
+; void* memcpy (void* dest, const void* src, size_t n);
+; void* memmove (void* dest, const void* src, size_t n);
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+
+       .export         _memcpy, _memmove
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3, tmp1, tmp2
+
+; ----------------------------------------------------------------------
+_memcpy:
+       jsr     getparms        ; Get the parameters from stack
+
+; Copy upwards
+
+copyup:        ldy     #0              ; set up to move 256
+       ldx     tmp2            ; hi byte of n
+       beq     @L2
+
+@L1:   lda     (ptr1),y        ; get a byte
+       sta     (ptr2),y        ; store it
+       iny
+               bne     @L1
+       inc     ptr1+1          ; bump ptrs
+       inc     ptr2+1
+               dex
+       bne     @L1             ; do another block
+
+@L2:   ldx     tmp1            ; get low byte of n
+       beq     done            ; jump if done
+
+@L3:   lda     (ptr1),y        ; get a byte
+       sta     (ptr2),y        ; store it
+       iny
+       dex
+       bne     @L3
+
+done:  lda     ptr3
+       ldx     ptr3+1          ; get function result (dest)
+               rts
+
+
+; ----------------------------------------------------------------------
+_memmove:
+       jsr     getparms        ; Get the parameters from stack
+
+       cpx     ptr1+1          ; dest > src?
+       bne     @L1
+       cmp     ptr1
+@L1:   beq     done            ; Both pointers are equal - nothing to copy
+       bcc     copyup          ; Copy upwards
+
+; Copy downwards
+
+       clc
+               lda     ptr1+1
+       adc     tmp2
+       sta     ptr1+1
+
+       clc
+       lda     ptr2+1
+       adc     tmp2
+       sta     ptr2+1
+
+; Copy the incomplete page
+
+       ldy     tmp1            ; Get low byte of count
+       beq     @L3
+
+@L2:   dey
+       lda     (ptr1),y
+       sta     (ptr2),y
+       tya                     ; Test Y
+       bne     @L2             ; Jump if not zero
+
+; Copy complete pages
+
+@L3:   ldx     tmp2            ; Get hi byte of count
+       beq     done
+
+@L4:   dec     ptr1+1
+       dec     ptr2+1
+@L5:   dey
+       lda     (ptr1),y
+       sta     (ptr2),y
+       tya
+       bne     @L5
+       dex
+       bne     @L4
+
+; Done
+
+       beq     done
+
+; ----------------------------------------------------------------------
+; Get the parameters from stack
+          
+getparms:
+               sta     tmp1            ; Save n
+               stx     tmp2
+               jsr     popax           ; src
+               sta     ptr1
+               stx     ptr1+1
+               jsr     popax           ; dest
+       sta     ptr2
+       stx     ptr2+1          ; save work copy
+       sta     ptr3
+       stx     ptr3+1          ; save function result
+       rts
+
+
diff --git a/libsrc/common/memset.s b/libsrc/common/memset.s
new file mode 100644 (file)
index 0000000..18fc996
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; void* memset (void* ptr, int c, size_t n);
+;
+; Ullrich von Bassewitz, 29.05.1998
+;
+
+       .export         _memset
+       .import         popax
+       .importzp       ptr1, ptr2, tmp1, tmp2, tmp3
+
+_memset:
+       sta     tmp1            ; Save n
+       stx     tmp2
+       jsr     popax           ; Get c
+       sta     tmp3            ; Save c
+       jsr     popax           ; Get ptr
+       sta     ptr1
+       stx     ptr1+1          ; Save work copy
+       sta     ptr2
+       stx     ptr2+1          ; Save a copy for the function result
+               lda     tmp3
+
+       ldy     #0
+       ldx     tmp2            ; Get high byte of n
+               beq     L2              ; Jump if zero
+
+; Set 256 byte blocks
+
+L1:    sta     (ptr1),y        ; Set one byte
+       iny
+       sta     (ptr1),y        ; Unroll this a bit to make it faster
+       iny
+       bne     L1
+       inc     ptr1+1
+               dex                     ; Next 256 byte block
+       bne     L1              ; Repeat if any
+
+; Set the remaining bytes if any
+                                              
+L2:            ldx     tmp1            ; Get the low byte of n
+       beq     L9              ; Low byte is zero
+
+L3:            sta     (ptr1),y        ; Set one byte
+       iny
+               dex                     ; Done?
+       bne     L3
+
+L9:    lda     ptr2            ; Load function result
+       ldx     ptr2+1
+       rts
+
+
diff --git a/libsrc/common/perror.c b/libsrc/common/perror.c
new file mode 100644 (file)
index 0000000..814152e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * perror.c
+ *
+ * Ullrich von Bassewitz, 01.10.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+
+void perror (const char* msg)
+{                        
+    if (msg) {               
+        fprintf (stderr, "%s: ", msg);
+    }
+    fprintf (stderr, "%s\n", strerror (errno));
+}
+
+
+
diff --git a/libsrc/common/printf.c b/libsrc/common/printf.c
new file mode 100644 (file)
index 0000000..7f0fcb4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * printf.c
+ * 
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int printf (char* format, ...)
+{
+    va_list ap;
+    va_start (ap, format);
+
+    /* Do formatting and output. Since we know, that va_end is empty, we don't
+     * call it here, saving an extra variable and some code.
+     */
+    return vfprintf (stdout, (char*) va_fix (ap, 1), ap);
+}
+
+
+
diff --git a/libsrc/common/putchar.c b/libsrc/common/putchar.c
new file mode 100644 (file)
index 0000000..95bee07
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * putchar.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <stdio.h>
+
+/* This is usually declared as a macro */
+#undef putchar
+
+
+
+int putchar (int c)
+{
+    return fputc (c, stdout);
+}
+
+
+
diff --git a/libsrc/common/puts.c b/libsrc/common/puts.c
new file mode 100644 (file)
index 0000000..e3522c7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * puts.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int puts (const char* s)
+{
+    static char nl = '\n';
+
+    /* Assume stdout is always open */
+    if (write (stdout->f_fd, s, strlen (s)) < 0 ||
+       write (stdout->f_fd, &nl, 1)        < 0) {
+               stdout->f_flags |= _FERROR;
+       return -1;
+    }
+
+    /* Done */
+    return 0;
+}
+
+
+
diff --git a/libsrc/common/qsort.c b/libsrc/common/qsort.c
new file mode 100644 (file)
index 0000000..88da4b2
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * qsort.c
+ *
+ * Ullrich von Bassewitz, 09.12.1998
+ */
+
+
+
+#include <stdlib.h>
+
+
+
+static void QuickSort (void* Base, int Lo, int Hi, size_t Size,
+                      int (*Compare)(const void*, const void*))
+/* Internal recursive function. Works with ints, but this shouldn't be
+ * a problem.
+ */
+{
+    int I, J;
+
+    /* Get a char pointer */
+    unsigned char* B = Base;
+
+    /* Quicksort */
+    while (Hi > Lo) {
+       I = Lo + Size;
+       J = Hi;
+       while (I <= J) {
+           while (I <= J && Compare (B + Lo, B + I) >= 0) {
+               I += Size;
+           }
+           while (I <= J && Compare (B + Lo, B + J) < 0) {
+               J -= Size;
+           }
+           if (I <= J) {
+               _swap (B + I, B + J, Size);
+               I += Size;
+               J -= Size;
+           }
+       }
+       if (J != Lo) {
+           _swap (B + J, B + Lo, Size);
+       }
+               if (((unsigned) J) * 2 > (Hi + Lo)) {
+           QuickSort (Base, J + Size, Hi, Size, Compare);
+           Hi = J - Size;
+       } else {
+           QuickSort (Base, Lo, J - Size, Size, Compare);
+           Lo = J + Size;
+       }
+    }
+}
+
+
+
+void qsort (void* base, size_t nmemb, size_t size,
+           int (*compare)(const void*, const void*))
+/* Quicksort implementation */
+{
+    if (nmemb > 1) {
+               QuickSort (base, 0, (nmemb-1) * size, size, compare);
+    }
+}
+
+
+
+
+
diff --git a/libsrc/common/rand.s b/libsrc/common/rand.s
new file mode 100644 (file)
index 0000000..5195961
--- /dev/null
@@ -0,0 +1,63 @@
+;      
+; Randum number generator
+;
+; Written and donated by Sidney Cadot - sidney@ch.twi.tudelft.nl
+;
+; May be distributed with the cc65 runtime using the same license.
+;
+;
+; int rand (void);
+; void srand (unsigned seed);
+;
+;  Uses 4-byte state.
+;  Multiplier must be 1 (mod 4)
+;  Added value must be 1 (mod 2)
+;  This guarantees max. period (2**32)
+;  Bits 8-22 are returned (positive 2-byte int)
+;  where 0 is LSB, 31 is MSB.
+;  This is better as lower bits exhibit easily
+;  detectable patterns.
+;
+
+       .export         _rand, _srand
+
+.bss
+
+rand:          .res    4               ; Seed
+
+.code
+
+_rand: clc
+       lda     rand+0          ; SEED *= $01010101
+       adc     rand+1
+       sta     rand+1
+       adc     rand+2
+       sta     rand+2
+       adc     rand+3
+       sta     rand+3
+       clc
+       lda     rand+0          ; SEED += $31415927
+       adc     #$27
+       sta     rand+0
+       lda     rand+1
+       adc     #$59
+       sta     rand+1
+       pha
+       lda     rand+2
+       adc     #$41
+       sta     rand+2
+       and     #$7f            ; Suppress sign bit (make it positive)
+       tax
+       lda     rand+3
+       adc     #$31
+       sta     rand+3
+       pla                     ; return bit 8-22 in (X,A)
+       rts
+
+_srand:        sta     rand+0          ; Store the seed
+       stx     rand+1
+       lda     #0
+       sta     rand+2          ; Set MSW to zero
+       sta     rand+3
+       rts
+
diff --git a/libsrc/common/realloc.c b/libsrc/common/realloc.c
new file mode 100644 (file)
index 0000000..32c05f4
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * realloc.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "_heap.h"
+
+
+
+void* realloc (void* block, size_t size)
+{
+    unsigned* b;
+    unsigned* newblock;
+    unsigned oldsize;
+    int diff;
+
+    /* Check the block parameter */
+    if (!block) {
+       /* Block is NULL, same as malloc */
+       return malloc (size);
+    }
+
+    /* Check the size parameter */
+    if (size == 0) {
+       /* Block is not NULL, but size is: free the block */
+       free (block);
+       return 0;
+    }
+
+    /* Make the internal used size from the given size */
+    size += HEAP_ADMIN_SPACE;
+    if (size < sizeof (struct freeblock)) {
+        size = sizeof (struct freeblock);
+    }
+
+    /* Get a pointer to the real block, get the old block size */
+    b = (unsigned*) (((int) block) - 2);
+    oldsize = *b;
+
+    /* Get the size difference as a signed quantity */
+    diff = size - oldsize;
+
+    /* Is the block at the current heap top? */
+    if (((int) b) + oldsize == ((int) _hptr)) {
+       /* Check if we've enough memory at the heap top */
+       int newhptr;
+       newhptr = ((int) _hptr) + diff;
+       if (newhptr <= ((int) _hend)) {
+           /* Ok, there's space enough */
+                   _hptr = (unsigned*) newhptr;
+           *b = size;
+           return block;
+       }
+    }
+
+    /* The given block was not located on top of the heap, or there's no
+     * room left. Try to allocate a new block and copy the data.
+     */
+    if (newblock = malloc (size)) {
+       memcpy (newblock, block, oldsize - 2);
+       free (block);
+    }
+    return newblock;
+}
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/common/setjmp.s b/libsrc/common/setjmp.s
new file mode 100644 (file)
index 0000000..38ca80e
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int setjmp (jmp_buf buf);
+;
+
+       .export         __setjmp
+       .importzp       sp, ptr1
+
+__setjmp:
+       sta     ptr1            ; Save buf
+       stx     ptr1+1
+       ldy     #0
+
+; The parameter stack is now empty, put it into buf
+
+       lda     sp
+       sta     (ptr1),y
+       iny
+       lda     sp+1
+       sta     (ptr1),y
+       iny
+
+; Put the return stack pointer next
+
+       tsx
+       inx
+       inx                     ; drop return address
+       txa
+       sta     (ptr1),y
+       iny
+
+; Last thing is the return address.
+
+       pla
+       tax
+       pla
+       sta     (ptr1),y        ; high byte first
+       iny
+       pha
+       txa
+       sta     (ptr1),y
+       pha
+
+; Return zero
+
+       lda     #0
+       tax
+       rts
+
+
+  
diff --git a/libsrc/common/sprintf.c b/libsrc/common/sprintf.c
new file mode 100644 (file)
index 0000000..26b0348
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * sprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int sprintf (char* /*buf*/, char* format, ...)
+{
+    va_list ap;
+    va_start (ap, format);
+
+    /* Do formatting and output. Since we know, that va_end is empty, we don't
+     * call it here, saving an extra variable and some code.
+     */
+    return vsprintf ((char*) va_fix (ap, 1), (char*) va_fix (ap, 2), ap);
+}
+
+
+
diff --git a/libsrc/common/stkcheck.s b/libsrc/common/stkcheck.s
new file mode 100644 (file)
index 0000000..3dff403
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 18.08.1998
+;
+; Stack checker
+;
+
+
+       .export         _stkcheck, __stksafety
+       .import         pushax, exit
+       .import         __hend
+       .importzp       sp
+
+.data
+__stksafety:
+       .word   64                      ;
+
+.code
+_stkcheck:
+       clc
+       lda     __hend
+       adc     __stksafety
+       tax                             ; Remember low byte
+       lda     __hend+1
+       adc     __stksafety+1
+
+       cmp     sp+1
+       bcc     Ok
+               bne     L1
+       cpx     sp
+       bcc     Ok
+
+; Stack overflow
+
+L1:            inc     sp+1                    ; Create 256 bytes of space
+       ldx     #0
+       lda     #4
+       jsr     pushax
+       jmp     exit
+
+; All is well
+
+Ok:    rts
+
+
+
+
+
+
diff --git a/libsrc/common/strcat.s b/libsrc/common/strcat.s
new file mode 100644 (file)
index 0000000..7297579
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strcat (char* dest, const char* src);
+;
+
+               .export         _strcat
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+_strcat:
+               sta     ptr1            ; Save src
+               stx     ptr1+1
+               jsr     popax           ; Get dest
+       sta     ptr2
+       stx     ptr2+1
+       sta     ptr3            ; Remember for function return
+       stx     ptr3+1
+       ldy     #0
+
+; find end of dest
+
+sc1:   lda     (ptr2),y
+       beq     sc2
+       iny
+       bne     sc1
+       inc     ptr2+1
+       bne     sc1
+
+; end found, get offset in y into pointer
+
+sc2:   tya
+       clc
+       adc     ptr2
+       sta     ptr2
+       bcc     sc3
+       inc     ptr2+1
+
+; copy src
+
+sc3:   ldy     #0
+sc4:   lda     (ptr1),y
+       sta     (ptr2),y
+       beq     sc5
+       iny
+       bne     sc4
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     sc4
+
+; done, return pointer to dest
+
+sc5:   lda     ptr3
+       ldx     ptr3+1
+       rts
+
+
diff --git a/libsrc/common/strchr.s b/libsrc/common/strchr.s
new file mode 100644 (file)
index 0000000..7a5c767
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; const char* strchr (const char* s, int c);
+;
+
+       .export         _strchr
+       .import         popax
+       .importzp       ptr1, tmp1
+
+_strchr:
+               sta     tmp1            ; Save c
+               jsr     popax           ; get s
+               sta     ptr1
+               stx     ptr1+1
+               ldy     #0
+
+scloop:        lda     (ptr1),y        ; get next char
+               beq     strz            ; jump if end of string
+               cmp     tmp1            ; found?
+               beq     strf            ; jump if yes
+               iny
+               bne     scloop
+               inc     ptr1+1
+               bne     scloop          ; jump always
+
+; found, calculate pointer to c
+
+strf:          ldx     ptr1+1          ; get high byte of pointer
+               tya                     ; low byte offset
+               clc
+               adc     ptr1
+               bcc     str1
+               inx
+str1:          rts
+
+; not found, return zero
+
+strz:  tax                     ; return 0
+       rts
+
diff --git a/libsrc/common/strcmp.s b/libsrc/common/strcmp.s
new file mode 100644 (file)
index 0000000..db85d9b
--- /dev/null
@@ -0,0 +1,35 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; int strcmp (const char* s1, const char* s2);
+;
+
+       .export         _strcmp
+       .import         popax
+       .importzp       ptr1, ptr2
+
+_strcmp:
+       sta     ptr2            ; Save s2
+       stx     ptr2+1
+       jsr     popax           ; Get s1
+       sta     ptr1
+       stx     ptr1+1
+       ldy     #0
+
+loop:  lda     (ptr1),y
+       cmp     (ptr2),y
+       bne     L1
+       tax                     ; end of strings?
+       beq     L3
+       iny
+       bne     loop
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     loop
+
+L1:    bcs     L2
+       ldx     #$FF
+       rts
+
+L2:    ldx     #$01
+L3:    rts
diff --git a/libsrc/common/strcoll.s b/libsrc/common/strcoll.s
new file mode 100644 (file)
index 0000000..664d1f4
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 11.12.1998
+;
+; int strcoll (const char* s1, const char* s2);
+;
+; Since we don't have locales, this function is equivalent to strcmp.
+;
+
+       .export         _strcoll
+       .import         _strcmp
+
+_strcoll       = _strcmp
+
diff --git a/libsrc/common/strcpy.s b/libsrc/common/strcpy.s
new file mode 100644 (file)
index 0000000..a0194db
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strcpy (char* dest, const char* src);
+;
+
+       .export         _strcpy
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+_strcpy:
+       sta     ptr1            ; Save src
+       stx     ptr1+1
+       jsr     popax           ; Get dest
+       sta     ptr2
+       stx     ptr2+1
+       sta     ptr3            ; remember for function return
+       stx     ptr3+1
+       ldy     #$00
+
+L1:    lda     (ptr1),y
+       sta     (ptr2),y
+       beq     L9
+       iny
+       bne     L1
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     L1
+
+L9:    lda     ptr3
+       ldx     ptr3+1
+       rts
+
diff --git a/libsrc/common/strcspn.s b/libsrc/common/strcspn.s
new file mode 100644 (file)
index 0000000..6c12561
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; size_t strcspn (const char* s1, const char* s2);
+;
+
+       .export         _strcspn
+       .import         popax
+       .importzp       ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strcspn:
+       sta     ptr2            ; Save s2
+       stx     ptr2+1
+       jsr     popax           ; Get s1
+       sta     ptr1
+       stx     ptr1+1
+       ldx     #0              ; low counter byte
+       stx     tmp1            ; high counter byte
+       ldy     #$00
+
+L1:    lda     (ptr1),y        ; get next char from s1
+               beq     L6              ; jump if done
+       sta     tmp2            ; save char
+       iny
+       bne     L2
+       inc     ptr1+1
+L2:    sty     tmp3            ; save index into s1
+
+       ldy     #0              ; get index into s2
+L3:    lda     (ptr2),y        ;
+       beq     L4              ; jump if done
+       cmp     tmp2
+       beq     L6
+       iny
+       bne     L3
+
+; The character was not found in s2. Increment the counter and start over
+
+L4:            ldy     tmp3            ; reload index
+       inx
+       bne     L1
+       inc     tmp1
+       bne     L1
+
+; The character was found, or we reached the end of s1. Return count of
+; characters
+
+L6:    txa                     ; get low counter byte
+       ldx     tmp1            ; get high counter byte
+       rts
+
+
+
+
diff --git a/libsrc/common/strdup.c b/libsrc/common/strdup.c
new file mode 100644 (file)
index 0000000..42a01af
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * strdup.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <string.h>
+#include <stdlib.h>
+
+
+
+char* strdup (char* s)
+{
+    char* p;
+    p = malloc (strlen (s) + 1);
+    if (p) {
+       strcpy (p, s);
+    }
+    return p;
+}
+
+
+
diff --git a/libsrc/common/strerror.s b/libsrc/common/strerror.s
new file mode 100644 (file)
index 0000000..6149c42
--- /dev/null
@@ -0,0 +1,29 @@
+;
+; Ullrich von Bassewitz, 17.05.2000
+;
+; char* __fastcall__ strerror (int errcode);
+; /* Map an error number to an error message */
+;
+
+       .export         _strerror
+       .import         __sys_errlist
+
+       .include        "errno.inc"
+
+_strerror:
+       cpx     #$00            ; High byte must be zero
+               bne     @L1             ; Jump if invalid error
+       cmp     #EMAX           ; Valid error code (map EUNKNOWN to 0)?
+       bcc     @L2             ; Jump if ok
+@L1:   lda     #$00            ; "Unknown error"
+@L2:   asl     a               ; * 2
+       tay
+
+; Load the pointer to the error message and return
+
+       lda     __sys_errlist+1,y
+       tax
+       lda     __sys_errlist,y
+       rts
+
+
diff --git a/libsrc/common/stricmp.s b/libsrc/common/stricmp.s
new file mode 100644 (file)
index 0000000..62e2f84
--- /dev/null
@@ -0,0 +1,59 @@
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; int stricmp (const char* s1, const char* s2);                /* DOS way */
+; int strcasecmp (const char* s1, const char* s2);     /* UNIX way */
+;
+
+       .export         _stricmp, _strcasecmp
+       .import         popax
+       .import         __ctype, __cdiff
+       .importzp       ptr1, ptr2, tmp1
+
+
+_stricmp:
+_strcasecmp:
+       sta     ptr2            ; Save s2
+       stx     ptr2+1
+       jsr     popax           ; get s1
+       sta     ptr1
+       stx     ptr1+1
+       ldy     #0
+
+loop:          lda     (ptr2),y        ; get char from second string
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$01            ; lower case char?
+       beq     L1              ; jump if no
+       txa                     ; get character back
+       clc
+       adc     __cdiff         ; make upper case char
+       tax                     ;
+L1:    stx     tmp1            ; remember upper case equivalent
+
+       lda     (ptr1),y        ; get character from first string
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$01            ; lower case char?
+               beq     L2              ; jump if no
+       txa                     ; get character back
+       clc
+       adc     __cdiff         ; make upper case char
+       tax
+
+L2:    cpx     tmp1            ; compare characters
+       bne     L3
+       txa                     ; end of strings?
+       beq     L5              ; a/x both zero
+       iny
+       bne     loop
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     loop
+
+L3:    bcs     L4
+       ldx     #$FF
+       rts
+
+L4:    ldx     #$01
+L5:    rts
diff --git a/libsrc/common/strlen.s b/libsrc/common/strlen.s
new file mode 100644 (file)
index 0000000..6cef2ea
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; int strlen (const char* s);
+;
+
+       .export         _strlen
+       .importzp       ptr1
+
+_strlen:
+       sta     ptr1            ; Save s
+       stx     ptr1+1
+       ldx     #0              ; YX used as counter
+       ldy     #0
+
+L1:    lda     (ptr1),y
+       beq     L9
+       iny
+       bne     L1
+       inc     ptr1+1
+       inx
+       bne     L1
+
+L9:    tya                     ; get low byte of counter, hi's all set
+               rts
+
diff --git a/libsrc/common/strlower.s b/libsrc/common/strlower.s
new file mode 100644 (file)
index 0000000..49e906b
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; char* strlower (char* s);
+; char* strlwr (char* s);
+;
+; Non-ANSI
+;
+
+       .export         _strlower, _strlwr
+       .import         popax
+       .import         __ctype, __cdiff
+       .importzp       ptr1, ptr2
+
+_strlower:
+_strlwr:
+       sta     ptr1            ; Save s (working copy)
+       stx     ptr1+1          
+       sta     ptr2
+       sta     ptr2+2          ; save function result
+       ldy     #0
+
+loop:  lda     (ptr1),y        ; get character
+       beq     L9              ; jump if done
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$02            ; upper case char?
+       beq     L1              ; jump if no
+       txa                     ; get character back into accu
+       sec
+       sbc     __cdiff         ; make lower case char
+       sta     (ptr1),y        ; store back
+L1:    iny                     ; next char
+       bne     loop
+       inc     ptr1+1          ; handle offset overflow
+       bne     loop            ; branch always
+
+; Done, return the argument string
+
+L9:    lda     ptr2
+       ldx     ptr2+1
+       rts
+
+
+
diff --git a/libsrc/common/strncat.s b/libsrc/common/strncat.s
new file mode 100644 (file)
index 0000000..5171ad9
--- /dev/null
@@ -0,0 +1,72 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strncat (char* dest, const char* src, size_t n);
+;
+
+               .export         _strncat
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3, tmp1, tmp2
+
+_strncat:
+       eor     #$FF            ; one's complement to count upwards
+       sta     tmp1
+       txa
+       eor     #$FF
+       sta     tmp2
+               jsr     popax           ; get src
+               sta     ptr1
+               stx     ptr1+1
+               jsr     popax           ; get dest
+       sta     ptr2
+       stx     ptr2+1
+       sta     ptr3            ; remember for function return
+       stx     ptr3+1
+       ldy     #0
+
+; find end of dest
+
+L1:    lda     (ptr2),y
+       beq     L2
+       iny
+       bne     L1
+       inc     ptr2+1
+       bne     L1
+
+; end found, get offset in y into pointer
+
+L2:    tya
+       clc
+       adc     ptr2
+       sta     ptr2
+       bcc     L3
+       inc     ptr2+1
+
+; copy src. We've put the ones complement of the count into the counter, so
+; we'll increment the counter on top of the loop
+
+L3:    ldy     #0
+       ldx     tmp1            ; low counter byte
+
+L4:    inx
+       bne     L5
+       inc     tmp2
+               beq     L6              ; jump if done
+L5:    lda     (ptr1),y
+       sta     (ptr2),y
+       beq     L7
+       iny
+       bne     L4
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     L4
+
+; done, set the trailing zero and return pointer to dest
+
+L6:            lda     #0
+       sta     (ptr2),y
+L7:    lda     ptr3
+       ldx     ptr3+1
+       rts
+
+
diff --git a/libsrc/common/strncmp.s b/libsrc/common/strncmp.s
new file mode 100644 (file)
index 0000000..3af44fa
--- /dev/null
@@ -0,0 +1,81 @@
+;
+; Ullrich von Bassewitz, 25.05.2000
+;
+; int strncmp (const char* s1, const char* s2, unsigned n);
+;
+
+       .export         _strncmp
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3
+
+
+_strncmp:
+
+; Convert the given counter value in a/x from a downward counter into an
+; upward counter, so we can increment the counter in the loop below instead
+; of decrementing it. This adds some overhead now, but is cheaper than
+; executing a more complex test in each iteration of the loop. We do also
+; correct the value by one, so we can do the test on top of the loop.
+
+       eor     #$FF
+       sta     ptr3
+       txa
+       eor     #$FF
+       sta     ptr3+1
+
+; Get the remaining arguments
+
+               jsr     popax           ; get s2
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax           ; get s1
+       sta     ptr1
+       stx     ptr1+1
+
+; Loop setup
+
+       ldy     #0
+
+; Start of compare loop. Check the counter.
+
+Loop:          inc     ptr3
+       beq     IncHi           ; Increment high byte
+
+; Compare a byte from the strings
+
+Comp:  lda     (ptr1),y
+       cmp     (ptr2),y
+               bne     NotEqual        ; Jump if strings different
+       tax                     ; End of strings?
+               beq     Equal1          ; Jump if EOS reached, a/x == 0
+
+; Increment the pointers
+
+       iny
+       bne     Loop
+       inc     ptr1+1
+       inc     ptr2+1
+       bne     Loop            ; Branch always
+
+; Increment hi byte
+
+IncHi: inc     ptr3+1
+               bne     Comp            ; Jump if counter not zero
+
+; Exit code if strings are equal. a/x not set
+
+Equal: lda     #$00
+       tax
+Equal1:        rts
+
+; Exit code if strings not equal
+
+NotEqual:
+       bcs     L1
+       ldx     #$FF            ; Make result negative
+       rts
+
+L1:    ldx     #$01            ; Make result positive
+       rts
+
+
diff --git a/libsrc/common/strncpy.s b/libsrc/common/strncpy.s
new file mode 100644 (file)
index 0000000..7c5ee15
--- /dev/null
@@ -0,0 +1,98 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strncpy (char* dest, const char* src, unsigned size);
+;
+
+       .export         _strncpy
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3, tmp1, tmp2
+
+_strncpy:
+       sta     tmp1            ; Save size
+               stx     tmp2
+               jsr     popax           ; get src
+       sta     ptr1
+       stx     ptr1+1
+       jsr     popax           ; get dest
+       sta     ptr2
+       stx     ptr2+1
+       sta     ptr3            ; remember for function return
+       stx     ptr3+1
+
+       ldy     #$00
+       ldx     tmp1            ; Low byte of size
+       beq     L1
+
+; Copy the first chunk < 256
+
+       jsr     CopyChunk
+               bcs     L3              ; Jump if end of string found
+
+; Copy full 256 byte chunks
+
+L1:            lda     tmp2            ; High byte of size
+       beq     L3
+       ldx     #$00            ; Copy 256 bytes
+L2:    jsr     CopyChunk
+       bcs     L3
+       dec     tmp2
+       bne     L2
+       beq     L9
+
+; Fill the remaining space with zeroes. If we come here, the value in X
+; is the low byte of the fill count, tmp2 holds the high byte. Y is the index
+; into the target string.
+
+L3:    tax                     ; Test low byte
+       beq     L4
+       jsr     FillChunk
+
+L4:    lda     tmp2            ; Test high byte
+       beq     L9
+L5:    jsr     FillChunk
+       dec     tmp2
+       bne     L5
+
+; Done - return a pointer to the string
+
+L9:    lda     ptr3
+       ldx     ptr3+1
+       rts
+
+
+; -------------------------------------------------------------------
+; Copy byte count in X from ptr1 to ptr2
+
+.proc  CopyChunk
+L1:    lda     (ptr1),y
+       sta     (ptr2),y
+       beq     L3
+       iny
+       bne     L2
+       inc     ptr1+1
+       inc     ptr2+1
+L2:    dex
+       bne     L1
+       clc
+       rts
+L3:    sec
+       rts
+.endproc
+
+
+; -------------------------------------------------------------------
+; Fill byte count in X with zeroes
+
+.proc  FillChunk
+       lda     #$00
+L1:    sta     (ptr1),y
+       iny
+       bne     L2
+       inc     ptr1+1
+L2:    dex
+       bne     L1
+       rts
+.endproc
+
+
diff --git a/libsrc/common/strpbrk.s b/libsrc/common/strpbrk.s
new file mode 100644 (file)
index 0000000..e34468b
--- /dev/null
@@ -0,0 +1,60 @@
+;                                                  
+; Ullrich von Bassewitz, 11.06.1998
+;
+; char* strpbrk (const char* s1, const char* s2);
+;
+
+       .export         _strpbrk
+       .import         popax, return0
+       .importzp       ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strpbrk:
+               jsr     popax           ; get s2
+       sta     ptr2
+       stx     ptr2+1
+       jsr     popax           ; get s1
+       sta     ptr1
+       stx     ptr1+1
+       ldy     #$00
+
+L1:    lda     (ptr1),y        ; get next char from s1
+               beq     L9              ; jump if done
+       sta     tmp2            ; save char
+       iny
+       bne     L2
+       inc     ptr1+1
+L2:    sty     tmp3            ; save index into s1
+
+       ldy     #0              ; get index into s2
+L3:    lda     (ptr2),y        ;
+       beq     L4              ; jump if done
+       cmp     tmp2
+       beq     L6
+       iny
+       bne     L3
+
+; The character was not found in s2. Increment the counter and start over
+
+L4:            ldy     tmp3            ; reload index
+       inx
+       bne     L1
+       inc     tmp1
+       bne     L1
+
+; A character was found. Calculate a pointer to this char in s1 and return it.
+
+L6:    ldx     ptr1+1
+       lda     tmp3            ; get y offset
+       clc
+       adc     ptr1
+       bcc     L7
+       inx
+L7:    rts
+
+; None of the characters in s2 was found - return NULL
+
+L9:    jmp     return0
+
+
+
+
diff --git a/libsrc/common/strrchr.s b/libsrc/common/strrchr.s
new file mode 100644 (file)
index 0000000..bf09fbd
--- /dev/null
@@ -0,0 +1,47 @@
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strrchr (const char* s, int c);
+;
+
+       .export         _strrchr
+       .import         popax
+       .importzp       ptr1, ptr2, tmp1
+
+_strrchr:
+               sta     tmp1            ; Save c
+               jsr     popax           ; get s
+               sta     ptr1
+               stx     ptr1+1
+       lda     #0              ; function result = NULL
+       sta     ptr2
+       sta     ptr2+1
+               tay
+
+L1:    lda     (ptr1),y        ; get next char
+               beq     L3              ; jump if end of string
+               cmp     tmp1            ; found?
+               bne     L2              ; jump if no
+
+; Remember a pointer to the character
+
+       tya
+       clc
+       adc     ptr1
+       sta     ptr2
+       lda     ptr1+1
+       adc     #$00
+       sta     ptr2+1
+
+; Next char
+
+L2:    iny
+               bne     L1
+               inc     ptr1+1
+               bne     L1              ; jump always
+
+; Return the pointer to the last occurrence
+
+L3:    lda     ptr2
+       ldx     ptr2+1
+       rts
diff --git a/libsrc/common/strspn.s b/libsrc/common/strspn.s
new file mode 100644 (file)
index 0000000..884a337
--- /dev/null
@@ -0,0 +1,56 @@
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; size_t strspn (const char* s1, const char* s2);
+;
+
+       .export         _strspn
+       .import         popax
+       .importzp       ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strspn:
+       sta     ptr2            ; Save s2
+       stx     ptr2+1
+       jsr     popax           ; get s1
+       sta     ptr1
+       stx     ptr1+1
+       ldx     #0              ; low counter byte
+       stx     tmp1            ; high counter byte
+       ldy     #$00
+
+L1:    lda     (ptr1),y        ; get next char from s1
+               beq     L6              ; jump if done
+       sta     tmp2            ; save char
+       iny
+       bne     L2
+       inc     ptr1+1
+L2:    sty     tmp3            ; save index into s1
+
+       ldy     #0              ; get index into s2
+L3:    lda     (ptr2),y        ;
+               beq     L6              ; jump if done
+       cmp     tmp2
+       beq     L4
+       iny
+       bne     L3
+
+; The character was found in s2. Increment the counter and start over
+
+L4:            ldy     tmp3            ; reload index
+       inx
+       bne     L1
+       inc     tmp1
+       bne     L1
+
+; The character was not found, or we reached the end of s1. Return count of
+; characters
+
+L6:    txa                     ; get low counter byte
+       ldx     tmp1            ; get high counter byte
+       rts
+
+
+
+
+
+
diff --git a/libsrc/common/strstr.s b/libsrc/common/strstr.s
new file mode 100644 (file)
index 0000000..62e1944
--- /dev/null
@@ -0,0 +1,97 @@
+;
+; Ullrich von Bassewitz, 11.12.1998
+;
+; char* strstr (const char* haystack, const char* needle);
+;
+
+       .export         _strstr
+       .import         popax
+       .importzp       ptr1, ptr2, ptr3, ptr4, tmp1
+
+_strstr:
+       sta     ptr2            ; Save needle
+       stx     ptr2+1
+       sta     ptr4            ; Setup temp copy for later
+
+       jsr     popax           ; Get haystack
+       sta     ptr1
+       stx     ptr1+1          ; Save haystack
+
+; If needle is empty, return haystack
+
+       ldy     #$00
+       lda     (ptr2),y        ; Get first byte of needle
+               beq     @Found          ; Needle is empty --> we're done
+
+; Search for the beginning of the string (this is not an optimal search
+; strategy [in fact, it's pretty dumb], but it's simple to implement).
+
+       sta     tmp1            ; Save start of needle
+@L1:   lda     (ptr1),y        ; Get next char from haystack
+               beq     @NotFound       ; Jump if end
+       cmp     tmp1            ; Start of needle found?
+               beq     @L2             ; Jump if so
+       iny                     ; Next char
+       bne     @L1
+       inc     ptr1+1          ; Bump high byte
+       bne     @L1             ; Branch always
+
+; We found the start of needle in haystack
+
+@L2:   tya                     ; Get offset
+       clc
+       adc     ptr1
+       sta     ptr1            ; Make ptr1 point to start
+       bcc     @L3
+       inc     ptr1+1
+
+; ptr1 points to the start of needle now. Setup temporary pointers for the
+; search. The low byte of ptr4 is already set.
+
+@L3:           sta     ptr3
+       lda     ptr1+1
+        sta    ptr3+1
+       lda     ptr2+1
+       sta     ptr4+1
+       ldy     #1              ; First char is identical, so start on second
+
+; Do the compare
+
+@L4:   lda     (ptr4),y        ; Get char from needle
+               beq     @Found          ; Jump if end of needle (-> found)
+       cmp     (ptr3),y        ; Compare with haystack
+       bne     @L5             ; Jump if not equal
+       iny                     ; Next char
+               bne     @L4
+       inc     ptr3+1
+       inc     ptr4+1          ; Bump hi byte of pointers
+       bne     @L4             ; Next char (branch always)
+
+; The strings did not compare equal, search next start of needle
+
+@L5:   ldy     #1              ; Start after this char
+               bne     @L1             ; Branch always
+
+; We found the start of needle
+
+@Found:        lda     ptr1
+       ldx     ptr1+1
+       rts
+
+; We reached end of haystack without finding needle
+
+@NotFound:
+       lda     #$00            ; return NULL
+       tax
+       rts
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsrc/common/strtok.c b/libsrc/common/strtok.c
new file mode 100644 (file)
index 0000000..d3f8b56
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * strtok.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <string.h>
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Memory location that holds the last input */
+static char* Last = 0;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+char* strtok (char* s1, const char* s2)
+{
+    char c;
+    char* start;
+
+    /* Use the stored location if called with a NULL pointer */
+    if (s1 == 0) {
+       s1 = Last;
+    }
+
+    /* If s1 is empty, there are no more tokens. Return 0 in this case. */
+    if (*s1 == '\0') {
+       return 0;
+    }
+
+    /* Search the address of the first element in s1 that equals none
+     * of the characters in s2.
+     */
+    while ((c = *s1) && strchr (s2, c) != 0) {
+       ++s1;
+    }
+    if (c == '\0') {
+       /* No more tokens found */
+       Last = s1;
+       return 0;
+    }
+
+    /* Remember the start of the token */
+    start = s1;
+
+    /* Search for the end of the token */
+    while ((c = *s1) && strchr (s2, c) == 0) {
+       ++s1;
+    }
+    if (c == '\0') {
+       /* Last element */
+       Last = s1;
+    } else {
+       *s1 = '\0';
+       Last = s1 + 1;
+    }
+
+    /* Return the start of the token */
+    return start;
+}
+
+
+
diff --git a/libsrc/common/strupper.s b/libsrc/common/strupper.s
new file mode 100644 (file)
index 0000000..80019ac
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; char* strupper (char* s);
+; char* strupr (char* s);
+;
+; Non-ANSI
+;
+
+       .export         _strupper, _strupr
+       .import         popax
+       .import         __ctype, __cdiff
+       .importzp       ptr1, ptr2
+
+_strupper:
+_strupr:
+       sta     ptr1            ; Save s (working copy)
+       stx     ptr1+1          
+       sta     ptr2
+       sta     ptr2+2          ; save function result
+       ldy     #0
+
+loop:  lda     (ptr1),y        ; get character
+       beq     L9              ; jump if done
+       tax
+       lda     __ctype,x       ; get character classification
+       and     #$01            ; lower case char?
+       beq     L1              ; jump if no
+       txa                     ; get character back into accu
+       clc
+       adc     __cdiff         ; make upper case char
+       sta     (ptr1),y        ; store back
+L1:    iny                     ; next char
+       bne     loop
+       inc     ptr1+1          ; handle offset overflow
+       bne     loop            ; branch always
+
+; Done, return the argument string
+
+L9:    lda     ptr2
+       ldx     ptr2+1
+       rts
+
+
+
diff --git a/libsrc/common/strxfrm.c b/libsrc/common/strxfrm.c
new file mode 100644 (file)
index 0000000..47d9a99
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * strxfrm.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <string.h>
+
+
+
+size_t strxfrm (char* dest, const char* src, size_t count)
+{
+    strncpy (dest, src, count);
+    return strlen (src);
+}
+
+
+
diff --git a/libsrc/common/tolower.s b/libsrc/common/tolower.s
new file mode 100644 (file)
index 0000000..5ecc92f
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int tolower (int c);
+;
+
+       .export         _tolower
+       .import         __ctype, __cdiff
+
+_tolower:
+               tay                     ; Get C into Y
+       lda     __ctype,y       ; Get character classification
+       and     #$02            ; Is this an upper case char?
+       beq     L1              ; Jump if no
+       tya                     ; Get char back into A
+               sec
+       sbc     __cdiff         ; make lower case char
+               rts                     ; CC are set
+
+L1:    tya                     ; Get char back into A
+       rts                     ; CC are set
+
diff --git a/libsrc/common/toupper.s b/libsrc/common/toupper.s
new file mode 100644 (file)
index 0000000..43ff081
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int toupper (int c);
+;
+
+       .export         _toupper
+       .import         __ctype, __cdiff
+
+_toupper:
+       tay                     ; Get c into Y
+       lda     __ctype,y       ; Get character classification
+       and     #$01            ; Mask lower char bit
+       beq     L1              ; Jump if not lower char
+       tya                     ; Get C back into A
+               clc
+       adc     __cdiff         ; make upper case char
+       rts                     ; CC are set
+
+L1:    tya                     ; Get C back
+       rts                     ; CC are set
+
diff --git a/libsrc/common/vcprintf.c b/libsrc/common/vcprintf.c
new file mode 100644 (file)
index 0000000..97e8214
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * vcprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <conio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+    /* Fast screen output */
+    d->ccount += count;
+    while (count) {
+       cputc (*buf);
+       ++buf;
+        --count;
+    }
+}
+
+
+
+int vcprintf (char* format, va_list ap)
+{
+    struct outdesc d;
+
+    /* Setup descriptor */
+    d.fout = out;
+
+    /* Do formatting and output */
+    _printf (&d, format, ap);
+
+    /* Return bytes written */
+    return d.ccount;
+}
+
+
+
diff --git a/libsrc/common/vfprintf.c b/libsrc/common/vfprintf.c
new file mode 100644 (file)
index 0000000..a150aaa
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * vfprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+    /* Write to the file */
+    if (fwrite (buf, count, 1, (FILE*) d->ptr) == -1) {
+       d->ccount = -1;
+    } else {
+       d->ccount += count;
+    }
+}
+
+
+
+int vfprintf (FILE* f, char* format, va_list ap)
+{
+    struct outdesc d;
+
+    /* Setup descriptor */
+    d.fout = out;
+    d.ptr  = f;
+
+    /* Do formatting and output */
+    _printf (&d, format, ap);
+
+    /* Return bytes written */
+    return d.ccount;
+}
+
+
+
diff --git a/libsrc/common/vprintf.c b/libsrc/common/vprintf.c
new file mode 100644 (file)
index 0000000..923d3e5
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * vprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+int vprintf (char* format, va_list ap)
+{
+    return vfprintf (stdout, format, ap);
+}
+
+
+
diff --git a/libsrc/common/vsprintf.c b/libsrc/common/vsprintf.c
new file mode 100644 (file)
index 0000000..bb97a88
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * vsprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+    /* String - be shure to check the size */
+    while (count-- && d->ccount < d->uns) {
+       ((char*) d->ptr) [d->ccount] = *buf;
+       ++buf;
+       ++d->ccount;
+    }
+}
+
+
+
+int vsprintf (char* buf, char* format, va_list ap)
+{
+    struct outdesc d;
+
+    /* Setup descriptor */
+    d.fout = out;
+    d.ptr  = buf;
+    d.uns  = 0x7FFF;
+
+    /* Do formatting and output */
+    _printf (&d, format, ap);
+
+    /* Return bytes written */
+    return d.ccount;
+}
+
+
+
diff --git a/libsrc/common/zerobss.s b/libsrc/common/zerobss.s
new file mode 100644 (file)
index 0000000..9e1d005
--- /dev/null
@@ -0,0 +1,47 @@
+;
+; Ullrich von Bassewitz, 17.09.1998
+;
+; Zero the bss segment.
+;
+
+       .export         zerobss
+       .import         __BSS_RUN__, __BSS_SIZE__
+       .importzp       ptr1
+
+
+.code
+
+zerobss:
+       lda     #<__BSS_RUN__
+       sta     ptr1
+       lda     #>__BSS_RUN__
+       sta     ptr1+1
+       lda     #0
+       tay
+
+; Clear full pages
+
+L1:    ldx     #>__BSS_SIZE__
+       beq     L3
+L2:    sta     (ptr1),y
+       iny
+       bne     L2
+       inc     ptr1+1
+       dex
+       bne     L2
+
+; Clear remaining page (y is zero on entry)
+
+L3:    ldx     #<__BSS_SIZE__
+       beq     L5
+L4:    sta     (ptr1),y
+       iny
+       dex
+       bne     L4
+
+; Done
+
+L5:    rts
+
+
+
diff --git a/libsrc/conio/Makefile b/libsrc/conio/Makefile
new file mode 100644 (file)
index 0000000..2fc751a
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = cputs.o cursor.o cputhex.o scrsize.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f *~
+       @rm -f $(C_OBJS:.o=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
diff --git a/libsrc/conio/cputhex.s b/libsrc/conio/cputhex.s
new file mode 100644 (file)
index 0000000..1aaeed6
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cputhex8 (unsigned char val);
+; void cputhex16 (unsigned val);
+;
+
+       .export         _cputhex8, _cputhex16
+       .import         _cputc
+       .import         __hextab
+
+
+_cputhex16:
+       pha                     ; Save low byte
+       txa                     ; Get high byte into A
+       jsr     _cputhex8       ; Output high byte
+       pla                     ; Restore low byte and run into _cputhex8
+
+_cputhex8:
+       pha                     ; Save the value
+       lsr     a
+       lsr     a
+       lsr     a
+       lsr     a
+       tay
+       lda     __hextab,y
+       jsr     _cputc
+       pla
+       and     #$0F
+       tay
+       lda     __hextab,y
+       jmp     _cputc
+
+
+
+
+
+
+
diff --git a/libsrc/conio/cputs.s b/libsrc/conio/cputs.s
new file mode 100644 (file)
index 0000000..1d86626
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputsxy (unsigned char x, unsigned char y, char* s);
+; void cputs (char* s);
+;
+
+       .export         _cputsxy, _cputs
+       .import         popa, _gotoxy, _cputc
+       .importzp       ptr1, tmp1
+                
+_cputsxy:
+       sta     ptr1            ; Save s for later
+       stx     ptr1+1
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, pop x
+       jmp     L0              ; Same as cputs...
+
+_cputs:        sta     ptr1            ; Save s
+       stx     ptr1+1
+L0:    ldy     #0
+L1:    lda     (ptr1),y
+       beq     L9              ; Jump if done
+       iny
+       sty     tmp1            ; Save offset
+       jsr     _cputc          ; Output char, advance cursor
+       ldy     tmp1            ; Get offset
+       bne     L1              ; Next char
+       inc     ptr1+1          ; Bump high byte
+       bne     L1
+
+; Done
+
+L9:    rts
+
+
diff --git a/libsrc/conio/cursor.s b/libsrc/conio/cursor.s
new file mode 100644 (file)
index 0000000..1dd500e
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; unsigned char cursor (unsigned char onoff);
+;
+
+       .export         _cursor
+       .export         cursor
+
+
+.proc  _cursor
+
+       tay                     ; onoff into Y
+       ldx     #0              ; High byte of result
+       lda     cursor          ; Get old value
+       sty     cursor          ; Set new value
+       rts
+
+.endproc
+
+
+.bss
+
+cursor:        .res    1
+
+
diff --git a/libsrc/conio/scrsize.s b/libsrc/conio/scrsize.s
new file mode 100644 (file)
index 0000000..4be5996
--- /dev/null
@@ -0,0 +1,38 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void screensize (unsigned char* x, unsigned char* y);
+;
+
+       .export         _screensize
+       .export         xsize, ysize
+
+       .import         popax
+       .importzp       ptr1, ptr2
+
+.proc  _screensize
+
+       sta     ptr1            ; Store the y pointer
+       stx     ptr1+1
+
+       jsr     popax           ; get the x pointer
+       sta     ptr2
+       stx     ptr2+1
+
+       ldy     #0
+       lda     xsize
+       sta     (ptr2),y
+       lda     ysize
+       sta     (ptr1),y
+       rts
+
+.endproc       
+
+
+.bss
+
+xsize: .res    1
+ysize: .res    1
+
+
+
diff --git a/libsrc/dbg/.cvsignore b/libsrc/dbg/.cvsignore
new file mode 100644 (file)
index 0000000..4966575
--- /dev/null
@@ -0,0 +1 @@
+dbg.s
diff --git a/libsrc/dbg/Makefile b/libsrc/dbg/Makefile
new file mode 100644 (file)
index 0000000..1dcf8b1
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -g -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS = dbg.o
+
+S_OBJS = asmtab.o dbgdasm.o dbgdump.o dbgisram.o dbgsupp.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f *~
+       @rm -f $(C_OBJS:.o=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
diff --git a/libsrc/dbg/asmtab.s b/libsrc/dbg/asmtab.s
new file mode 100644 (file)
index 0000000..d094485
--- /dev/null
@@ -0,0 +1,61 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; Tables needed for the line assembler/disassembler.
+;
+
+       .export         OffsetTab
+       .export         AdrFlagTab
+       .export         SymbolTab1, SymbolTab2
+       .export         MnemoTab1, MnemoTab2
+
+; -------------------------------------------------------------------------
+; Assembler tables
+
+.rodata
+
+
+OffsetTab:
+       .byte   $40,$02,$45,$03,$D0,$08,$40,$09
+       .byte   $30,$22,$45,$33,$D0,$08,$40,$09
+       .byte   $40,$02,$45,$33,$D0,$08,$40,$09
+       .byte   $40,$02,$45,$B3,$D0,$08,$40,$09
+       .byte   $00,$22,$44,$33,$D0,$8C,$44,$00
+       .byte   $11,$22,$44,$33,$D0,$8C,$44,$9A
+       .byte   $10,$22,$44,$33,$D0,$08,$40,$09
+       .byte   $10,$22,$44,$33,$D0,$08,$40,$09
+       .byte   $62,$13,$78,$A9
+
+AdrFlagTab:
+       .byte   $00,$21,$81,$82,$00,$00,$59,$4D
+       .byte   $91,$92,$86,$4A,$85,$9D
+
+SymbolTab1:
+       .byte   $2C,$29,$2C,$23,$28,$24
+
+SymbolTab2:
+       .byte   $59,$00,$58,$24,$24,$00
+
+MnemoTab1:
+       .byte   $1C,$8A,$1C,$23,$5D,$8B,$1B,$A1
+       .byte   $9D,$8A,$1D,$23,$9D,$8B,$1D,$A1
+       .byte   $00,$29,$19,$AE,$69,$A8,$19,$23
+       .byte   $24,$53,$1B,$23,$24,$53,$19,$A1
+       .byte   $00,$1A,$5B,$5B,$A5,$69,$24,$24
+       .byte   $AE,$AE,$A8,$AD,$29,$00,$7C,$00
+       .byte   $15,$9C,$6D,$9C,$A5,$69,$29,$53
+       .byte   $84,$13,$34,$11,$A5,$69,$23,$A0
+
+MnemoTab2:
+       .byte   $D8,$62,$5A,$48,$26,$62,$94,$88
+       .byte   $54,$44,$C8,$54,$68,$44,$E8,$94
+       .byte   $00,$B4,$08,$84,$74,$B4,$28,$6E
+       .byte   $74,$F4,$CC,$4A,$72,$F2,$A4,$8A
+       .byte   $00,$AA,$A2,$A2,$74,$74,$74,$72
+       .byte   $44,$68,$B2,$32,$B2,$00,$22,$00
+       .byte   $1A,$1A,$26,$26,$72,$72,$88,$C8
+       .byte   $C4,$CA,$26,$48,$44,$44,$A2,$C8
+
+
+   
+
diff --git a/libsrc/dbg/dbg.c b/libsrc/dbg/dbg.c
new file mode 100644 (file)
index 0000000..e657b0c
--- /dev/null
@@ -0,0 +1,1511 @@
+/*
+ * dbg.c
+ *
+ * Ullrich von Bassewitz, 08.08.1998
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <ctype.h>
+#include <6502.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/*                            Function forwards                             */
+/*****************************************************************************/
+
+
+
+/* Forwards for handler functions */
+static char AsmHandler (void);
+static char RegHandler (void);
+static char StackHandler (void);
+static char CStackHandler (void);
+static char DumpHandler (void);
+static char HelpHandler (void);
+
+/* Forwards for other functions */
+static void DisplayPrompt (char* s);
+static void SingleStep (char StepInto);
+static void RedrawStatic (char  Frame);
+static void Redraw (char Frame);
+static char GetKeyUpdate (void);
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+/* Color definitions */
+#ifdef __PLUS4__
+#  define COLOR_BORDER         (BCOLOR_DARKBLUE | CATTR_LUMA6)
+#  define COLOR_BACKGROUND     COLOR_WHITE
+#  define COLOR_TEXTHIGH               COLOR_BLACK
+#  define COLOR_TEXTLOW        COLOR_GRAY1
+#  define COLOR_FRAMEHIGH      COLOR_BLACK
+#  define COLOR_FRAMELOW       COLOR_GRAY2
+#else
+#  ifdef COLOR_GRAY3
+#    define COLOR_BORDER       COLOR_BLACK
+#    define COLOR_BACKGROUND   COLOR_BLACK
+#    define COLOR_TEXTHIGH     COLOR_WHITE
+#    define COLOR_TEXTLOW      COLOR_GRAY3
+#    define COLOR_FRAMEHIGH    COLOR_WHITE
+#    define COLOR_FRAMELOW     COLOR_GRAY3
+#  else
+#    ifdef __APPLE2__
+#      define COLOR_BORDER             COLOR_BLACK
+#      define COLOR_BACKGROUND  COLOR_BLACK
+#      define COLOR_TEXTHIGH   COLOR_BLACK
+#      define COLOR_TEXTLOW    COLOR_BLACK
+#      define COLOR_FRAMEHIGH  COLOR_BLACK
+#      define COLOR_FRAMELOW   COLOR_BLACK
+#    else
+#      define COLOR_BORDER     COLOR_BLACK
+#      define COLOR_BACKGROUND  COLOR_BLACK
+#      define COLOR_TEXTHIGH   COLOR_WHITE
+#      define COLOR_TEXTLOW    COLOR_WHITE
+#      define COLOR_FRAMEHIGH  COLOR_WHITE
+#      define COLOR_FRAMELOW   COLOR_WHITE
+#    endif
+#  endif
+#endif
+
+/* Screen definitions */
+#ifdef __CBM610__
+#  define BIGSCREEN
+#  define MAX_X                80
+#  define MAX_Y                25
+#  define DUMP_BYTES   16
+#else
+#  ifdef __APPLE2__
+#    define MAX_X       40
+#    define MAX_Y       24
+#    define DUMP_BYTES   8
+#  else
+#    ifdef __ATARI__
+#      define MAX_X       40
+#      define MAX_Y       24
+#      define DUMP_BYTES   8
+#    else
+#      define MAX_X    40
+#      define MAX_Y    25
+#      define DUMP_BYTES       8
+#    endif
+#  endif
+#endif
+
+
+
+/* Key definitions */
+#ifndef CH_F1
+#  define CH_F1                '?'
+#endif
+#ifndef CH_F2
+#  define CH_F2                0
+#endif
+#ifndef CH_F3
+#  define CH_F3                0
+#endif
+#ifndef CH_F4
+#  define CH_F4                0
+#endif
+#ifndef CH_F5
+#  define CH_F5                0
+#endif
+#ifndef CH_F6
+#  define CH_F6                0
+#endif
+#ifndef CH_F7
+#  define CH_F7                0
+#endif
+#ifndef CH_F8
+#  define CH_F8                0
+#endif
+
+
+
+/* Defines for opcodes */
+#define        OPC_BRK         0x00
+#define OPC_BPL                0x10
+#define OPC_JSR                0x20
+#define OPC_BMI                0x30
+#define OPC_RTI                0x40
+#define OPC_JMP                0x4C
+#define OPC_BVC                0x50
+#define OPC_RTS                0x60
+#define OPC_JMPIND     0x6C
+#define OPC_BVS                0x70
+#define OPC_BCC                0x90
+#define OPC_BCS                0xB0
+#define OPC_BNE                0xD0
+#define OPC_BEQ                0xF0
+
+
+
+/* Register values that are used also in the assembler stuff */
+extern unsigned char DbgSP;            /* Stack pointer */
+extern unsigned      DbgCS;            /* C stack pointer */
+extern unsigned      DbgHI;            /* High 16 bit of primary reg */
+
+
+
+/* Descriptor for one text line */
+typedef struct {
+    unsigned char x;
+    unsigned char y;
+    char*                text;
+} TextDesc;
+
+/* Window descriptor */
+typedef struct {
+    unsigned char fd_tl;                       /* Top left char */
+    unsigned char fd_tr;               /* Top right char */
+    unsigned char fd_bl;               /* Bottom left char */
+    unsigned char fd_br;               /* Bottom right char */
+    unsigned char fd_x1, fd_y1;                /* Upper left corner */
+    unsigned char fd_x2, fd_y2;                /* Lower right corner */
+    unsigned char fd_width, fd_height; /* Redundant but faster */
+    unsigned char fd_visible;          /* Is the window currently visible? */
+    char (*fd_func) (void);            /* Handler function */
+    unsigned char fd_textcount;                /* Number of text lines to print */
+    TextDesc*            fd_text;              /* Static text in the window */
+} FrameDesc;
+
+
+
+/* Texts for the windows */
+static TextDesc RegText [] = {
+    { 1,  0, "PC" },
+    { 1,  1, "SR" },
+    { 1,  2, "A"  },
+    { 1,  3, "X"  },
+    { 1,  4, "Y"  },
+    { 1,  5, "SP" },
+    { 1,  6, "CS" },
+    { 1,  7, "HI" }
+};
+static TextDesc HelpText [] = {
+    { 1,  0, "F1      Help"                            },
+    { 1,  1, "F2      Toggle breakpoint"               },
+    { 1,  2, "F3      Run until subroutine returns"    },
+    { 1,  3, "F4      Run to cursor"                   },
+    { 1,  4, "F7      Step into"                       },
+    { 1,  5, "F8      Step over"                       },
+    { 1,  6, "1-5     Select active window"            },
+    { 1,  7, "+       Page down"                       },
+    { 1,  8, "-       Page up"                         },
+    { 1,  9, "Cursor  Move up/down"                    },
+    { 1, 10, "c       Continue"                                },
+    { 1, 11, "f       Follow instruction"              },
+    { 1, 12, "o       Goto origin"                     },
+    { 1, 13, "p       Use as new PC value"             },
+    { 1, 14, "r       Redraw screen"                   },
+    { 1, 15, "q       Quit"                            },
+    { 1, 16, "s       Skip next instruction"           },
+};
+
+
+/* Window data */
+static FrameDesc AsmFrame = {
+    CH_ULCORNER, CH_TTEE, CH_LTEE, CH_CROSS,
+    0, 0, MAX_X - 10, 15,
+    MAX_X - 11, 14,
+    1,
+    AsmHandler,
+    0, 0
+};
+static FrameDesc RegFrame = {
+    CH_TTEE, CH_URCORNER, CH_LTEE, CH_RTEE,
+    MAX_X - 10, 0, MAX_X - 1, 9,
+    8, 8,
+    1,
+    RegHandler,
+    sizeof (RegText) / sizeof (RegText [0]), RegText
+};
+static FrameDesc StackFrame = {
+    CH_LTEE, CH_RTEE, CH_CROSS, CH_RTEE,
+    MAX_X - 10, 9, MAX_X - 1, 15,
+    8, 5,
+    1,
+    StackHandler,
+    0, 0
+};
+static FrameDesc CStackFrame = {
+    CH_CROSS, CH_RTEE, CH_BTEE, CH_LRCORNER,
+    MAX_X - 10, 15, MAX_X - 1, MAX_Y - 1,
+    8, MAX_Y - 17,
+    1,
+    CStackHandler,
+    0, 0
+};
+static FrameDesc DumpFrame = {
+    CH_LTEE, CH_CROSS, CH_LLCORNER, CH_BTEE,
+    0, 15, MAX_X - 10, MAX_Y-1,
+    MAX_X - 11, MAX_Y - 17,
+    1,
+    DumpHandler,
+    0, 0
+};
+static FrameDesc HelpFrame = {
+    CH_ULCORNER, CH_URCORNER, CH_LLCORNER, CH_LRCORNER,
+    0, 0, MAX_X - 1, MAX_Y-1,
+    MAX_X - 2, MAX_Y - 2,
+    0,
+    HelpHandler,
+    sizeof (HelpText) / sizeof (HelpText [0]), HelpText
+};
+static FrameDesc* Frames [] = {
+    &AsmFrame,
+    &RegFrame,
+    &StackFrame,
+    &CStackFrame,
+    &DumpFrame,
+    &HelpFrame
+};
+
+/* Number of active frame, -1 = none */
+static int ActiveFrame = -1;
+
+/* Window names */
+#define        WIN_ASM         0
+#define WIN_REG                1
+#define WIN_STACK      2
+#define WIN_CSTACK     3
+#define WIN_DUMP       4
+#define WIN_HELP       5
+
+/* Other window data */
+static unsigned AsmAddr;       /* Start address of output */
+static unsigned DumpAddr;      /* Start address of output */
+static unsigned CStackAddr;    /* Start address of output */
+static unsigned char StackAddr;        /* Start address of output */
+
+
+
+/* Prompt line data */
+static char* ActivePrompt = 0; /* Last prompt line displayed */
+static char PromptColor;       /* Color behind prompt */
+static char PromptLength;      /* Length of current prompt string */
+
+
+
+/* Values for the bk_use field of struct BreakPoint */
+#define BRK_EMPTY      0x00
+#define BRK_USER       0x01
+#define BRK_TMP                0x80
+
+/* Structure describing a breakpoint */
+typedef struct {
+    unsigned      bk_addr;     /* Address, 0 if unused */
+    unsigned char bk_opc;      /* Opcode */
+    unsigned char bk_use;      /* 1 if in use, 0 otherwise */
+} BreakPoint;
+
+
+
+/* Temporary breakpoints - also accessed from the assembler source */
+#define MAX_USERBREAKS 10
+unsigned char DbgBreakCount = 0;
+BreakPoint DbgBreaks [MAX_USERBREAKS+2];
+
+
+
+/*****************************************************************************/
+/*             Forwards for functions in the assembler source               */
+/*****************************************************************************/
+
+
+
+BreakPoint* DbgGetBreakSlot (void);
+/* Search for a free breakpoint slot. Return a pointer to the slot or 0 */
+
+BreakPoint* DbgIsBreak (unsigned Addr);
+/* Check if there is a user breakpoint at the given address, if so, return
+ * a pointer to the slot, else return 0.
+ */
+
+
+
+/*****************************************************************************/
+/*                        Frame/window drawing code                         */
+/*****************************************************************************/
+
+
+
+static void DrawFrame (FrameDesc* F, char Active)
+/* Draw one window frame */
+{
+    TextDesc* T;
+    unsigned char Count;
+    unsigned char tl, tr, bl, br;
+    unsigned char x1, y1, width;
+    unsigned char OldColor;
+
+    /* Determine the characters for the corners, set frame color */
+    if (Active) {
+       OldColor = textcolor (COLOR_FRAMEHIGH);
+               tl = CH_ULCORNER;
+       tr = CH_URCORNER;
+       bl = CH_LLCORNER;
+       br = CH_LRCORNER;
+    } else {
+       OldColor = textcolor (COLOR_FRAMELOW);
+       tl = F->fd_tl;
+       tr = F->fd_tr;
+       bl = F->fd_bl;
+       br = F->fd_br;
+    }
+
+    /* Get the coordinates into locals for faster access */
+    x1 = F->fd_x1;
+    y1 = F->fd_y1;
+    width = F->fd_width;
+
+    /* Top line */
+    cputcxy (x1, y1, tl);
+    chline (width);
+    cputc (tr);
+
+    /* Left line */
+    cvlinexy (x1, ++y1, F->fd_height);
+
+    /* Bottom line */
+    cputc (bl);
+    chline (width);
+    cputc (br);
+
+    /* Right line */
+    cvlinexy (F->fd_x2, y1, F->fd_height);
+
+    /* If the window has static text associated, print the text */
+    textcolor (COLOR_TEXTLOW);
+    Count = F->fd_textcount;
+    T = F->fd_text;
+    while (Count--) {
+       cputsxy (x1 + T->x, y1 + T->y, T->text);
+       ++T;
+    }
+
+    /* Set the old color */
+    textcolor (OldColor);
+}
+
+
+
+static void DrawFrames (void)
+/* Draw all frames */
+{
+    unsigned char I;
+    FrameDesc* F;
+
+    /* Build the frame layout of the screen */
+    for (I = 0; I < sizeof (Frames) / sizeof (Frames [0]); ++I) {
+       F = Frames [I];
+       if (F->fd_visible) {
+           DrawFrame (F, 0);
+       }
+    }
+}
+
+
+
+static void ActivateFrame (int Num, unsigned char Clear)
+/* Activate a new frame, deactivate the old one */
+{
+    unsigned char y;
+    FrameDesc* F;
+
+    if (ActiveFrame != Num) {
+
+       /* Deactivate the old one */
+       if (ActiveFrame >= 0) {
+           DrawFrame (Frames [ActiveFrame], 0);
+       }
+
+       /* Activate the new one */
+       if ((ActiveFrame = Num) >= 0) {
+                   F = Frames [ActiveFrame];
+           /* Clear the frame if requested */
+           if (Clear) {
+               for (y = F->fd_y1+1; y < F->fd_y2; ++y) {
+                   cclearxy (F->fd_x1+1, y, F->fd_width);
+               }
+           }
+           DrawFrame (F, 1);
+       }
+
+       /* Redraw the current prompt line */
+       DisplayPrompt (ActivePrompt);
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                               Prompt line                                */
+/*****************************************************************************/
+
+
+
+static void DisplayPrompt (char* s)
+/* Display a prompt */
+{
+    unsigned char OldColor;
+
+    /* Remember the current color */
+    OldColor = textcolor (COLOR_TEXTHIGH);
+
+    /* Clear the old prompt if there is one */
+    if (ActivePrompt) {
+       textcolor (PromptColor);
+       chlinexy ((MAX_X - PromptLength) / 2, MAX_Y-1, PromptLength);
+    }
+
+    /* Get the new prompt data */
+    ActivePrompt = s;
+    PromptColor  = OldColor;
+    PromptLength = strlen (ActivePrompt);
+
+    /* Display the new prompt */
+    textcolor (COLOR_TEXTHIGH);
+    cputsxy ((MAX_X - PromptLength) / 2, MAX_Y-1, ActivePrompt);
+
+    /* Restore the old color */
+    textcolor (PromptColor);
+}
+
+
+
+static void HelpPrompt (void)
+/* Display a prompt line mentioning the help key */
+{
+    DisplayPrompt ("Press F1 for help");
+}
+
+
+
+static void AnyKeyPrompt (void)
+{
+    DisplayPrompt ("Press any key to continue");
+}
+
+
+
+static char Input (char* Prompt, char* Buf, unsigned char Count)
+/* Read input from the user, return 1 on success, 0 if aborted */
+{
+    int Frame;
+    unsigned char OldColor;
+    unsigned char OldCursor;
+    unsigned char x1;
+    unsigned char i;
+    unsigned char done;
+    char c;
+
+    /* Clear the current prompt line */
+    cclearxy (0, MAX_Y-1, MAX_X);
+
+    /* Display the new prompt */
+    OldColor = textcolor (COLOR_TEXTHIGH);
+    cputsxy (0, MAX_Y-1, Prompt);
+    textcolor (COLOR_TEXTLOW);
+
+    /* Remember where we are, enable the cursor */
+    x1 = wherex ();
+    OldCursor = cursor (1);
+
+    /* Get input and handle it */
+    i = done = 0;
+    do {
+       c = cgetc ();
+       if (isalnum (c) && i < Count) {
+           Buf [i] = c;
+           cputcxy (x1 + i, MAX_Y-1, c);
+           ++i;
+       } else if (i > 0 && c == CH_DEL) {
+                   --i;
+           cputcxy (x1 + i, MAX_Y-1, ' ');
+           gotoxy (x1 + i, MAX_Y-1);
+       } else if (c == '\n') {
+           Buf [i] = '\0';
+           done = 1;
+       } else if (c == CH_ESC) {
+           /* Abort */
+           done = 2;
+       }
+    } while (!done);
+
+    /* Reset settings, display old prompt line */
+    cursor (OldCursor);
+    textcolor (OldColor);
+    DrawFrames ();
+    Frame = ActiveFrame;
+    ActiveFrame = -1;
+    ActivateFrame (Frame, 0);
+
+    return (done == 1);
+}
+
+
+
+static int InputHex (char* Prompt, unsigned* Val)
+/* Prompt for a hexadecimal value */
+{
+    char Buf [5];
+    char* P;
+    char C;
+    unsigned V;
+
+    /* Read input from the user (4 digits max), check input */
+    if (Input (Prompt, Buf, sizeof (Buf)-1) && isxdigit (Buf [0])) {
+
+       /* Check the characters and convert to hex */
+       P = Buf;
+       V = 0;
+       while ((C = *P) && isxdigit (C)) {
+           V <<= 4;
+           if (isdigit (C)) {
+               C -= '0';
+           } else {
+               C = toupper (C) - ('A' - 10);
+           }
+           V += C;
+           ++P;
+       }
+
+       /* Assign the value */
+       *Val = V;
+
+       /* Success */
+       return 1;
+
+    } else {
+
+        /* Failure */
+        return 0;
+
+    }
+}
+
+
+
+static int InputGoto (unsigned* Addr)
+/* Prompt "Goto" and read an address */
+{
+    return InputHex ("Goto: ", Addr);
+}
+
+
+
+static void ErrorPrompt (char* Msg)
+/* Display an error message and wait for a key */
+{
+    /* Save the current prompt */
+    char* OldPrompt = ActivePrompt;
+
+    /* Display the new one */
+    DisplayPrompt (Msg);
+
+    /* Wait for a key and discard it */
+    cgetc ();
+
+    /* Restore the old prompt */
+    DisplayPrompt (OldPrompt);
+}
+
+
+
+static void BreakInRomError (void)
+/* Print an error message if we cannot set a breakpoint */
+{
+    ErrorPrompt ("Cannot set breakpoint - press a key");
+}
+
+
+
+/*****************************************************************************/
+/*                           Breakpoint handling                            */
+/*****************************************************************************/
+
+
+
+static void DbgSetTmpBreak (unsigned Addr)
+/* Set a breakpoint */
+{
+    BreakPoint* B = DbgGetBreakSlot ();
+    B->bk_addr    = Addr;
+    B->bk_use     = BRK_TMP;
+}
+
+
+
+static void DbgToggleUserBreak (unsigned Addr)
+/* Set a breakpoint */
+{
+    BreakPoint* B = DbgIsBreak (Addr);
+
+    if (B) {
+       /* We have a breakpoint, remove it */
+       B->bk_use = BRK_EMPTY;
+       --DbgBreakCount;
+    } else {
+       /* We don't have a breakpoint, set one */
+       if (DbgBreakCount >= MAX_USERBREAKS) {
+           ErrorPrompt ("Too many breakpoints - press a key");
+       } else {
+           /* Test if we can set a breakpoint at that address */
+           if (!DbgIsRAM (Addr)) {
+               BreakInRomError ();
+           } else {
+               /* Set the breakpoint */
+               B = DbgGetBreakSlot ();
+               B->bk_addr = Addr;
+               B->bk_use  = BRK_USER;
+               ++DbgBreakCount;
+           }
+       }
+    }
+}
+
+
+
+static void DbgResetTmpBreaks (void)
+/* Reset all temporary breakpoints */
+{
+    unsigned char i;
+    BreakPoint* B = DbgBreaks;
+
+    for (i = 0; i < MAX_USERBREAKS; ++i) {
+       if (B->bk_use == BRK_TMP) {
+           B->bk_use = BRK_EMPTY;
+       }
+       ++B;
+    }
+}
+
+
+
+static int DbgTmpBreaksOk (void)
+/* Check if the temporary breakpoints can be set, if so, return 1, if not,
+ * reset them all and return 0.
+ */
+{
+    unsigned char i;
+    BreakPoint* B = DbgBreaks;
+    for (i = 0; i < MAX_USERBREAKS; ++i) {
+       if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
+           BreakInRomError ();
+           DbgResetTmpBreaks ();
+           return 0;
+       }
+       ++B;
+    }
+    return 1;
+}
+
+
+
+/*****************************************************************************/
+/*                         Assembler window stuff                           */
+/*****************************************************************************/
+
+
+
+static unsigned AsmBack (unsigned mem, unsigned char lines)
+/* Go back in the assembler window the given number of lines (calculate
+ * new start address).
+ */
+{
+    unsigned cur;
+    unsigned adr [32];
+    unsigned char in;
+
+    unsigned offs = 6;
+    while (1) {
+       in = 0;
+       cur = mem - (lines * 3) - offs;
+       while (1) {
+           cur += DbgDisAsmLen (cur);
+           adr [in] = cur;
+           in = (in + 1) & 0x1F;
+                   if (cur >= mem) {
+               if (cur == mem || offs == 12) {
+                   /* Found */
+                   return adr [(in - lines - 1) & 0x1F];
+               } else {
+                   /* The requested address is inside an instruction, go back
+                    * one more byte and try again.
+                    */
+                   ++offs;
+                   break;
+               }
+           }
+       }
+    }
+}
+
+
+
+static unsigned UpdateAsm (void)
+/* Update the assembler window starting at the given address */
+{
+    char buf [MAX_X];
+    unsigned char len;
+    unsigned char y;
+    unsigned char width = AsmFrame.fd_width;
+    unsigned char x = AsmFrame.fd_x1 + 1;
+    unsigned      m = AsmBack (AsmAddr, 2);
+
+    for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
+       len = DbgDisAsm (m, buf, width);
+               if (m == brk_pc) {
+           buf [4] = '-';
+           buf [5] = '>';
+       }
+       if (DbgIsBreak (m)) {
+           buf [5] = '*';
+       }
+       if (m == AsmAddr) {
+           revers (1);
+           cputsxy (1, y, buf);
+           revers (0);
+       } else {
+           cputsxy (1, y, buf);
+       }
+       m += len;
+    }
+    return m;
+}
+
+
+
+static unsigned AsmArg16 (void)
+/* Return a 16 bit argument */
+{
+    return *(unsigned*)(AsmAddr+1);
+}
+
+
+
+static void AsmFollow (void)
+/* Follow the current instruction */
+{
+    switch (*(unsigned char*) AsmAddr) {
+
+       case OPC_JMP:
+       case OPC_JSR:
+                   AsmAddr = AsmArg16 ();
+           break;
+
+        case OPC_JMPIND:
+           AsmAddr = *(unsigned*)AsmArg16 ();
+           break;
+
+       case OPC_BPL:
+       case OPC_BMI:
+       case OPC_BVC:
+       case OPC_BVS:
+       case OPC_BCC:
+       case OPC_BCS:
+       case OPC_BNE:
+       case OPC_BEQ:
+                   AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
+           break;
+
+        case OPC_RTS:
+           AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
+           break;
+
+        case OPC_RTI:
+           AsmAddr = *(unsigned*) (DbgSP + 0x102);
+           break;
+
+    }
+}
+
+
+
+static void AsmHome (void)
+/* Set the cursor to home position */
+{
+    AsmAddr = brk_pc;
+}
+
+
+
+static void InitAsm (void)
+/* Initialize the asm window */
+{
+    AsmHome ();
+    UpdateAsm ();
+}
+
+
+
+static char AsmHandler (void)
+/* Get characters and handle them */
+{
+    char c;
+    unsigned Last;
+
+    while (1) {
+
+       /* Update the window contents */
+       Last = UpdateAsm ();
+
+       /* Read and handle input */
+       switch (c = GetKeyUpdate ()) {
+
+           case  '+':
+               AsmAddr = Last;
+               break;
+
+           case '-':
+               AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
+               break;
+
+           case CH_F2:
+               DbgToggleUserBreak (AsmAddr);
+               break;
+
+           case 'f':
+               AsmFollow ();
+               break;
+
+           case 'g':
+               InputGoto (&AsmAddr);
+               break;
+
+           case 'o':
+               AsmHome ();
+               break;
+
+           case 'p':
+               brk_pc = AsmAddr;
+               break;
+
+           case CH_CURS_UP:
+               AsmAddr = AsmBack (AsmAddr, 1);
+               break;
+
+           case CH_CURS_DOWN:
+               AsmAddr += DbgDisAsmLen (AsmAddr);
+               break;
+
+           default:
+               return c;
+
+       }
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                          Register window stuff                           */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateReg (void)
+/* Update the register window */
+{
+    unsigned char x1 = RegFrame.fd_x1 + 5;
+    unsigned char x2 = x1 + 2;
+    unsigned char y = RegFrame.fd_y1;
+
+    /* Print the register contents */
+    gotoxy (x1, ++y);          cputhex16 (brk_pc);
+    gotoxy (x2, ++y);          cputhex8  (brk_sr);
+    gotoxy (x2, ++y);          cputhex8  (brk_a);
+    gotoxy (x2, ++y);          cputhex8  (brk_x);
+    gotoxy (x2, ++y);          cputhex8  (brk_y);
+    gotoxy (x2, ++y);          cputhex8  (DbgSP);
+    gotoxy (x1, ++y);   cputhex16 (DbgCS);
+    gotoxy (x1, ++y);          cputhex16 (DbgHI);
+
+    /* Not needed */
+    return 0;
+}
+
+
+
+static void InitReg (void)
+/* Initialize the register window */
+{
+    UpdateReg ();
+}
+
+
+
+static char RegHandler (void)
+/* Get characters and handle them */
+{
+    return GetKeyUpdate ();
+}
+
+
+
+/*****************************************************************************/
+/*                            Stack window stuff                            */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateStack (void)
+/* Update the stack window */
+{
+    unsigned char mem = StackAddr;
+    unsigned char x1 = StackFrame.fd_x1 + 1;
+    unsigned char x2 = x1 + 6;
+    unsigned char y;
+
+    for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
+       gotoxy (x1, y);
+       cputhex8 (mem);
+       gotoxy (x2, y);
+       cputhex8 (* (unsigned char*) (mem + 0x100));
+               ++mem;
+    }
+    return mem;
+}
+
+
+
+static void StackHome (void)
+/* Set the cursor to home position */
+{
+    StackAddr = DbgSP + 1;
+}
+
+
+
+static void InitStack (void)
+/* Initialize the stack window */
+{
+    StackHome ();
+    UpdateStack ();
+}
+
+
+
+static char StackHandler (void)
+/* Get characters and handle them */
+{
+    char c;
+    unsigned char BytesPerPage = StackFrame.fd_height;
+
+    while (1) {
+
+       /* Read and handle input */
+       switch (c = GetKeyUpdate ()) {
+
+           case  '+':
+                       StackAddr += BytesPerPage;
+               break;
+
+           case '-':
+               StackAddr -= BytesPerPage;
+               break;
+
+           case 'o':
+               StackHome ();
+               break;
+
+           case CH_CURS_UP:
+               --StackAddr;
+               break;
+
+           case CH_CURS_DOWN:
+               ++StackAddr;
+               break;
+
+           default:
+               return c;
+
+       }
+
+       /* Update the window contents */
+               UpdateStack ();
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                  C Stack window stuff                            */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateCStack (void)
+/* Update the C stack window */
+{
+    unsigned mem     = CStackAddr;
+    unsigned char x  = CStackFrame.fd_x1 + 5;
+    unsigned char y;
+
+    for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
+       gotoxy (x, y);
+       cputhex16 (* (unsigned*)mem);
+       mem += 2;
+    }
+    cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
+    return mem;
+}
+
+
+
+static void CStackHome (void)
+/* Set the cursor to home position */
+{
+    CStackAddr = DbgCS;
+}
+
+
+
+static void InitCStack (void)
+/* Initialize the C stack window */
+{
+    CStackHome ();
+    UpdateCStack ();
+}
+
+
+
+static char CStackHandler (void)
+/* Get characters and handle them */
+{
+    char c;
+    unsigned char BytesPerPage = CStackFrame.fd_height * 2;
+
+    while (1) {
+
+       /* Read and handle input */
+       switch (c = GetKeyUpdate ()) {
+
+           case  '+':
+                       CStackAddr += BytesPerPage;
+               break;
+
+           case '-':
+               CStackAddr -= BytesPerPage;
+               break;
+
+           case 'o':
+               CStackHome ();
+               break;
+
+           case CH_CURS_UP:
+               CStackAddr -= 2;
+               break;
+
+           case CH_CURS_DOWN:
+               CStackAddr += 2;
+               break;
+
+           default:
+               return c;
+
+       }
+
+       /* Update the window contents */
+               UpdateCStack ();
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            Dump window stuff                             */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateDump (void)
+/* Update the dump window */
+{
+    char Buf [MAX_X];
+    unsigned char y;
+    unsigned mem = DumpAddr;
+    unsigned char x = DumpFrame.fd_x1 + 1;
+    unsigned char* p = (unsigned char*) mem;
+
+    for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
+       cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
+       mem += DUMP_BYTES;
+    }
+    return mem;
+}
+
+
+
+static void DumpHome (void)
+/* Set the cursor to home position */
+{
+    DumpAddr = 0;
+}
+
+
+
+static char DumpHandler (void)
+/* Get characters and handle them */
+{
+    char c;
+    unsigned BytesPerPage = DumpFrame.fd_height * 8;
+
+    while (1) {
+
+       /* Read and handle input */
+       switch (c = GetKeyUpdate ()) {
+
+           case  '+':
+               DumpAddr += BytesPerPage;
+               break;
+
+           case '-':
+               DumpAddr -= BytesPerPage;
+               break;
+
+           case 'g':
+               InputGoto (&DumpAddr);
+               break;
+
+           case 'o':
+               DumpHome ();
+               break;
+
+           case CH_CURS_UP:
+               DumpAddr -= 8;
+               break;
+
+           case CH_CURS_DOWN:
+               DumpAddr += 8;
+               break;
+
+           default:
+               return c;
+
+       }
+
+       /* Update the window contents */
+               UpdateDump ();
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            Help window stuff                             */
+/*****************************************************************************/
+
+
+
+static char HelpHandler (void)
+/* Get characters and handle them */
+{
+    /* Activate the frame */
+    int OldActive = ActiveFrame;
+    ActivateFrame (WIN_HELP, 1);
+
+    /* Say that we're waiting for a key */
+    AnyKeyPrompt ();
+
+    /* Get a character and discard it */
+    cgetc ();
+
+    /* Redraw the old stuff */
+    Redraw (OldActive);
+
+    /* Done, return no char */
+    return 0;
+}
+
+
+
+/*****************************************************************************/
+/*                               Singlestep                                 */
+/*****************************************************************************/
+
+
+
+static unsigned GetArg16 (void)
+/* Read an argument */
+{
+    return *(unsigned*)(brk_pc+1);
+}
+
+
+
+static unsigned GetStack16 (unsigned char Offs)
+/* Fetch a 16 bit value from stack top */
+{
+    return *(unsigned*)(DbgSP+Offs+0x101);
+}
+
+
+
+static void SetRTSBreak (void)
+/* Set a breakpoint at the return target */
+{
+    DbgSetTmpBreak (GetStack16 (0) + 1);
+}
+
+
+
+static void SingleStep (char StepInto)
+{
+    signed char Offs;
+
+    switch (*(unsigned char*) brk_pc) {
+
+        case OPC_JMP:
+           /* Set breakpoint at target */
+           DbgSetTmpBreak (GetArg16 ());
+           return;
+
+       case OPC_JMPIND:
+           /* Indirect jump, ignore CPU error when crossing page */
+           DbgSetTmpBreak (*(unsigned*)GetArg16 ());
+           return;
+
+       case OPC_BPL:
+       case OPC_BMI:
+       case OPC_BVC:
+       case OPC_BVS:
+       case OPC_BCC:
+       case OPC_BCS:
+       case OPC_BNE:
+       case OPC_BEQ:
+           /* Be sure not to set the breakpoint twice if this is a jump to
+            * the following instruction.
+            */
+           Offs = *(signed char*)(brk_pc+1);
+           if (Offs) {
+               DbgSetTmpBreak (brk_pc + Offs + 2);
+           }
+           break;
+
+        case OPC_RTS:
+           /* Set a breakpoint at the return target */
+           SetRTSBreak ();
+           return;
+
+        case OPC_RTI:
+           /* Set a breakpoint at the return target */
+           DbgSetTmpBreak (GetStack16 (1));
+           return;
+
+        case OPC_JSR:
+           if (StepInto) {
+               /* Set breakpoint at target */
+               DbgSetTmpBreak (GetArg16 ());
+               return;
+           }
+           break;
+    }
+
+    /* Place a breakpoint behind the instruction */
+    DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
+}
+
+
+
+/*****************************************************************************/
+/*                       High level window handling                         */
+/*****************************************************************************/
+
+
+
+static void RedrawStatic (char Frame)
+/* Redraw static display stuff */
+{
+    /* Reset the active frame */
+    ActiveFrame = -1;
+
+    /* Clear the screen hide the cursor */
+    bordercolor (COLOR_BORDER);
+    bgcolor (COLOR_BACKGROUND);
+    clrscr ();
+    cursor (0);
+
+    /* Build the frame layout of the screen */
+    textcolor (COLOR_FRAMELOW);
+    DrawFrames ();
+
+    /* Draw the prompt line */
+    HelpPrompt ();
+
+    /* Activate the active frame */
+    ActivateFrame (Frame, 0);
+}
+
+
+
+static void Redraw (char Frame)
+/* Redraw the display in case it's garbled */
+{
+    /* Redraw the static stuff */
+    RedrawStatic (Frame);
+
+    /* Init the window contents */
+    UpdateAsm ();
+    UpdateReg ();
+    UpdateStack ();
+    UpdateCStack ();
+    UpdateDump ();
+}
+
+
+
+static char GetKeyUpdate (void)
+/* Wait for a key updating the windows in the background */
+{
+    static unsigned char Win;
+
+    /* While there are no keys... */
+    while (!kbhit ()) {
+
+       switch (Win) {
+
+           case 0:
+               UpdateAsm ();
+               break;
+
+           case 1:
+               UpdateStack ();
+               break;
+
+           case 2:
+               UpdateCStack ();
+               break;
+
+           case 3:
+               UpdateDump ();
+               break;
+       }
+
+       Win = (Win + 1) & 0x03;
+
+    }
+
+    /* We have a key - return it */
+    return cgetc ();
+}
+
+
+
+/*****************************************************************************/
+/*                      Externally visible functions                        */
+/*****************************************************************************/
+
+
+
+void DbgEntry (void)
+/* Start up the debugger */
+{
+    static unsigned char FirstTime = 1;
+    char c;
+    char done;
+
+    /* If this is the first call, setup the display */
+    if (FirstTime) {
+       FirstTime = 0;
+
+       /* Draw the window, default active frame is ASM frame */
+       RedrawStatic (WIN_ASM);
+       InitAsm ();
+       InitReg ();
+       InitStack ();
+       InitCStack ();
+       UpdateDump ();
+    }
+
+    /* Only initialize variables here, don't do a display update. The actual
+     * display update will be done while waiting for user input.
+     */
+    AsmHome ();
+    UpdateReg ();              /* Must update this (static later) */
+    StackHome ();
+    CStackHome ();
+    DumpHome ();
+
+    /* Wait for user input */
+    done = 0;
+    while (!done) {
+       c = Frames [ActiveFrame]->fd_func ();
+       switch (c) {
+
+           case '1':
+           case '2':
+           case '3':
+           case '4':
+           case '5':
+               ActivateFrame (c - '1', 0);
+               break;
+
+           case CH_F1:
+               HelpHandler ();
+               break;
+
+           case CH_F3:
+               /* Go until return */
+               SetRTSBreak ();
+               done = 1;
+               break;
+
+           case CH_F4:
+               /* Go to cursor, only possible if cursor not at current PC */
+               if (AsmAddr != brk_pc) {
+                   DbgSetTmpBreak (AsmAddr);
+                   done = 1;
+               }
+               break;
+
+           case ' ':
+           case '\n':
+           case CH_F7:
+           case CH_F8:
+               SingleStep (c == CH_F7 || c == ' ');
+               if (DbgTmpBreaksOk ()) {
+                   /* Could set breakpoints */
+                   done = 1;
+               }
+               break;
+
+           case 'c':
+           case 0:
+               done = 1;
+               break;
+
+           case 's':
+               /* Skip instruction */
+               brk_pc += DbgDisAsmLen (brk_pc);
+               InitAsm ();
+               break;
+
+           case 'r':
+               /* Redraw screen */
+               Redraw (ActiveFrame);
+               break;
+
+           case 'q':
+               /* Quit program */
+               clrscr ();
+               exit (1);
+
+       }
+    }
+}
+
+
diff --git a/libsrc/dbg/dbgdasm.s b/libsrc/dbg/dbgdasm.s
new file mode 100644 (file)
index 0000000..80c90e3
--- /dev/null
@@ -0,0 +1,295 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned DbgDisAsm (char* buf, unsigned addr);
+; unsigned DbgDisAsm (unsigned addr);
+;
+;
+; Part of this code is taken from the Plus/4 machine language monitor
+; (TEDMon).
+;
+
+       .import         utsta0, popax
+       .import         __hextab, OffsetTab, AdrFlagTab
+       .import         SymbolTab1, SymbolTab2, MnemoTab1, MnemoTab2
+
+
+
+; -------------------------------------------------------------------------
+; Equates for better readability
+
+       .importzp       sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3
+
+BufIndex       = tmp1          ; Index into output buffer
+OperandLen     = tmp2          ; Length of operand
+BufLen         = tmp3          ; Length of output buffer
+AdrFlagBuf     = tmp4          ; Flag for addressing mode
+YSave          = sreg          ; Temp storage
+XSave          = sreg+1        ; Dito
+BufPtr         = ptr1          ; Pointer to output buffer
+MemPtr         = ptr2          ; Pointer to memory to disassemble
+MnemoBuf       = ptr3          ; Buffer for decoding mnemonic
+
+
+; -------------------------------------------------------------------------
+; Main entries
+
+       .export         _DbgDisAsm, _DbgDisAsmLen
+
+.proc  _DbgDisAsm
+       sta     BufLen          ; Save the buffer length
+       jsr     popax           ; Get the buffer pointer
+       sta     BufPtr
+       stx     BufPtr+1
+       jsr     popax           ; Get the address
+       sta     MemPtr
+       stx     MemPtr+1
+       lda     #0
+       sta     BufIndex        ; Initialize index into buffer
+       jsr     DisAssLine      ; Disassemble one line into the buffer
+
+       lda     BufLen          ; Get requested length
+       sec
+       sbc     BufIndex
+       beq     L2
+       tax                     ; Count into X
+       ldy     BufIndex
+       lda     #$20            ; Get a space
+L1:    sta     (BufPtr),y
+       iny
+       dex
+       bne     L1
+L2:            lda     #0              ; Add C string terminator
+       sta     (BufPtr),y
+       beq     disassret
+
+.endproc
+
+
+_DbgDisAsmLen:
+       sta     MemPtr          ; Save address
+       stx     MemPtr+1
+               ldy     #$00
+               lda     (MemPtr),y      ; Get the opcode from memory...
+       jsr     AnalyzeOPCode   ; ...and analyze it
+disassret:
+       ldx     OperandLen      ; Get length of operand
+       inx                     ; Adjust for opcode byte
+       txa
+       jmp     utsta0          ; Set condition codes
+
+; -------------------------------------------------------------------------
+; Helper functions
+
+
+Put3Spaces:
+               jsr     PutSpace
+Put2Spaces:
+               jsr     PutSpace
+PutSpace:
+               lda     #$20
+PutChar:
+               sty     YSave           ; Save Y
+               ldy     BufIndex        ; Get current line pointer
+       cpy     BufLen          ; Be sure not to overflow the buffer
+       bcs     PC9
+               sta     (BufPtr),y      ; store character
+               iny                     ; bump index
+               sty     BufIndex
+PC9:           ldy     YSave           ; get old value
+       rts
+
+; Print the 16 bit hex value in X/Y
+
+PutHex16:
+       txa
+       jsr     PutHex8
+       tya
+
+; Print 8 bit value in A, save X and Y
+
+PutHex8:
+       stx     XSave
+       sty     YSave
+       ldy     BufIndex
+       pha
+       lsr     a
+       lsr     a
+       lsr     a
+       lsr     a
+       tax
+       lda     __hextab,x
+       sta     (BufPtr),y
+       iny
+       pla
+       and     #$0F
+       tax
+       lda     __hextab,x
+       sta     (BufPtr),y
+       iny
+       sty     BufIndex
+       ldy     YSave
+       ldx     XSave
+       rts
+
+; -------------------------------------------------------------------------
+; Eine Zeile disassemblieren
+
+DisAssLine:
+       ldy     MemPtr
+       ldx     MemPtr+1
+               jsr     PutHex16                ; Print the address
+               jsr     Put2Spaces              ; Add some space
+       ldy     #$00
+               lda     (MemPtr),y              ; Get the opcode from memory...
+       jsr     AnalyzeOPCode           ; ...and analyze it
+       pha                             ; Save mnemonic
+       ldx     OperandLen              ; Number of bytes
+
+; Print the bytes that make up the instruction
+
+       inx
+L2083: dex
+       bpl     L208C                   ; Print the instruction bytes
+       jsr     Put3Spaces              ; If none left, print spaces instead
+       jmp     L2094
+L208C: lda     (MemPtr),y              ; Get a byte from memory
+               jsr     PutHex8                 ; ...and print it
+       jsr     PutSpace                ; Add some space
+
+L2094: iny                             ; Next one...
+       cpy     #$03                    ; Maximum is three
+       bcc     L2083                   ;
+
+       jsr     Put2Spaces              ; Add some space after bytes
+
+; Print the assembler mnemonic
+
+       pla                             ; Get mnemonic code
+       ldx     #$03
+       jsr     PutMnemo                ; Print the mnemonic
+       ldx     #$06
+
+; Print the operand
+
+L20A4: cpx     #$03
+       bne     L20BA
+       ldy     OperandLen
+       beq     L20BA
+
+L20AC: lda     AdrFlagBuf
+       cmp     #$E8                    ; Branch?
+       lda     (MemPtr),y              ; Get branch offset
+       bcs     GetBranchAdr            ; If branch: Calculate address
+       jsr     PutHex8                 ; Otherwise print 8bit value
+       dey
+       bne     L20AC
+
+L20BA: asl     AdrFlagBuf
+       bcc     L20CC
+       lda     SymbolTab1-1,x
+       jsr     PutChar
+       lda     SymbolTab2-1,x
+       beq     L20CC
+       jsr     PutChar
+
+L20CC: dex
+       bne     L20A4
+       rts
+
+; If the instruction is a branch, calculate the absolute address of the
+; branch target and print it.
+
+GetBranchAdr:
+       jsr     L20DD
+       clc
+       adc     #$01
+       bne     L20D9
+       inx                             ; Bump high byte
+L20D9: tay
+       jmp     PutHex16                ; Output address
+
+L20DD: ldx     MemPtr+1
+       tay
+       bpl     L20E3
+       dex
+L20E3: adc     MemPtr
+       bcc     L20E8
+       inx                             ; Bump high byte
+L20E8: rts
+
+; -------------------------------------------------------------------------
+; Subroutine to analyze an opcode byte in A. Will return a byte that
+; encodes the mnemonic, and will set the number of bytes needed for this
+; instruction in OperandLen
+
+AnalyzeOPCode:
+       tay
+       lsr     a
+       bcc     L20F8
+       lsr     a
+       bcs     L2107
+       cmp     #$22
+       beq     L2107
+       and     #$07
+       ora     #$80
+L20F8: lsr     a
+       tax
+       lda     OffsetTab,x
+       bcs     L2103
+       lsr     a
+       lsr     a
+       lsr     a
+       lsr     a
+L2103: and     #$0F
+       bne     L210B
+L2107: ldy     #$80
+       lda     #$00
+L210B: tax
+       lda     AdrFlagTab,x
+       sta     AdrFlagBuf
+       and     #$03
+       sta     OperandLen
+       tya
+       and     #$8F
+       tax
+       tya
+       ldy     #$03
+       cpx     #$8A
+       beq     L212B
+
+L2120: lsr     a
+       bcc     L212B
+       lsr     a
+L2124: lsr     a
+       ora     #$20
+       dey
+       bne     L2124
+       iny
+L212B: dey
+       bne     L2120
+       rts
+
+; -------------------------------------------------------------------------
+; Print the mnemonic with code in A (that code was returned by
+; AnalyzeOpcode).
+
+PutMnemo:
+       tay
+       lda     MnemoTab1,y
+       sta     MnemoBuf
+       lda     MnemoTab2,y
+       sta     MnemoBuf+1
+L213A: lda     #$00
+       ldy     #$05            ; 3*5 bits in two bytes
+L213E: asl     MnemoBuf+1
+       rol     MnemoBuf
+       rol     a
+       dey
+       bne     L213E
+       adc     #$3F
+       jsr     PutChar
+       dex
+       bne     L213A
+       jmp     PutSpace
+
diff --git a/libsrc/dbg/dbgdump.s b/libsrc/dbg/dbgdump.s
new file mode 100644 (file)
index 0000000..ff8818f
--- /dev/null
@@ -0,0 +1,81 @@
+;
+; Ullrich von Bassewitz, 11.08.1998
+;
+; char* DbgMemDump (unsigend Addr, char* Buf, unsigned char Length);
+;
+
+       .export         _DbgMemDump
+       .import         addysp1
+       .import         __hextab
+       .importzp       sp, tmp2, tmp3, tmp4, ptr3, ptr4
+
+_DbgMemDump:
+       ldy     #0
+       lda     (sp),y          ; Get length
+               sta     tmp4
+       iny
+       lda     (sp),y          ; Get the string buffer
+       sta     ptr3
+       iny
+       lda     (sp),y
+               sta     ptr3+1
+       iny
+       lda     (sp),y          ; Get the address
+       sta     ptr4
+       iny
+       lda     (sp),y
+       sta     ptr4+1
+       jsr     addysp1         ; Drop the parameters
+
+       lda     #0
+       sta     tmp2            ; String index
+       sta     tmp3            ; Byte index
+
+; Print the address
+
+               lda     ptr4+1          ; Hi address byte
+               jsr     dump            ; Print address
+       lda     ptr4            ; Lo address byte
+       jsr     dump
+       jsr     putspace        ; Add a space
+
+dump1: dec     tmp4            ; Bytes left?
+       bmi     dump9           ; Jump if no
+               jsr     putspace        ; Add a space
+       ldy     tmp3
+       inc     tmp3
+       lda     (ptr4),y
+       jsr     dump
+       jmp     dump1
+
+dump9:         lda     #0
+       ldy     tmp2
+       sta     (ptr3),y        ; Add string terminator
+       lda     ptr3
+       ldx     ptr3+1          ; We assume this is not zero
+       rts
+
+; Dump one hex byte
+
+dump:  pha
+       lsr     a
+       lsr     a
+       lsr     a
+       lsr     a
+       tax
+       lda     __hextab,x
+       jsr     putc
+       pla
+       and     #$0F
+       tax
+       lda     __hextab,x
+putc:  ldy     tmp2
+       inc     tmp2
+       sta     (ptr3),y
+       rts
+
+putspace:
+       lda     #$20
+       bne     putc
+
+
diff --git a/libsrc/dbg/dbgisram.s b/libsrc/dbg/dbgisram.s
new file mode 100644 (file)
index 0000000..f231b3f
--- /dev/null
@@ -0,0 +1,55 @@
+;
+; Ullrich von Bassewitz, 10.08.1998
+;
+; int DbgIsRAM (unsigned Addr);
+;
+
+       .export         _DbgIsRAM
+       .import         popax, return0, return1
+       .importzp       ptr1
+
+_DbgIsRAM:
+       sta     ptr1            ; Store the address
+       stx     ptr1+1
+
+       ldy     #0
+       php                     ; Save I flag
+       sei                     ; Disable interrupts
+
+       lda     (ptr1),y        ; Get old value
+       pha                     ; ...and save it
+
+       ldx     #3
+L1:    lda     TestVal,x
+       jsr     CheckCell
+       bne     L2
+       dex
+       bpl     L1
+
+; This seems to be RAM
+
+       pla
+       sta     (ptr1),y        ; Restore old value
+       plp                     ; Restore old I flag
+       jmp     return1
+
+; No RAM at this address
+
+L2:    pla
+       sta     (ptr1),y        ; Restore old value
+       plp                     ; Restore old I flag
+       jmp     return0
+
+; Check one memory cell
+
+CheckCell:
+       sta     (ptr1),y
+       cmp     (ptr1),y        ; Could we write it?
+       rts
+
+
+.rodata
+TestVal:
+               .byte   $55, $AA, $33, $CC
+
+
diff --git a/libsrc/dbg/dbgsupp.s b/libsrc/dbg/dbgsupp.s
new file mode 100644 (file)
index 0000000..64ec3c8
--- /dev/null
@@ -0,0 +1,201 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; Support routines for the debugger
+;
+
+       .export         _DbgInit
+               .export         _DbgSP, _DbgCS, _DbgHI
+       .import         popax, return0, _DbgEntry, _set_brk, _end_brk
+       .import         _DbgBreaks
+       .import         _brk_pc
+       .importzp       sp, sreg, ptr1, tmp1, zpspace
+
+; C callable function, will install the debugger
+
+_DbgInit:
+       lda     #<DbgBreak
+       ldx     #>DbgBreak
+       jmp     _set_brk
+
+
+; Entry for the break vector.
+
+DbgBreak:
+       pla
+       sta     retsav
+       pla
+       sta     retsav+1
+
+       cli
+       tsx                     ; Stack pointer
+       stx     _DbgSP
+
+       jsr     DbgSwapZP       ; Swap stuff
+       lda     #<DbgStack      ; Set new stack
+       sta     sp
+       lda     #>DbgStack
+       sta     sp+1
+       jsr     ResetDbgBreaks  ; Reset temporary breakpoints
+       jsr     _DbgEntry       ; Call C code
+       jsr     SetDbgBreaks    ; Set temporary breakpoints
+               jsr     DbgSwapZP       ; Swap stuff back
+
+       lda     retsav+1
+       pha
+       lda     retsav
+       pha
+       rts
+
+
+
+; Stack used when in debugger mode
+
+.bss
+               .res    256
+DbgStack:
+
+; Swap space for the the C temporaries
+
+CTemp:
+_DbgCS:        .res    2               ; sp
+_DbgHI:        .res    2               ; sreg
+       .res    22              ; Other stuff
+_DbgSP:        .res    1
+retsav:        .res    2               ; Save buffer for return address
+
+.code
+
+; Swap the C temporaries
+
+DbgSwapZP:
+       ldy     #zpspace-1
+Swap1:         ldx     CTemp,y
+               lda     sp,y            ; ######
+               sta     CTemp,y
+               txa
+               sta     sp,y
+               dey
+               bpl     Swap1
+               rts
+
+; ----------------------------------------------------------------------------
+; Utility functions
+
+
+; Set/reset the breakpoints. We must do that here since the breakpoints
+; may be in the runtime stuff, causing the C part to fail before it has
+; reset the breakpoints. See declaration of struct breakpoint in the C
+; source
+
+MaxBreaks      = 48            ; 4*12
+
+ResetDbgBreaks:
+               ldy     #0
+               ldx     #0
+L4:            lda     _DbgBreaks+3,x  ; Get bk_use
+               beq     L6              ; Jump if not set
+               bpl     L5              ; Jump if user breakpoint
+               lda     #0
+               sta     _DbgBreaks+3,x  ; Clear if temp breakpoint
+L5:            lda     _DbgBreaks+1,x  ; PC hi
+               sta     ptr1+1
+               lda     _DbgBreaks,x    ; PC lo
+               sta     ptr1
+               lda     _DbgBreaks+2,x  ; Old OPC
+               sta     (ptr1),y        ; Reset the breakpoint
+L6:            inx
+               inx
+               inx
+               inx
+               cpx     #MaxBreaks      ; Done?
+               bne     L4
+               rts
+
+SetDbgBreaks:
+               ldx     #0
+       ldy     #0
+L7:            lda     _DbgBreaks+3,x  ; Get bk_use
+               beq     L8              ; Jump if not set
+       lda     _DbgBreaks+1,x  ; PC hi
+               sta     ptr1+1
+               lda     _DbgBreaks,x    ; PC lo
+               sta     ptr1
+               lda     (ptr1),y        ; Get the breakpoint OPC...
+               sta     _DbgBreaks+2,x  ; ...and save it
+       lda     #$00            ; Load BRK opcode
+       sta     (ptr1),y
+L8:            inx
+               inx
+               inx
+               inx
+               cpx     #MaxBreaks      ; Done?
+               bne     L7
+               rts
+
+; Get a free breakpoint slot or return 0
+
+       .export         _DbgGetBreakSlot
+
+_DbgGetBreakSlot:
+               ldx     #0
+L10:   lda     _DbgBreaks+3,x  ; Get bk_use
+               beq     L11             ; Jump if not set
+       inx
+               inx
+               inx
+               inx
+               cpx     #MaxBreaks      ; Done?
+               bne     L10
+       jmp     return0         ; No free slot
+
+L11:   stx     tmp1
+       lda     #<_DbgBreaks
+       ldx     #>_DbgBreaks
+       clc
+       adc     tmp1
+       bcc     L12
+       inx
+L12:   ldy     #1              ; Force != 0
+       rts
+
+
+; Check if a given address has a user breakpoint set, if found, return the
+; slot, otherwise return 0.
+
+       .export         _DbgIsBreak
+
+_DbgIsBreak:
+       jsr     popax           ; Get address
+       sta     ptr1
+       stx     ptr1+1
+               ldx     #0
+L20:   lda     _DbgBreaks+3,x  ; Get bk_use
+               beq     L21             ; Jump if not set
+       bmi     L21             ; Jump if temp breakpoint
+       lda     _DbgBreaks,x    ; Low byte of address
+       cmp     ptr1
+       bne     L21
+       lda     _DbgBreaks+1,x  ; High byte of address
+       cmp     ptr1+1
+       beq     L22
+L21:   inx
+               inx
+               inx
+       inx
+               cpx     #MaxBreaks      ; Done?
+               bne     L20
+       jmp     return0         ; Not found
+
+L22:           stx     tmp1
+       lda     #<_DbgBreaks
+       ldx     #>_DbgBreaks
+       clc
+       adc     tmp1
+       bcc     L23
+       inx
+L23:           ldy     #1              ; Force != 0
+       rts
+
+
+
diff --git a/libsrc/geos/Makefile b/libsrc/geos/Makefile
new file mode 100644 (file)
index 0000000..30b48a2
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+# Maciej 'YTM/Alliance' Witkowiak
+
+export CC      = ../../../src/cc65
+export CFLAGS  = -O
+export AS              = ../../../src/ca65/ca65
+export ASFLAGS =
+AR             = ../../src/ar65/ar65
+
+
+OBJ_DIRS=disk dlgbox file graph menuicon memory mousesprite process system
+
+all:
+       @for i in devel $(OBJ_DIRS); do $(MAKE) -C $$i; done
+       @mv devel/crt0.o ../geos.o
+       @for i in $(OBJ_DIRS); do $(AR) a ../geos.lib $$i/*.o; done
+
+rebuild: zap all clean
+
+
+.PHONY: clean
+clean:
+       @for i in $(OBJ_DIRS); do \
+           cd $$i;                             \
+           $(MAKE) clean;                      \
+           cd ..;                              \
+       done
+
+.PHONY: zap
+zap:   clean
+       @rm -f ../geos.lib ../geos.o
+
diff --git a/libsrc/geos/devel/Makefile b/libsrc/geos/devel/Makefile
new file mode 100644 (file)
index 0000000..e7c140a
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = crt0.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/devel/crt0.s b/libsrc/geos/devel/crt0.s
new file mode 100644 (file)
index 0000000..00cac2d
--- /dev/null
@@ -0,0 +1,77 @@
+;
+; This must be the *second* file on the linker command line
+; (.cvt header must be the *first* one)
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 26.10.99, 10.3.2000
+
+; no __hinit
+
+       .export         _exit
+               .import         pushax
+       .import         _main
+       .import         zerobss, doatexit
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave, regbank
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+
+sp             =       $72             ; stack pointer
+sreg   =       $74             ; secondary register/high 16 bit for longs
+regsave        =       $76             ; slot to save/restore (E)AX into
+ptr1   =       $7A             ;
+ptr2   =       $7C
+ptr3   =       $7E
+ptr4   =       $70
+tmp1   =       $fb
+tmp2   =       $fc
+tmp3   =       $fd
+tmp4   =       $fe
+
+regbank =      $a3             ; 6 bytes hopefully not used by Kernal
+
+; ------------------------------------------------------------------------
+
+;      .org $0400-508          ; $0400 - length of .cvt header
+;      .include "cvthead.s"
+
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Setup stack
+
+       lda     #<$7900
+       sta     sp
+       lda     #>$7900
+               sta     sp+1            ; Set argument stack ptr
+
+; Initialize the heap
+
+;;!    jsr     __hinit
+
+; Pass an empty command line
+
+       lda     #0
+       tax
+       jsr     pushax          ; argc
+       jsr     pushax          ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+       jmp     $c1c3           ; jump to GEOS MainLoop
+
+; exit must be called from the code!
+
+_exit: 
+       jsr     doatexit        ; call exit functions
+
+       jmp     $c22c           ; EnterDeskTop
diff --git a/libsrc/geos/devel/cvthead.s b/libsrc/geos/devel/cvthead.s
new file mode 100644 (file)
index 0000000..a7b2f56
--- /dev/null
@@ -0,0 +1,110 @@
+
+; NOTE THAT EASIER AND SAFER WAY OF GETTING HEADER IS TO GENERATE IT !!!
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 28.02.2000
+
+; This is .cvt header for GEOS files, it is recognized by Convert v2.5 for GEOS
+; and Star Commander (when copying GEOS files to/from .d64 images)
+; This is only an example, and you should customize file header values (such as
+; Author, Class, Date, filename) either here for all GEOS apps or manually later
+; in GEOS environment using specialized apps or disk editor
+
+; currently only SEQUENTIAL structure is supported, no overlays
+
+; defineable values are marked with ';**' in comment line, please be careful with
+; string lengths
+
+
+;              .org $0400-508          ; $0400 - length of .cvt header
+
+               .segment "HEADER"
+
+               .include "../inc/const.inc"
+
+ProgType       = APPLICATION           ;** may be one of:
+               ; APPLICATION
+               ; ASSEMBLY
+               ; DESK_ACC (unusable, unless you will fix end address in header before run)
+               ; PRINTER  (unusable, unless you change $0400 to $7900 here and in crt0.s)
+               ; INPUT_DEVICE (like above but change $0400 to $fe80, you have $017a bytes)
+               ; AUTO_EXEC (you need to fit in $0400-$4fff area)
+               ; INPUT_128 (like INPUT_DEVICE but change $0400 to $fd80, you have $017a bytes)
+
+           .byte USR | $80             ; DOS filetype
+           .word 0                     ; T&S, will be fixed by converter
+
+           .byte "filename"            ;** DOS filename (16 chars with $a0 padding)
+           .byte $a0,$a0,$a0,$a0,$a0,$a0,$a0,$a0
+           
+           .word 0                     ; header T&S
+
+           .byte SEQUENTIAL            ; GEOS structure
+           .byte ProgType              ; GEOS filetype
+           .byte 00                    ;** year 2000=00 or 100?
+           .byte 02                    ;** month
+           .byte 28                    ;** day
+           .byte 18                    ;** hour
+           .byte 58                    ;** minute
+
+           .word 0                     ; size in blocks, will be fixed by converter
+           
+           .byte "PRG formatted GEOS file V1.0"
+                                       ; converter stamp
+           .res $c4                    ; some bytes are left
+           
+           .byte 3, 21, 63 | $80       ; icon picture header, 63 bytes follow
+       
+           ;** hey, uberhacker! edit icon here!!! ;-))    
+           .byte %11111111, %11111111, %11111111
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %10000000, %00000000, %00000001
+           .byte %11111111, %11111111, %11111111
+
+           .byte USR | $80                             ;again DOS type
+           .byte ProgType                              ;again GEOS type
+           .byte SEQUENTIAL                            ;structure
+           .word $0400                                 ;ProgStart
+           .word $0400-1                               ;ProgEnd (needs proper value for DESK_ACC)
+           .word $0400                                 ;ProgExec
+           
+           .byte "Filename"                            ;**GEOS class (12 chars)
+           .byte $20,$20,$20,$20                       ; padding with spaces to 12
+           
+           .byte "V1.0",0                              ;**version
+           .word 0
+           
+           .byte %01000000                             ;**40/80 columns capability
+; B7 B6
+; 0  0 - runs under GEOS128 but only in 40 column mode
+; 0  1 - runs under GEOS128 in both 40/80 column modes
+; 1  0 - does not run under GEOS128
+; 1  1  - runs under GEOS128 but only in 80 column mode
+
+           
+           .byte "Author"                              ;**author's name (63 chars)
+           .byte 0                                     ;        +terminator
+           .res (63-7)                                 ; padding to 63
+           
+           .byte "Compiled with cc65"                  ;**note (95 chars)
+           .byte 0                                     ;       +terminator
+           .res (95-18)                                ; padding to 95
+           
+           ; end of header, code follows
diff --git a/libsrc/geos/disk/Makefile b/libsrc/geos/disk/Makefile
new file mode 100644 (file)
index 0000000..9020128
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for GEOS lib
+# for cc65
+# 
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = blkalloc.o calcblksfree.o changediskdevice.o chkdkgeos.o enterturbo.o exitturbo.o\
+         findbambit.o freeblock.o getblock.o getdirhead.o getptrcurdknm.o newdisk.o\
+         nxtblkalloc.o opendisk.o purgeturbo.o putblock.o putdirhead.o readblock.o\
+         readbuff.o setnextfree.o setgeosdisk.o writeblock.o writebuff.o verwriteblock.o\
+         gettrse.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/disk/blkalloc.s b/libsrc/geos/disk/blkalloc.s
new file mode 100644 (file)
index 0000000..a8f0638
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char BlkAlloc (struct tr_se output[], int length);
+
+           .import popax
+           .export _BlkAlloc
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_BlkAlloc:
+       sta r2L
+       stx r2H
+       jsr popax
+       sta r4L
+       stx r4H
+       jsr BlkAlloc
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/calcblksfree.s b/libsrc/geos/disk/calcblksfree.s
new file mode 100644 (file)
index 0000000..9e0247e
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; int CalcBlksFree (void);
+
+           .export _CalcBlksFree
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_CalcBlksFree:
+       jsr CalcBlksFree
+       stx errno
+       lda r4L
+       ldx r4H
+       rts
diff --git a/libsrc/geos/disk/changediskdevice.s b/libsrc/geos/disk/changediskdevice.s
new file mode 100644 (file)
index 0000000..204b460
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ChangeDiskDevice (char newDriveNumber);
+
+           .export _ChangeDiskDevice
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_ChangeDiskDevice:
+       jsr ChangeDiskDevice
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/chkdkgeos.s b/libsrc/geos/disk/chkdkgeos.s
new file mode 100644 (file)
index 0000000..0149607
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ChkDkGEOS (void);
+
+           .export _ChkDkGEOS
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_ChkDkGEOS:
+       jsr ChkDkGEOS
+       stx errno
+       lda isGEOS
+       rts
diff --git a/libsrc/geos/disk/enterturbo.s b/libsrc/geos/disk/enterturbo.s
new file mode 100644 (file)
index 0000000..1236fa2
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void EnterTurbo (void);
+
+           .export _EnterTurbo
+
+           .include "../inc/jumptab.inc"
+       
+_EnterTurbo    = EnterTurbo
diff --git a/libsrc/geos/disk/exitturbo.s b/libsrc/geos/disk/exitturbo.s
new file mode 100644 (file)
index 0000000..521f70f
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void ExitTurbo (void);
+
+           .export _ExitTurbo
+
+           .include "../inc/jumptab.inc"
+       
+_ExitTurbo     = ExitTurbo
diff --git a/libsrc/geos/disk/findbambit.s b/libsrc/geos/disk/findbambit.s
new file mode 100644 (file)
index 0000000..66a6898
--- /dev/null
@@ -0,0 +1,25 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char FindBAMBit (struct tr_se *TS);
+; (might be called inUSE (if (!inUSE(block))))
+
+           .import gettrse
+           .export _FindBAMBit
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FindBAMBit:
+       jsr gettrse
+       sta r6L
+       stx r6H
+       jsr FindBAMBit
+       bne inUse
+       lda #0
+       rts
+inUse: lda #$ff 
+       rts
diff --git a/libsrc/geos/disk/freeblock.s b/libsrc/geos/disk/freeblock.s
new file mode 100644 (file)
index 0000000..57b84b7
--- /dev/null
@@ -0,0 +1,22 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char FreeBlock (struct tr_se *TS);
+
+           .import gettrse
+           .export _FreeBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FreeBlock:
+       jsr gettrse
+       sta r6L
+       stx r6H
+       jsr FreeBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/getblock.s b/libsrc/geos/disk/getblock.s
new file mode 100644 (file)
index 0000000..2ba5f3f
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetBlock (struct tr_se *myTS, char *buffer);
+
+           .import popax
+           .import gettrse
+           .export _GetBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_GetBlock:
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr GetBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/getdirhead.s b/libsrc/geos/disk/getdirhead.s
new file mode 100644 (file)
index 0000000..e3a4522
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetDirHead (void);
+
+           .export _GetDirHead
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_GetDirHead:
+       jsr GetDirHead
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/getptrcurdknm.s b/libsrc/geos/disk/getptrcurdknm.s
new file mode 100644 (file)
index 0000000..c36068c
--- /dev/null
@@ -0,0 +1,34 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void GetPtrCurDkNm (char *curName);
+;  (fills curName[17] with current disk's name)
+
+           .importzp ptr4, ptr3
+           .export _GetPtrCurDkNm
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_GetPtrCurDkNm: 
+       sta ptr3
+       stx ptr3+1
+       ldx #ptr4
+       jsr GetPtrCurDkNm
+       ldy #0
+       txa
+       bne fin
+namelp:        lda (ptr4),y
+       cmp #$a0
+       beq fin
+       sta (ptr3),y
+       iny
+       cpy #16
+       bne namelp
+fin:   lda #0
+       sta (ptr3),y
+       stx errno
+       rts
diff --git a/libsrc/geos/disk/gettrse.s b/libsrc/geos/disk/gettrse.s
new file mode 100644 (file)
index 0000000..525df08
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.1.00
+
+           .export gettrse
+           .importzp ptr4
+gettrse:
+           sta ptr4
+           stx ptr4+1
+           ldy #1
+           lda (ptr4),y
+           tax
+           dey
+           lda (ptr4),y
+           rts
diff --git a/libsrc/geos/disk/newdisk.s b/libsrc/geos/disk/newdisk.s
new file mode 100644 (file)
index 0000000..7a539c0
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char NewDisk (void);
+
+           .export _NewDisk
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_NewDisk:
+       jsr NewDisk
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/nxtblkalloc.s b/libsrc/geos/disk/nxtblkalloc.s
new file mode 100644 (file)
index 0000000..8bab0e4
--- /dev/null
@@ -0,0 +1,30 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char NxtBlkAlloc (struct tr_se *startTS, struct tr_se output[], int length );
+
+           .import popax
+           .import gettrse
+           .importzp ptr4
+           .export _NxtBlkAlloc
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_NxtBlkAlloc:
+       sta r2L
+       stx r2H
+       jsr popax
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r3L
+       stx r3H
+       jsr NxtBlkAlloc
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/opendisk.s b/libsrc/geos/disk/opendisk.s
new file mode 100644 (file)
index 0000000..7f0c83d
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char OpenDisk (void);
+
+           .export _OpenDisk
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_OpenDisk:
+       jsr OpenDisk
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/purgeturbo.s b/libsrc/geos/disk/purgeturbo.s
new file mode 100644 (file)
index 0000000..d6a2862
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PurgeTurbo (void);
+
+           .export _PurgeTurbo
+
+           .include "../inc/jumptab.inc"
+       
+_PurgeTurbo    = PurgeTurbo
diff --git a/libsrc/geos/disk/putblock.s b/libsrc/geos/disk/putblock.s
new file mode 100644 (file)
index 0000000..c857bf7
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char PutBlock (struct tr_se *myTS, char *buffer);
+
+           .import popax
+           .import gettrse
+           .export _PutBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_PutBlock:
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr PutBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/putdirhead.s b/libsrc/geos/disk/putdirhead.s
new file mode 100644 (file)
index 0000000..2457786
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char PutDirHead (void);
+
+           .export _PutDirHead
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_PutDirHead:
+       jsr PutDirHead
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/readblock.s b/libsrc/geos/disk/readblock.s
new file mode 100644 (file)
index 0000000..5c319e2
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ReadBlock (struct tr_se myTS, char *buffer);
+
+           .import popax
+           .import gettrse
+           .export _ReadBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_ReadBlock:
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr ReadBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/readbuff.s b/libsrc/geos/disk/readbuff.s
new file mode 100644 (file)
index 0000000..4d6cda0
--- /dev/null
@@ -0,0 +1,22 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; char ReadBuff  (struct tr_se);
+
+           .import gettrse
+           .export _ReadBuff
+
+           .include "../inc/diskdrv.inc"
+           .include "../inc/geossym.inc"
+       
+_ReadBuff:
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr ReadBuff
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/setgeosdisk.s b/libsrc/geos/disk/setgeosdisk.s
new file mode 100644 (file)
index 0000000..cf1f327
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char SetGEOSDisk (void);
+
+           .export _SetGEOSDisk
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_SetGEOSDisk:
+       jsr SetGEOSDisk
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/setnextfree.s b/libsrc/geos/disk/setnextfree.s
new file mode 100644 (file)
index 0000000..df698b1
--- /dev/null
@@ -0,0 +1,23 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; struct tr_se SetNextFree (struct tr_se *startTS);
+
+           .import gettrse
+           .export _SetNextFree
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_SetNextFree:
+       jsr gettrse
+       sta r3L
+       stx r3H
+       jsr SetNextFree
+       stx errno
+       lda r3L
+       ldx r3H
+       rts
diff --git a/libsrc/geos/disk/verwriteblock.s b/libsrc/geos/disk/verwriteblock.s
new file mode 100644 (file)
index 0000000..88601ee
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char VerWriteBlock (struct tr_se *myTS, char *buffer);
+
+           .import popax
+           .import gettrse
+           .export _VerWriteBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_VerWriteBlock:
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr VerWriteBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/writeblock.s b/libsrc/geos/disk/writeblock.s
new file mode 100644 (file)
index 0000000..4574f2f
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char WriteBlock (struct tr_se *myTS, char *buffer);
+
+           .import popax
+           .import gettrse
+           .export _WriteBlock
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_WriteBlock:
+       sta r4L
+       stx r4H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr WriteBlock
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/disk/writebuff.s b/libsrc/geos/disk/writebuff.s
new file mode 100644 (file)
index 0000000..ecd04bc
--- /dev/null
@@ -0,0 +1,22 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; char WriteBuff (struct tr_se*);
+
+           .import gettrse
+           .export _WriteBuff
+
+           .include "../inc/diskdrv.inc"
+           .include "../inc/geossym.inc"
+       
+_WriteBuff:
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr WriteBuff
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/dlgbox/Makefile b/libsrc/geos/dlgbox/Makefile
new file mode 100644 (file)
index 0000000..3f8cb8e
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = dodlgbox.o rstrfrmdialogue.o\
+         dbget2lines.o dlgboxyesno.o dlgboxokcancel.o dlgboxok.o dlgboxgetstring.o\
+         dlgboxfileselect.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/dlgbox/dbget2lines.s b/libsrc/geos/dlgbox/dbget2lines.s
new file mode 100644 (file)
index 0000000..1258dbb
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+           .export DB_get2lines
+           .importzp ptr3,ptr4
+           .import popax
+
+DB_get2lines:
+           sta ptr4
+           stx ptr4+1
+           jsr popax
+           sta ptr3
+           stx ptr3+1
+           rts
diff --git a/libsrc/geos/dlgbox/dlgboxfileselect.s b/libsrc/geos/dlgbox/dlgboxfileselect.s
new file mode 100644 (file)
index 0000000..8efc447
--- /dev/null
@@ -0,0 +1,62 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxFileSelect       (char *class, char ftype, char *fname);
+
+               .export _DlgBoxFileSelect
+               .import popa, popax
+
+               .include "../inc/jumptab.inc"
+               .include "../inc/geossym.inc"
+               .include "../inc/const.inc"
+               .include "../inc/geosmac.ca65.inc"
+
+_DlgBoxFileSelect:
+;          sta r5L
+;          stx r5H
+;          jsr popa
+;          sta r7L
+;          jsr popax
+;          sta r10L
+;          stx r10H
+
+               sta tmp_r5
+               stx tmp_r5+1
+               jsr popa
+               sta tmp_r7L
+               jsr popax
+               sta tmp_r10
+               stx tmp_r10+1
+
+DB_FS_reload:
+               MoveW tmp_r5, r5
+               MoveW tmp_r10, r10
+               MoveB tmp_r7L, r7L
+
+               lda #<paramStrFileSelect
+               ldx #>paramStrFileSelect
+               sta r0L
+               stx r0H
+               jsr DoDlgBox
+               lda r0L
+               cmp #DISK
+               bne DB_FS_Fin
+               jsr OpenDisk
+               txa
+               beq DB_FS_reload
+DB_FS_Fin:     rts
+
+paramStrFileSelect:
+               .byte DEF_DB_POS | 1
+               .byte DBGETFILES, 4, 4
+               .byte OPEN, DBI_X_2, DBI_Y_0+16
+               .byte DISK, DBI_X_2, DBI_Y_0+32+1
+               .byte CANCEL, DBI_X_2, DBI_Y_0+64+3
+               .byte NULL
+
+tmp_r5:                .word 0
+tmp_r7L:       .byte 0
+tmp_r10:       .word 0
diff --git a/libsrc/geos/dlgbox/dlgboxgetstring.s b/libsrc/geos/dlgbox/dlgboxgetstring.s
new file mode 100644 (file)
index 0000000..8398bd7
--- /dev/null
@@ -0,0 +1,40 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxGetString       (char *string, char strlen, char *line1,char *line2);
+
+           .export _DlgBoxGetString
+           .import DB_get2lines
+           .importzp ptr2, ptr3, ptr4
+           .import popa, popax
+           
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           .include "../inc/const.inc"
+
+_DlgBoxGetString:
+           jsr DB_get2lines
+           jsr popa
+           sta DB_strlen
+           jsr popax
+           sta ptr2
+           stx ptr2+1
+           lda #<paramStrGetString
+           ldx #>paramStrGetString
+           sta r0L
+           stx r0H
+           jsr DoDlgBox
+           lda r0L
+           rts
+
+paramStrGetString:
+           .byte DEF_DB_POS | 1
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_1_Y, ptr3
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr4
+           .byte DBGETSTRING, TXT_LN_X, TXT_LN_3_Y, ptr2
+DB_strlen:  .byte 17
+           .byte CANCEL, DBI_X_2, DBI_Y_2
+           .byte NULL
diff --git a/libsrc/geos/dlgbox/dlgboxok.s b/libsrc/geos/dlgbox/dlgboxok.s
new file mode 100644 (file)
index 0000000..8b9b961
--- /dev/null
@@ -0,0 +1,32 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxOk       (char *line1,char *line2);
+
+           .export _DlgBoxOk
+           .import DB_get2lines
+           .importzp ptr3, ptr4
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           .include "../inc/const.inc"
+
+_DlgBoxOk:
+           jsr DB_get2lines
+           lda #<paramStrOk
+           ldx #>paramStrOk
+           sta r0L
+           stx r0H
+           jsr DoDlgBox
+           lda r0L
+           rts
+
+paramStrOk:
+           .byte DEF_DB_POS | 1
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+           .byte OK, DBI_X_0, DBI_Y_2
+           .byte NULL
diff --git a/libsrc/geos/dlgbox/dlgboxokcancel.s b/libsrc/geos/dlgbox/dlgboxokcancel.s
new file mode 100644 (file)
index 0000000..14a4e93
--- /dev/null
@@ -0,0 +1,33 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxOkCancel       (char *line1,char *line2);
+
+           .export _DlgBoxOkCancel
+           .import DB_get2lines
+           .importzp ptr3, ptr4
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           .include "../inc/const.inc"
+
+_DlgBoxOkCancel:
+           jsr DB_get2lines
+           lda #<paramStrOkCancel
+           ldx #>paramStrOkCancel
+           sta r0L
+           stx r0H
+           jsr DoDlgBox
+           lda r0L
+           rts
+
+paramStrOkCancel:
+           .byte DEF_DB_POS | 1
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+           .byte OK, DBI_X_0, DBI_Y_2
+           .byte CANCEL, DBI_X_2, DBI_Y_2
+           .byte NULL
diff --git a/libsrc/geos/dlgbox/dlgboxyesno.s b/libsrc/geos/dlgbox/dlgboxyesno.s
new file mode 100644 (file)
index 0000000..7c1d934
--- /dev/null
@@ -0,0 +1,33 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxYesNo       (char *line1,char *line2);
+
+           .export _DlgBoxYesNo
+           .import DB_get2lines
+           .importzp ptr3, ptr4
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           .include "../inc/const.inc"
+
+_DlgBoxYesNo:
+           jsr DB_get2lines
+           lda #<paramStrYesNo
+           ldx #>paramStrYesNo
+           sta r0L
+           stx r0H
+           jsr DoDlgBox
+           lda r0L
+           rts
+
+paramStrYesNo:
+           .byte DEF_DB_POS | 1
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+           .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+           .byte YES, DBI_X_0, DBI_Y_2
+           .byte NO, DBI_X_2, DBI_Y_2
+           .byte NULL
diff --git a/libsrc/geos/dlgbox/dodlgbox.s b/libsrc/geos/dlgbox/dodlgbox.s
new file mode 100644 (file)
index 0000000..b17a4f6
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DoDlgBox         (char *myParamString);
+
+           .export _DoDlgBox
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_DoDlgBox:
+           sta r0L
+           stx r0H
+           jsr DoDlgBox
+           lda r0L
+           rts
diff --git a/libsrc/geos/dlgbox/rstrfrmdialogue.s b/libsrc/geos/dlgbox/rstrfrmdialogue.s
new file mode 100644 (file)
index 0000000..585e5b3
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char RstrFrmDialogue  (void);
+
+           .export _RstrFrmDialogue
+
+           .include "../inc/jumptab.inc"
+       
+_RstrFrmDialogue       = RstrFrmDialogue
diff --git a/libsrc/geos/file/Makefile b/libsrc/geos/file/Makefile
new file mode 100644 (file)
index 0000000..01299b3
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Makefile for GEOS lib
+# for cc65
+# 
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = get1stdirentry.o getnxtdirentry.o\
+         openrecordfile.o closerecordfile.o nextrecord.o previousrecord.o pointrecord.o\
+         deleterecord.o insertrecord.o appendrecord.o readrecord.o writerecord.o\
+         updaterecordfile.o\
+         findfile.o followchain.o getfhdrinfo.o readfile.o savefile.o freefile.o\
+         deletefile.o renamefile.o findftypes.o readbyte.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/file/appendrecord.s b/libsrc/geos/file/appendrecord.s
new file mode 100644 (file)
index 0000000..243fdf2
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char AppendRecord  (void);
+
+           .export _AppendRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_AppendRecord:
+
+       jsr AppendRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/closerecordfile.s b/libsrc/geos/file/closerecordfile.s
new file mode 100644 (file)
index 0000000..b8454d0
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char CloseRecordFile  (void);
+
+           .export _CloseRecordFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_CloseRecordFile:
+       jsr CloseRecordFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/deletefile.s b/libsrc/geos/file/deletefile.s
new file mode 100644 (file)
index 0000000..919e55e
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DeleteFile  (char *myName);
+
+           .export _DeleteFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_DeleteFile:
+       sta r0L
+       stx r0H
+       jsr DeleteFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/deleterecord.s b/libsrc/geos/file/deleterecord.s
new file mode 100644 (file)
index 0000000..8691b6a
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DeleteRecord  (void);
+
+           .export _DeleteRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_DeleteRecord:
+       jsr DeleteRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/findfile.s b/libsrc/geos/file/findfile.s
new file mode 100644 (file)
index 0000000..65008d6
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FindFile  (char *myName);
+
+           .export _FindFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FindFile:
+       sta r6L
+       stx r6H
+       jsr FindFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/findftypes.s b/libsrc/geos/file/findftypes.s
new file mode 100644 (file)
index 0000000..66e270c
--- /dev/null
@@ -0,0 +1,28 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FindFTypes  (char *buffer, char fileType, char fileMax, char *Class);
+
+           .export _FindFTypes
+           .import popax, popa
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FindFTypes:
+       sta r10L
+       stx r10H
+       jsr popa
+       sta r7H
+       jsr popa
+       sta r7L
+       jsr popax
+       sta r6L
+       stx r6H
+       jsr FindFTypes
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/followchain.s b/libsrc/geos/file/followchain.s
new file mode 100644 (file)
index 0000000..a76d9c6
--- /dev/null
@@ -0,0 +1,26 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FollowChain  (struct tr_se *myTrSe, char *buffer);
+
+           .export _FollowChain
+           .import popax
+           .import gettrse
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FollowChain:
+       sta r3L
+       stx r3H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr FollowChain
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/freefile.s b/libsrc/geos/file/freefile.s
new file mode 100644 (file)
index 0000000..dd02d28
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FreeFile  (struct trse myTrSe[]);
+
+           .export _FreeFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_FreeFile:
+       sta r9L
+       stx r9H
+       jsr FreeFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/get1stdirentry.s b/libsrc/geos/file/get1stdirentry.s
new file mode 100644 (file)
index 0000000..7542c7d
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; struct filehandle* Get1stDirEntry (void);
+
+           .export _Get1stDirEntry
+
+           .include "../inc/diskdrv.inc"
+           .include "../inc/geossym.inc"
+
+_Get1stDirEntry:
+       jsr Get1stDirEntry
+       stx errno
+       lda r5L
+       ldx r5H
+       rts
diff --git a/libsrc/geos/file/getfhdrinfo.s b/libsrc/geos/file/getfhdrinfo.s
new file mode 100644 (file)
index 0000000..815a707
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char GetFHdrInfo  (struct filehandle *myFile);
+
+           .export _GetFHdrInfo
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_GetFHdrInfo:
+       sta r9L
+       stx r9H
+       jsr GetFHdrInfo
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/getnxtdirentry.s b/libsrc/geos/file/getnxtdirentry.s
new file mode 100644 (file)
index 0000000..d67f3fc
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; struct filehandle* GetNxtDirEntry (void);
+
+           .export _GetNxtDirEntry
+
+           .include "../inc/diskdrv.inc"
+           .include "../inc/geossym.inc"
+
+_GetNxtDirEntry:
+       jsr GetNxtDirEntry
+       stx errno
+       lda r5L
+       ldx r5H
+       rts
diff --git a/libsrc/geos/file/insertrecord.s b/libsrc/geos/file/insertrecord.s
new file mode 100644 (file)
index 0000000..5b94de9
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char InsertRecord  (void);
+
+           .export _InsertRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_InsertRecord:
+       jsr InsertRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/nextrecord.s b/libsrc/geos/file/nextrecord.s
new file mode 100644 (file)
index 0000000..473806e
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char NextRecord  (void);
+
+           .export _NextRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_NextRecord:
+       jsr NextRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/openrecordfile.s b/libsrc/geos/file/openrecordfile.s
new file mode 100644 (file)
index 0000000..9251e67
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char OpenRecordFile  (char *myName);
+
+           .export _OpenRecordFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_OpenRecordFile:
+       sta r0L
+       stx r0H
+       jsr OpenRecordFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/pointrecord.s b/libsrc/geos/file/pointrecord.s
new file mode 100644 (file)
index 0000000..bfd5b8b
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char PointRecord  (char recordNum);
+
+           .export _PointRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_PointRecord:
+       jsr PointRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/previousrecord.s b/libsrc/geos/file/previousrecord.s
new file mode 100644 (file)
index 0000000..2c84ba5
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char PreviousRecord  (void);
+
+           .export _PreviousRecord
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_PreviousRecord:
+       jsr PreviousRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/readbyte.s b/libsrc/geos/file/readbyte.s
new file mode 100644 (file)
index 0000000..e618ebf
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadByte  (void);
+
+           .export _ReadByte
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_ReadByte:
+       jsr ReadByte
+       stx errno
+       rts
diff --git a/libsrc/geos/file/readfile.s b/libsrc/geos/file/readfile.s
new file mode 100644 (file)
index 0000000..333d096
--- /dev/null
@@ -0,0 +1,29 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadFile  (struct tr_se *myTS, char *buffer, int length);
+
+           .export _ReadFile
+           .import popax
+           .import gettrse
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_ReadFile:
+       sta r2L
+       stx r2H
+       jsr popax
+       sta r7L
+       stx r7H
+       jsr popax
+       jsr gettrse
+       sta r1L
+       stx r1H
+       jsr ReadFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/readrecord.s b/libsrc/geos/file/readrecord.s
new file mode 100644 (file)
index 0000000..4ccda9b
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadRecord  (char *buffer, int length);
+
+           .export _ReadRecord
+           .import popax
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_ReadRecord:
+       sta r2L
+       stx r2H
+       jsr popax
+       sta r7L
+       stx r7H
+       jsr ReadRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/renamefile.s b/libsrc/geos/file/renamefile.s
new file mode 100644 (file)
index 0000000..dfa8855
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char RenameFile  (char *source, char *target);
+
+           .export _RenameFile
+           .import popax
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_RenameFile:
+       sta r0L
+       stx r0H
+       jsr popax
+       sta r6L
+       stx r6H
+       jsr RenameFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/savefile.s b/libsrc/geos/file/savefile.s
new file mode 100644 (file)
index 0000000..e0f3608
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char SaveFile  (struct fileheader *myHeader);
+
+           .export _SaveFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_SaveFile:
+       sta r9L
+       stx r9H
+       jsr SaveFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/updaterecordfile.s b/libsrc/geos/file/updaterecordfile.s
new file mode 100644 (file)
index 0000000..9960022
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char UpdateRecordFile  (void);
+
+           .export _UpdateRecordFile
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_UpdateRecordFile:
+       jsr UpdateRecordFile
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/file/writerecord.s b/libsrc/geos/file/writerecord.s
new file mode 100644 (file)
index 0000000..7f59482
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char WriteRecord  (char *buffer, int length);
+
+           .export _WriteRecord
+           .import popax
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+       
+_WriteRecord:
+       sta r2L
+       stx r2H
+       jsr popax
+       sta r7L
+       stx r7H
+       jsr WriteRecord
+       stx errno
+       txa
+       rts
diff --git a/libsrc/geos/graph/Makefile b/libsrc/geos/graph/Makefile
new file mode 100644 (file)
index 0000000..1abf1a9
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = drawline.o drawpoint.o framerectangle.o hlineregs.o horizontalline.o\
+         imprintrectangle.o invertline.o invertrectangle.o pointregs.o recoverline.o\
+         recoverrectangle.o rectangle.o initdrawwindow.o setpattern.o testpoint.o verticalline.o\
+         putchar.o putdecimal.o putstring.o usesystemfont.o\
+         getcharwidth.o loadcharset.o bitmapup.o bitmapregs.o bitmapclip.o bitotherclip.o\
+         graphicsstring.o getintcharint.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/graph/bitmapclip.s b/libsrc/geos/graph/bitmapclip.s
new file mode 100644 (file)
index 0000000..9876efe
--- /dev/null
@@ -0,0 +1,25 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitmapClip      (char skipl, char skipr, int skipy, struct iconpic *myGfx);
+
+           .import popa, popax
+           .import BitmapRegs
+           .export _BitmapClip
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_BitmapClip:
+           jsr BitmapRegs
+           jsr popax
+           sta r12L
+           stx r12H
+           jsr popa
+           sta r11H
+           jsr popa
+           sta r11L
+           jmp BitmapClip
diff --git a/libsrc/geos/graph/bitmapregs.s b/libsrc/geos/graph/bitmapregs.s
new file mode 100644 (file)
index 0000000..068239b
--- /dev/null
@@ -0,0 +1,22 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+           .importzp ptr4
+           
+           .export BitmapRegs
+
+           .include "../inc/geossym.inc"
+
+BitmapRegs:                    ;a/x is a struct iconpic*
+           sta ptr4
+           stx ptr4+1
+           ldy #0
+bmpLp:     lda (ptr4),y
+           sta r0L,y
+           iny
+           cpy #6
+           bne bmpLp
+           rts
diff --git a/libsrc/geos/graph/bitmapup.s b/libsrc/geos/graph/bitmapup.s
new file mode 100644 (file)
index 0000000..fbaa5f4
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitmapUp        (struct iconpic *myGfx);
+
+
+           .import BitmapRegs
+           .export _BitmapUp
+
+           .include "../inc/jumptab.inc"
+
+_BitmapUp:
+           jsr BitmapRegs
+           jmp BitmapUp
diff --git a/libsrc/geos/graph/bitotherclip.s b/libsrc/geos/graph/bitotherclip.s
new file mode 100644 (file)
index 0000000..6da0f4e
--- /dev/null
@@ -0,0 +1,37 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitOtherClip    (void *proc1, void* proc2, char skipl, char skipr, int skipy, 
+;                              struct iconpic *myGfx);
+
+; both proc1, proc2 should be: char __fastcall something (void);
+;      proc1 is called before reading a byte (.A returns next data)
+;      proc2 is called before reading each byte which is not pattern (code >219)
+
+
+           .import popa, popax
+           .import BitOtherRegs
+           .export _BitOtherClip
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_BitOtherClip:
+           jsr BitOtherRegs
+           jsr popax
+           sta r12L
+           stx r12H
+           jsr popa
+           sta r11H
+           jsr popa
+           sta r11L
+           jsr popax
+           sta r14L
+           stx r14H
+           jsr popax
+           sta r13L
+           stx r13H
+           jmp BitOtherClip
diff --git a/libsrc/geos/graph/drawline.s b/libsrc/geos/graph/drawline.s
new file mode 100644 (file)
index 0000000..baa68bc
--- /dev/null
@@ -0,0 +1,23 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void DrawLine         (struct window *mywindow);
+
+           .import _InitDrawWindow
+           .export _DrawLine
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           .include "../inc/geosmac.ca65.inc"
+
+_DrawLine:
+           tay
+           PushW r2
+           tya
+           jsr _InitDrawWindow
+           MoveW r2, r11
+           PopW r2
+           jmp DrawLine
diff --git a/libsrc/geos/graph/drawpoint.s b/libsrc/geos/graph/drawpoint.s
new file mode 100644 (file)
index 0000000..842a9b9
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void DrawPoint       (struct pixel *mypixel);
+
+
+           .import PointRegs
+           .export _DrawPoint
+
+           .include "../inc/jumptab.inc"
+
+_DrawPoint:
+           jsr PointRegs
+           jmp DrawPoint
diff --git a/libsrc/geos/graph/framerectangle.s b/libsrc/geos/graph/framerectangle.s
new file mode 100644 (file)
index 0000000..e9b7378
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void FrameRectangle   (char pattern);
+
+           .export _FrameRectangle
+
+           .include "../inc/jumptab.inc"
+           
+_FrameRectangle = FrameRectangle
diff --git a/libsrc/geos/graph/getcharwidth.s b/libsrc/geos/graph/getcharwidth.s
new file mode 100644 (file)
index 0000000..e0f0886
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetCharWidth (char character);
+
+           .export _GetCharWidth
+
+           .include "../inc/jumptab.inc"
+
+_GetCharWidth = GetCharWidth
diff --git a/libsrc/geos/graph/getintcharint.s b/libsrc/geos/graph/getintcharint.s
new file mode 100644 (file)
index 0000000..fdf5af7
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 11.03.2000
+
+           .import popa, popax
+           .export getintcharint
+
+           .include "../inc/geossym.inc"
+
+getintcharint:
+           sta r11L
+           stx r11H
+           jsr popa
+           sta r1H
+           jsr popax
+           sta r0L
+           stx r0H
+           rts
+
diff --git a/libsrc/geos/graph/graphicsstring.s b/libsrc/geos/graph/graphicsstring.s
new file mode 100644 (file)
index 0000000..3e751fc
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; void GraphicsString         (char *myString);
+
+           .export _GraphicsString
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_GraphicsString:
+           sta r0L
+           stx r0H
+           jmp GraphicsString
diff --git a/libsrc/geos/graph/hlineregs.s b/libsrc/geos/graph/hlineregs.s
new file mode 100644 (file)
index 0000000..8b5f234
--- /dev/null
@@ -0,0 +1,22 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+
+           .import popax, popa
+
+           .export HLineRegs
+
+           .include "../inc/geossym.inc"
+
+HLineRegs:
+           stx r4H
+           sta r4L
+           jsr popax
+           stx r3H
+           sta r3L
+           jsr popa
+           sta r11L
+           rts
diff --git a/libsrc/geos/graph/horizontalline.s b/libsrc/geos/graph/horizontalline.s
new file mode 100644 (file)
index 0000000..fa68ac7
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void HorizontalLine (char pattern, char y, int xstart, int xend);
+
+           .import popa
+           .import HLineRegs
+           
+           .export _HorizontalLine
+
+           .include "../inc/jumptab.inc"
+
+_HorizontalLine:
+           jsr HLineRegs
+           jsr popa
+           jmp HorizontalLine
diff --git a/libsrc/geos/graph/imprintrectangle.s b/libsrc/geos/graph/imprintrectangle.s
new file mode 100644 (file)
index 0000000..02b896a
--- /dev/null
@@ -0,0 +1,14 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void ImprintRectangle (void);
+           
+           .export _ImprintRectangle
+
+           .include "../inc/jumptab.inc"
+           
+_ImprintRectangle = ImprintRectangle
+
diff --git a/libsrc/geos/graph/initdrawwindow.s b/libsrc/geos/graph/initdrawwindow.s
new file mode 100644 (file)
index 0000000..307af72
--- /dev/null
@@ -0,0 +1,25 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+; 11.03.2000
+
+; void InitDrawWindow (struct window *myWindow);
+
+           .importzp ptr4
+           
+           .export _InitDrawWindow
+
+           .include "../inc/geossym.inc"
+
+_InitDrawWindow:                       ;a/x is a struct window*
+           sta ptr4
+           stx ptr4+1
+           ldy #0
+copyWin:    lda (ptr4),y
+           sta r2L,y
+           iny
+           cpy #6
+           bne copyWin
+           rts
diff --git a/libsrc/geos/graph/invertline.s b/libsrc/geos/graph/invertline.s
new file mode 100644 (file)
index 0000000..dcae0b4
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void InvertLine     (char y, int xstart, int xend);
+
+           .import HLineRegs
+           .export _InvertLine
+
+           .include "../inc/jumptab.inc"
+           
+_InvertLine:
+           jsr HLineRegs
+           jmp InvertLine
diff --git a/libsrc/geos/graph/invertrectangle.s b/libsrc/geos/graph/invertrectangle.s
new file mode 100644 (file)
index 0000000..0ef9d85
--- /dev/null
@@ -0,0 +1,14 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void InvertRectangle  (void);
+
+           .export _InvertRectangle
+           
+           .include "../inc/jumptab.inc"
+
+_InvertRectangle = InvertRectangle
+
diff --git a/libsrc/geos/graph/loadcharset.s b/libsrc/geos/graph/loadcharset.s
new file mode 100644 (file)
index 0000000..d61b7f9
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void LoadCharSet (struct fontdesc *myFont);
+
+           .export _LoadCharSet
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_LoadCharSet:
+           sta r0L
+           stx r0H
+           jmp LoadCharSet
diff --git a/libsrc/geos/graph/pointregs.s b/libsrc/geos/graph/pointregs.s
new file mode 100644 (file)
index 0000000..f87667a
--- /dev/null
@@ -0,0 +1,25 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+           .importzp ptr4
+           
+           .export PointRegs
+
+           .include "../inc/geossym.inc"
+
+PointRegs:                     ;a/x is a struct pixel*
+           sta ptr4
+           stx ptr4+1
+           ldy #0
+           lda (ptr4),y
+           sta r3L
+           iny
+           lda (ptr4),y
+           sta r3H
+           iny
+           lda (ptr4),y
+           sta r11L
+           rts
diff --git a/libsrc/geos/graph/putchar.s b/libsrc/geos/graph/putchar.s
new file mode 100644 (file)
index 0000000..ed88580
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutChar         (char character, char y, int x);
+
+           .import popa
+           .export _PutChar
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_PutChar:
+           sta r11L
+           stx r11H
+           jsr popa
+           sta r1H
+           jsr popa
+           jmp PutChar
diff --git a/libsrc/geos/graph/putdecimal.s b/libsrc/geos/graph/putdecimal.s
new file mode 100644 (file)
index 0000000..77e0ed2
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutDecimal         (char style, int value, char y, int x);
+
+           .import popa, popax
+           .import getintcharint
+           .export _PutDecimal
+
+           .include "../inc/jumptab.inc"
+
+_PutDecimal:
+           jsr getintcharint
+           jsr popa
+           jmp PutDecimal
diff --git a/libsrc/geos/graph/putstring.s b/libsrc/geos/graph/putstring.s
new file mode 100644 (file)
index 0000000..53b685d
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutString       (char *mytxt, char y, int x);
+
+           .import popax, popa
+           .import getintcharint
+           .export _PutString
+
+           .include "../inc/jumptab.inc"
+
+_PutString:
+           jsr getintcharint
+           jmp PutString
diff --git a/libsrc/geos/graph/recoverline.s b/libsrc/geos/graph/recoverline.s
new file mode 100644 (file)
index 0000000..1a59ae2
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void RecoverLine    (char y, int xstart, int xend);
+
+           .import HLineRegs
+
+           .export _RecoverLine
+           
+           .include "../inc/jumptab.inc"
+
+_RecoverLine:
+           jsr HLineRegs
+           jmp RecoverLine
+
diff --git a/libsrc/geos/graph/recoverrectangle.s b/libsrc/geos/graph/recoverrectangle.s
new file mode 100644 (file)
index 0000000..426b83d
--- /dev/null
@@ -0,0 +1,14 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void RecoverRectangle (void);
+           
+           .export _RecoverRectangle
+
+           .include "../inc/jumptab.inc"
+           
+_RecoverRectangle = RecoverRectangle
+
diff --git a/libsrc/geos/graph/rectangle.s b/libsrc/geos/graph/rectangle.s
new file mode 100644 (file)
index 0000000..c25a4e6
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void Rectangle        (void);
+
+           .export _Rectangle
+           
+           .include "../inc/jumptab.inc"
+
+_Rectangle = Rectangle
diff --git a/libsrc/geos/graph/setpattern.s b/libsrc/geos/graph/setpattern.s
new file mode 100644 (file)
index 0000000..e5c80bf
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void SetPattern     (char pattern);
+
+           .export _SetPattern
+
+           .include "../inc/jumptab.inc"
+
+_SetPattern = SetPattern
diff --git a/libsrc/geos/graph/testpoint.s b/libsrc/geos/graph/testpoint.s
new file mode 100644 (file)
index 0000000..f068e77
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; char TestPoint       (struct pixel *mypixel);
+
+           .import PointRegs
+           .export _TestPoint
+
+           .include "../inc/jumptab.inc"
+           
+_TestPoint:
+           jsr PointRegs
+           jsr TestPoint
+           bcc goFalse
+           lda #$ff
+           rts
+goFalse:    lda #0
+           rts
diff --git a/libsrc/geos/graph/usesystemfont.s b/libsrc/geos/graph/usesystemfont.s
new file mode 100644 (file)
index 0000000..0907273
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void UseSystemFont (void);
+
+           .export _UseSystemFont
+
+           .include "../inc/jumptab.inc"
+
+_UseSystemFont = UseSystemFont
diff --git a/libsrc/geos/graph/verticalline.s b/libsrc/geos/graph/verticalline.s
new file mode 100644 (file)
index 0000000..5ce0770
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void VerticalLine   (char pattern, char ystart, char yend, int x);
+
+           .import popa
+                           
+           .export _VerticalLine
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+           
+_VerticalLine:
+           stx r4H
+           sta r4L
+           jsr popa
+           sta r3H
+           jsr popa
+           sta r3L
+           jsr popa
+           jmp VerticalLine
diff --git a/libsrc/geos/inc/const.inc b/libsrc/geos/inc/const.inc
new file mode 100644 (file)
index 0000000..dcbf8e4
--- /dev/null
@@ -0,0 +1,418 @@
+
+;GeosConst - various system constans sorted by function
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99, 18-3-99
+
+NULL                   =       0
+FALSE                  =       NULL
+TRUE                   =       $ff
+
+MOUSE_SPRNUM           =       0
+
+DISK_DRV_LGH           =       $0d80
+
+;
+;filetypes
+;      GEOS
+NOT_GEOS               =       0
+BASIC                  =       1
+ASSEMBLY               =       2
+DATA                   =       3
+SYSTEM                 =       4
+DESK_ACC               =       5
+APPLICATION            =       6
+APPL_DATA              =       7
+FONT                   =       8
+PRINTER                =       9
+INPUT_DEVICE           =       10
+DISK_DEVICE            =       11
+SYSTEM_BOOT            =       12
+TEMPORARY              =       13
+AUTO_EXEC              =       14
+INPUT_128              =       15
+NUMFILETYPES           =       16
+;      structure
+SEQUENTIAL             =       0
+VLIR                   =       1
+;      DOS
+DEL                    =       0
+SEQ                    =       1
+PRG                    =       2
+USR                    =       3
+REL                    =       4
+CBM                    =       5
+
+;drivetypes
+DRV_NULL               =       0
+DRV_1541               =       1
+DRV_1571               =       2
+DRV_1581               =       3
+DRV_NETWORK            =       15
+
+;various disk
+REL_FILE_NUM           =       9
+CMND_FILE_NUM          =       15
+MAX_CMND_STR           =       32
+DIR_1581_TRACK         =       40
+DIR_ACC_CHAN           =       13
+DIR_TRACK              =       18
+N_TRACKS               =       35
+DK_NM_ID_LEN           =       18
+TRACK                  =       9
+SECTOR                 =       12
+TOTAL_BLOCKS           =       664
+
+;colours
+BLACK                  =       0
+WHITE                  =       1
+RED                    =       2
+CYAN                   =       3
+PURPLE                 =       4
+GREEN                  =       5
+BLUE                   =       6
+YELLOW                 =       7
+ORANGE                 =       8
+BROWN                  =       9
+LTRED                  =       10
+DKGREY                 =       11
+GREY                   =       12
+MEDGREY                =       12
+LTGREEN                =       13
+LTBLUE                 =       14
+LTGREY                 =       15
+
+;vic memory banks
+GRBANK0                =       %11
+GRBANK1                =       %10
+GRBANK2                =       %01
+GRBANK3                =       %00
+
+;screen
+VIC_X_POS_OFF          =       24
+VIC_Y_POS_OFF          =       50
+SC_BYTE_WIDTH          =       40
+SC_PIX_HEIGHT          =       200
+SC_PIX_WIDTH           =       320
+SC_SIZE                =       8000
+;128 screen size constants
+SCREENBYTEWIDTH        =       80
+SCREENPIXELWIDTH       =       640
+
+
+;control characters
+EOF                    =       0
+BACKSPACE              =       8
+FORWARDSPACE           =       9
+TAB                    =       9
+LF                     =       10
+HOME                   =       11
+PAGE_BREAK             =       12
+UPLINE                 =       12
+CR                     =       13
+ULINEON                =       14
+ULINEOFF               =       15
+ESC_GRAPHICS           =       16
+ESC_RULER              =       17
+REV_ON                 =       18
+REV_OFF                =       19
+GOTOX                  =       20
+GOTOY                  =       21
+GOTOXY                 =       22
+NEWCARDSET             =       23
+BOLDON                 =       24
+ITALICON               =       25
+OUTLINEON              =       26
+PLAINTEXT              =       27
+
+;keyboard
+KEY_F1                 =       1
+KEY_F2                 =       2
+KEY_F3                 =       3
+KEY_F4                 =       4
+KEY_F5                 =       5
+KEY_F6                 =       6
+KEY_NOSCRL             =       7
+KEY_ENTER              =       11
+KEY_F7                 =       14
+KEY_F8                 =       15
+KEY_UP                 =       16
+KEY_DOWN               =       17
+KEY_HOME               =       18
+KEY_CLEAR              =       19
+KEY_LARROW             =       20
+KEY_UPARROR            =       21
+KEY_STOP               =       22
+KEY_RUN                =       23
+KEY_BPS                =       24
+KEY_HELP               =       25
+KEY_ALT                =       26
+KEY_ESC                =       27
+KEY_INSERT             =       28
+KEY_DELETE             =       29
+KEY_RIGHT              =       30
+KEY_INVALID            =       31
+KEY_LEFT               =       BACKSPACE
+
+;DialogBox
+;      icons
+OK                     =       1
+CANCEL                 =       2
+YES                    =       3
+NO                     =       4
+OPEN                   =       5
+DISK                   =       6
+;      commands
+DBTXTSTR               =       11
+DBVARSTR               =       12
+DBGETSTRING            =       13
+DBSYSOPV               =       14
+DBGRPHSTR              =       15
+DBGETFILES             =       16
+DBOPVEC                =       17
+DBUSRICON              =       18
+DB_USR_ROUT            =       19
+;      tabulation in standard window
+DBI_X_0                =       1
+DBI_X_1                =       9
+DBI_X_2                =       17
+DBI_Y_0                =       8
+DBI_Y_1                =       40
+DBI_Y_2                =       72
+;      standard window
+SET_DB_POS             =       0
+DEF_DB_POS             =       $80
+DEF_DB_TOP             =       32
+DEF_DB_BOT             =       127
+DEF_DB_LEFT            =       64
+DEF_DB_RIGHT           =       255
+;      text tabulation
+TXT_LN_1_Y             =       16
+TXT_LN_2_Y             =       32
+TXT_LN_3_Y             =       48
+TXT_LN_4_Y             =       64
+TXT_LN_5_Y             =       80
+TXT_LN_X               =       16
+;      ???
+SYSDBI_HEIGHT          =       16
+SYSDBI_WIDTH           =       6
+
+;GraphicsString - commands
+MOVEPENTO              =       1
+LINETO                 =       2
+RECTANGLETO            =       3
+NEWPATTERN             =       5
+ESC_PUTSTRING          =       6
+FRAME_RECTO            =       7
+PEN_X_DELTA            =       8
+PEN_Y_DELTA            =       9
+PEN_XY_DELTA           =       10
+
+
+;DoMenu - menutypes
+MENU_ACTION            =       $00
+DYN_SUB_MENU           =       $40
+SUB_MENU               =       $80
+HORIZONTAL             =       %00000000
+VERTICAL               =       %10000000
+
+;Errors
+ANY_FAULT              =       %11110000
+NO_BLOCKS              =       1
+INV_TRACK              =       2
+INSUFF_SPACE           =       3
+FULL_DIRECTORY         =       4
+FILE_NOT_FOUND         =       5
+BAD_BAM                =       6
+UNOPENED_VLIR          =       7
+INV_RECORD             =       8
+OUT_OF_RECORDS         =       9
+STRUCT_MISMAT          =       10
+BFR_OVERFLOW           =       11
+CANCEL_ERR             =       12
+DEV_NOT_FOUND          =       13
+INCOMPATIBLE           =       14
+HDR_NOT_THERE          =       $20
+NO_SYNC                =       $21
+DBLK_NOT_THERE         =       $22
+DAT_CHKSUM_ERR         =       $23
+WR_VER_ERR             =       $25
+WR_PR_ON               =       $26
+HDR_CHKSUM_ERR         =       $27
+DSK_ID_MISMAT          =       $29
+BYTE_DEC_ERR           =       $2e
+DOS_MISMATCH           =       $73
+
+;Offsets
+;      ???
+OFF_INDEX_PTR          =       1
+;      icons
+OFF_NM_ICNS            =       0
+OFF_IC_XMOUSE          =       1
+OFF_IC_YMOUSE          =       3
+OFF_PIC_ICON           =       0
+OFF_X_ICON_POS         =       2
+OFF_Y_ICON_POS         =       3
+OFF_WDTH_ICON          =       4
+OFF_HEIGHT_ICON        =       5
+OFF_SRV_RT_ICON        =       6
+OFF_NX_ICON            =       8
+;      menu
+OFF_MY_TOP             =       0
+OFF_MY_BOT             =       1
+OFF_MX_LEFT            =       2
+OFF_MX_RIGHT           =       4
+OFF_NUM_M_ITEMS        =       6
+OFF_1ST_M_ITEM         =       7
+;      dialog box
+OFF_DB_FORM            =       0
+OFF_DB_TOP             =       1
+OFF_DB_BOT             =       2
+OFF_DB_LEFT            =       3
+OFF_DB_RIGHT           =       5
+OFF_DB_1STCMD          =       7
+;      directory
+;              disk header
+OFF_TO_BAM             =       4
+OFF_DISK_NAME          =       144
+OFF_GS_DTYPE           =       189
+OFF_OP_TR_SC           =       171
+OFF_GS_ID              =       173
+;              dir entry
+FRST_FILE_ENTRY        =       2
+OFF_CFILE_TYPE         =       0
+OFF_DE_TR_SC           =       1
+OFF_FNAME              =       3
+OFF_GHDR_PTR           =       19
+OFF_GSTRUC_TYPE        =       21
+OFF_GFILE_TYPE         =       22
+OFF_YEAR               =       23
+OFF_SIZE               =       28
+OFF_NXT_FILE           =       32
+;              file header
+O_GHIC_WIDTH           =       2
+O_GHIC_HEIGHT          =       3
+O_GHIC_PIC             =       4
+O_GHCMDR_TYPE          =       68
+O_GHGEOS_TYPE          =       69
+O_GHSTR_TYPE           =       70
+O_GHST_ADDR            =       71
+O_GHEND_ADDR           =       73
+O_GHST_VEC             =       75
+O_GHFNAME              =       77
+O_128_FLAGS            =       96
+O_GH_AUTHOR            =       97
+O_GHP_DISK             =       97
+O_GHP_FNAME            =       117
+O_GHINFO_TXT           =       $a0
+
+;values for config - C128 mmu
+CIOIN                  =       $7E     ;60K RAM, 4K I/O space in
+CRAM64K                =       $7F     ;64K RAM
+CKRNLBASIOIN           =       $40     ;kernal, I/O and basic ROM's mapped into memory
+CKRNLIOIN              =       $4E     ;Kernal ROM and I/O space mapped in
+
+;values of faultData - pointer position vs. mouseTop/Bottom/Left/Right
+;      bit numbers
+OFFTOP_BIT             =       7
+OFFBOTTOM_BIT          =       6
+OFFLEFT_BIT            =       5
+OFFRIGHT_BIT           =       4
+OFFMENU_BIT            =       3
+;      masks
+SET_OFFTOP             =       %10000000
+SET_OFFBOTTOM          =       %01000000
+SET_OFFLEFT            =       %00100000
+SET_OFFRIGHT           =       %00010000
+SET_OFFMENU            =       %00001000
+
+;values of currentMode
+;      bit numbers
+UNDERLINE_BIT          =       7
+BOLD_BIT               =       6
+REVERSE_BIT            =       5
+ITALIC_BIT             =       4
+OUTLINE_BIT            =       3
+SUPERSCRIPT_BIT        =       2
+SUBSCRIPT_BIT          =       1
+;      masks
+SET_UNDERLINE          =       %10000000
+SET_BOLD               =       %01000000
+SET_REVERSE            =       %00100000
+SET_ITALIC             =       %00010000
+SET_OUTLINE            =       %00001000
+SET_SUPERSCRIPT        =       %00000100
+SET_SUBSCRIPT          =       %00000010
+SET_PLAINTEXT          =       %00000000
+
+;Process control variable
+;      bit numbers
+RUNABLE_BIT            =       7
+BLOCKED_BIT            =       6
+FROZEN_BIT             =       5
+NOTIMER_BIT            =       4
+;      masks
+SET_RUNABLE            =       %10000000
+SET_BLOCKED            =       %01000000
+SET_FROZEN             =       %00100000
+SET_NOTIMER            =       %00010000
+
+;mouseOn
+;      bit numbers
+MOUSEON_BIT            =       7
+MENUON_BIT             =       6
+ICONSON_BIT            =       5
+;      masks
+SET_MSE_ON             =       %10000000
+SET_MENUON             =       %01000000
+SET_ICONSON            =       %00100000
+
+;pressFlag
+;      bit numbers
+KEYPRESS_BIT           =       7
+INPUT_BIT              =       6
+MOUSE_BIT              =       5
+;      masks
+SET_KEYPRESS           =       %10000000
+SET_INPUTCHG           =       %01000000
+SET_MOUSE              =       %00100000
+
+;dispBufferOn
+ST_WRGS_FORE           =       $20
+ST_WR_BACK             =       $40
+ST_WR_FORE             =       $80
+
+;alarmSetFlag
+ALARMMASK              =       %00000100
+
+;PutDecimal
+    ;leading zeroes
+SET_NOSURPRESS         =       %00000000
+SET_SURPRESS           =       %01000000
+    ;justification
+SET_RIGHTJUST          =       %00000000
+SET_LEFTJUST           =       %10000000
+
+;icons, menus status flags
+ST_FLASH               =       $80
+ST_INVERT              =       $40
+ST_LD_AT_ADDR          =       $01
+ST_LD_DATA             =       $80
+ST_PR_DATA             =       $40
+ST_WR_PR               =       $40
+
+;???
+ADD1_W                 =       $2000
+DOUBLE_B               =       $80
+DOUBLE_W               =       $8000
+
+CLR_SAVE               =       %01000000
+CONSTRAINED            =       %01000000
+UN_CONSTRAINED         =       %00000000
+FG_SAVE                =       %10000000
+
+FUTURE1                =       7
+FUTURE2                =       8
+FUTURE3                =       9
+FUTURE4                =       10
+USELAST                =       127
+SHORTCUT               =       128
diff --git a/libsrc/geos/inc/diskdrv.inc b/libsrc/geos/inc/diskdrv.inc
new file mode 100644 (file)
index 0000000..ce106d7
--- /dev/null
@@ -0,0 +1,42 @@
+
+;GEOS Disk Driver JumpTab
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;pointers
+_InitForIO             =       $9000
+_DoneWithIO            =       $9002
+_ExitTurbo             =       $9004
+_PurgeTurbo            =       $9006
+_EnterTurbo            =       $9008
+_ChangeDiskDevice      =       $900a
+_NewDisk               =       $900c
+_ReadBlock             =       $900e
+_WriteBlock            =       $9010
+_VerWriteBlock         =       $9012
+_OpenDisk              =       $9014
+_GetBlock              =       $9016
+_PutBlock              =       $9018
+_GetDirHead            =       $901a
+_PutDirHead            =       $901c
+_GetFreeDirBlk         =       $901e
+_CalcBlksFree          =       $9020
+_FreeBlock             =       $9022
+_SetNextFree           =       $9024
+_FindBAMBit            =       $9026
+_NxtBlkAlloc           =       $9028
+_BlkAlloc              =       $902a
+_ChkDkGEOS             =       $902c
+_SetGEOSDisk           =       $902e
+
+;jump table
+Get1stDirEntry         =       $9030
+GetNxtDirEntry         =       $9033
+GetBorder              =       $9036
+AddDirBlock            =       $9039
+ReadBuff               =       $903c
+WriteBuff              =       $903f
+;??? = $9042
+;??? = $9045
+AllocateBlock          =       $9048
+ReadLink               =       $904b
diff --git a/libsrc/geos/inc/geosmac.ca65.inc b/libsrc/geos/inc/geosmac.ca65.inc
new file mode 100644 (file)
index 0000000..e233ef9
--- /dev/null
@@ -0,0 +1,263 @@
+
+;GEOS macros
+;reassembled for 6502TASM/MMS by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;28-6-99 - ca65 port
+;macro 'sub' renamed to 'ssub' due to 65816 mnemonics
+
+
+       .macro          LoadB dest, value
+       lda #value
+       sta dest
+       .endmacro
+       
+       .macro          LoadW dest, value
+       lda #>value
+       sta dest+1
+       .if (>value)<>(<value)
+           lda #<value
+       .endif
+       sta dest+0
+       .endmacro
+       
+       .macro          MoveB source, dest
+       lda source
+       sta dest
+       .endmacro
+       
+       .macro          MoveW source, dest
+       MoveB source+1, dest+1
+       MoveB source+0, dest+0
+       .endmacro
+       
+       .macro          add source
+       clc
+       adc source
+       .endmacro
+       
+       .macro          AddB source, dest
+       lda source
+       add dest
+       sta dest
+       .endmacro
+       
+       .macro          AddW source, dest
+       AddB source+0, dest+0
+       lda source+1
+       adc dest+1
+       sta dest+1
+       .endmacro
+       
+       .macro          AddVB value, dest
+       lda dest
+       clc
+       adc #value
+       sta dest
+       .endmacro
+       
+       .macro          AddVW value, dest
+.local Skip
+       clc
+       lda #<value
+       adc dest+0
+       sta dest+0
+       .if (>value)=0
+           bcc Skip
+           inc dest+1
+       .else
+           lda #>value
+           adc dest+1
+           sta dest+1
+       .endif
+Skip:
+       .endmacro
+       
+       .macro          ssub source
+       sec
+       sbc source
+       .endmacro
+       
+       .macro          SubB source, dest
+       lda dest
+       ssub source
+       sta dest
+       .endmacro
+       
+       .macro          SubW source, dest
+       SubB source+0, dest+0
+       lda dest+1
+       sbc source+1
+       sta dest+1
+       .endmacro
+       
+       .macro          SubVW value, dest
+       sec
+       lda dest+0
+       sbc #<value
+       sta dest+0
+       lda dest+1
+       sbc #>value
+       sta dest+1
+       .endmacro
+       
+       .macro          CmpB source, dest
+       lda source
+       cmp dest
+       .endmacro
+       
+       .macro          CmpBI source, immed
+       lda source
+       cmp #immed
+       .endmacro
+       
+       .macro          CmpW source, dest
+.local Skip    
+       CmpB source+1, dest+1
+       bne Skip
+       CmpB source+0, dest+0
+Skip:
+       .endmacro
+       
+       .macro          CmpWI source, immed
+.local Skip
+       CmpBI source+1, >immed
+       bne Skip
+       CmpBI source+0, <immed
+Skip:
+       .endmacro
+       
+       .macro          PushB source
+       lda source
+       pha
+       .endmacro
+       
+       .macro          PushW source
+       PushB source+1
+       PushB source+0
+       .endmacro
+       
+       .macro          PopB dest
+       pla
+       sta dest
+       .endmacro
+       
+       .macro          PopW dest
+       PopB dest+0
+       PopB dest+1
+       .endmacro
+       
+       .macro          bra addr
+       clv
+       bvc addr
+       .endmacro
+       
+       .macro          smb bitNumber, dest
+       pha
+       lda #(1 << bitNumber)
+       ora dest
+       sta dest
+       pla
+       .endmacro
+       
+       .macro          smbf bitNumber, dest
+       lda #(1 << bitNumber)
+       ora dest
+       sta dest
+       .endmacro
+       
+       .macro          rmb bitNumber, dest
+       pha
+       lda #(1 << bitNumber) ^ $ff 
+       ora dest
+       sta dest
+       pla
+       .endmacro
+       
+       .macro          rmbf bitNumber, dest
+       lda #(1 << bitNumber) ^ $ff
+       ora dest
+       sta dest
+       .endmacro
+       
+       .macro          bbs bitNumber, source, addr
+.local Skip
+       php
+       pha
+       lda source
+       and #(1 << bitNumber)
+       beq Skip
+       pla
+       plp
+       bra addr
+Skip:  pla
+       plp
+       .endmacro
+       
+       .macro          bbsf bitNumber, source, addr
+       .if     bitNumber=7
+               bit source
+               bmi addr
+       .else
+               .if bitNumber=6
+                   bit source
+                   bvs addr
+               .else
+                   lda source
+                   and #(1 << bitNumber)
+                   bne addr
+               .endif
+       .endif
+       .endmacro
+       
+       .macro          bbr bitNumber, source, addr
+.local Skip
+       php
+       pha
+       lda source
+       and #(1 << bitNumber)
+       bne Skip
+       pla
+       plp
+       bra addr
+Skip:  pla
+       plp
+       .endmacro
+       
+       .macro          bbrf bitNumber, source, addr
+       .if bitNumber=7
+           bit source
+           bpl addr
+       .else
+               .if bitNumber=6
+                   bit source
+                   bvc addr
+               .else
+                   lda source
+                   and #(1 << bitNumber)
+                   beq addr
+               .endif
+       .endif
+       .endmacro
+       
+;03.03.99 by Maciej Witkowiak
+
+       .macro          addv value
+       clc
+       adc #value
+       .endmacro
+       
+       .macro          subv value
+       sec
+       sbc #value
+       .endmacro
+       
+       .macro          bnex addr
+       txa
+       bne addr
+       .endmacro
+       
+       .macro          beqx addr
+       txa
+       beq addr
+       .endmacro
\ No newline at end of file
diff --git a/libsrc/geos/inc/geossym.inc b/libsrc/geos/inc/geossym.inc
new file mode 100644 (file)
index 0000000..0dc1e56
--- /dev/null
@@ -0,0 +1,320 @@
+
+;GEOS variable memory locations sorted by address
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+zpage          =       $0000
+;
+
+CPU_DDR        =       $00
+CPU_DATA       =       $01
+;
+r0             =       $02
+r0L            =       $02
+r0H            =       $03
+r1             =       $04
+r1L            =       $04
+r1H            =       $05
+r2             =       $06
+r2L            =       $06
+r2H            =       $07
+r3             =       $08
+r3L            =       $08
+r3H            =       $09
+r4             =       $0a
+r4L            =       $0a
+r4H            =       $0b
+r5             =       $0c
+r5L            =       $0c
+r5H            =       $0d
+r6             =       $0e
+r6L            =       $0e
+r6H            =       $0f
+r7             =       $10
+r7L            =       $10
+r7H            =       $11
+r8             =       $12
+r8L            =       $12
+r8H            =       $13
+r9             =       $14
+r9L            =       $14
+r9H            =       $15
+r10            =       $16
+r10L           =       $16
+r10H           =       $17
+r11            =       $18
+r11L           =       $18
+r11H           =       $19
+r12            =       $1a
+r12L           =       $1a
+r12H           =       $1b
+r13            =       $1c
+r13L           =       $1c
+r13H           =       $1d
+r14            =       $1e
+r14L           =       $1e
+r14H           =       $1f
+r15            =       $20
+r15L           =       $20
+r15H           =       $21
+;
+a0             =       $fb
+a0L            =       $fb
+a0H            =       $fc
+a1             =       $fd
+a1L            =       $fd
+a1H            =       $fe
+a2             =       $70
+a2L            =       $70
+a2H            =       $71
+a3             =       $72
+a3L            =       $72
+a3H            =       $73
+a4             =       $74
+a4L            =       $74
+a4H            =       $75
+a5             =       $76
+a5L            =       $76
+a5H            =       $77
+a6             =       $78
+a6L            =       $78
+a6H            =       $79
+a7             =       $7a
+a7L            =       $7a
+a7H            =       $7b
+a8             =       $7c
+a8L            =       $7c
+a8H            =       $7d
+a9             =       $7e
+a9L            =       $7e
+a9H            =       $7f
+
+;
+
+curPattern             =       $22
+string                 =       $24
+baselineOffset         =       $26
+curSetWidth            =       $27
+curHeight              =       $29
+curIndexTable          =       $2a
+cardDataPntr           =       $2c
+currentMode            =       $2e
+dispBufferOn           =       $2f
+mouseOn                =       $30
+RAM_64K                =       $30
+msePicPtr              =       $31
+windowTop              =       $33
+windowBottom           =       $34
+leftMargin             =       $35
+IO_IN                  =       $35
+KRNL_IO_IN             =       $36
+rightMargin            =       $37
+KRNL_BAS_IO_IN         =       $37
+pressFlag              =       $39
+mouseXPos              =       $3a
+mouseYPos              =       $3c
+returnAddress          =       $3d
+graphMode              =       $3f
+TURBO_DD00             =       $8e     ; from 1541 turbo
+TURBO_DD00_CPY         =       $8f     ; from 1541 turbo
+STATUS                 =       $90
+curDevice              =       $ba
+;
+errno                  =       $91     ; custom error return code
+;
+irqvec                 =       $0314
+bkvec                  =       $0316
+nmivec                 =       $0318
+;
+APP_RAM                =       $0400
+BACK_SCR_BASE          =       $6000
+PRINTBASE              =       $7900
+OS_VARS                =       $8000
+;
+diskBlkBuf             =       $8000
+fileHeader             =       $8100
+curDirHead             =       $8200
+fileTrScTab            =       $8300
+dirEntryBuf            =       $8400
+DrACurDkNm             =       $841e
+DrBCurDkNm             =       $8430
+dataFileName           =       $8442
+dataDiskName           =       $8453
+PrntFilename           =       $8465
+PrntDiskName           =       $8476
+curDrive               =       $8489
+diskOpenFlg            =       $848a
+isGEOS                 =       $848b
+interleave             =       $848c
+NUMDRV                 =       $848d
+driveType              =       $848e
+_driveType             =       driveType-8
+turboFlags             =       $8492
+_turboFlags            =       turboFlags-8
+curRecord              =       $8496
+usedRecords            =       $8497
+fileWritten            =       $8498
+fileSize               =       $8499
+appMain                =       $849b
+intTopVector           =       $849d
+intBotVector           =       $849f
+mouseVector            =       $84a1
+keyVector              =       $84a3
+inputVector            =       $84a5
+mouseFaultVec          =       $84a7
+otherPressVec          =       $84a9
+StringFaultVec         =       $84ab
+alarmTmtVector         =       $84ad
+BRKVector              =       $84af
+RecoverVector          =       $84b1
+selectionFlash         =       $84b3
+alphaFlag              =       $84b4
+iconSelFlg             =       $84b5
+faultData              =       $84b6
+menuNumber             =       $84b7
+mouseTop               =       $84b8
+mouseBottom            =       $84b9
+mouseLeft              =       $84ba
+mouseRight             =       $84bc
+stringX                =       $84be
+stringY                =       $84c0
+mousePicData           =       $84c1
+maxMouseSpeed          =       $8501
+minMouseSpeed          =       $8502
+mouseAccel             =       $8503
+keyData                =       $8504
+mouseData              =       $8505
+inputData              =       $8506
+mouseSpeed             =       $8507
+random                 =       $850a
+saveFontTab            =       $850c
+dblClickCount          =       $8515
+year                   =       $8516
+month                  =       $8517
+day                    =       $8518
+hour                   =       $8519
+minutes                =       $851a
+seconds                =       $851b
+alarmSetFlag           =       $851c
+sysDBData              =       $851d
+screencolors           =       $851e
+dlgBoxRamBuf           =       $851f   ; to $8697
+;
+;$8698 - $8877 - various system data (keyboard queue, VLIR t&s, DBox, Menu, timers)
+;
+savedmoby2             =       $88bb
+scr80polar             =       $88bc
+scr80colors            =       $88bd
+vdcClrMode             =       $88be
+driveData              =       $88bf
+ramExpSize             =       $88c3
+sysRAMFlg              =       $88c4
+firstBoot              =       $88c5
+curType                =       $88c6
+ramBase                =       $88c7
+inputDevName           =       $88cb
+memBase                =       $88cf   ;???
+DrCCurDkNm             =       $88dc
+DrDCurDkNm             =       $88ee
+dir2Head               =       $8900
+;
+SPRITE_PICS            =       $8a00
+spr0pic                =       $8a00
+spr1pic                =       $8a40
+spr2pic                =       $8a80
+spr3pic                =       $8ac0
+spr4pic                =       $8b00
+spr5pic                =       $8b40
+spr6pic                =       $8b80
+spr7pic                =       $8bc0
+COLOR_MATRIX           =       $8c00
+;
+obj0Pointer            =       $8ff8
+obj1Pointer            =       $8ff9
+obj2Pointer            =       $8ffa
+obj3Pointer            =       $8ffb
+obj4Pointer            =       $8ffc
+obj5Pointer            =       $8ffd
+obj6Pointer            =       $8ffe
+obj7Pointer            =       $8fff
+;
+DISK_BASE              =       $9000
+SCREEN_BASE            =       $a000
+OS_ROM                 =       $c000
+OS_JUMPTAB             =       $c100
+RAMC_BASE              =       $de00
+RAMC_WINDOW            =       $df00
+EXP_BASE               =       $df00
+MOUSE_BASE_128         =       $fd00
+MOUSE_JMP_128          =       $fd00
+END_MOUSE_128          =       $fe80
+MOUSE_BASE             =       $fe80
+MOUSE_JMP              =       $fe80
+config                 =       $ff00
+END_MOUSE              =       $fffa
+NMI_VECTOR             =       $fffa
+RESET_VECTOR           =       $fffc
+IRQ_VECTOR             =       $fffe
+;
+vicbase                =       $d000
+sidbase                =       $d400
+mmu                    =       $d500
+VDC                    =       $d600
+ctab                   =       $d800
+cia1base               =       $dc00
+cia2base               =       $dd00
+;
+mob0xpos               =       $d000
+mob0ypos               =       $d001
+mob1xpos               =       $d002
+mob1ypos               =       $d003
+mob2xpos               =       $d004
+mob2ypos               =       $d005
+mob3xpos               =       $d006
+mob3ypos               =       $d007
+mob4xpos               =       $d008
+mob4ypos               =       $d009
+mob5xpos               =       $d00a
+mob5ypos               =       $d00b
+mob6xpos               =       $d00c
+mob6ypos               =       $d00d
+mob7xpos               =       $d00e
+mob7ypos               =       $d00f
+msbxpos                =       $d010
+grcntrl1               =       $d011
+rasreg                 =       $d012
+lpxpos                 =       $d013
+lpypos                 =       $d014
+mobenble               =       $d015
+grcntrl2               =       $d016
+grmemptr               =       $d018
+grirq                  =       $d019
+grirqen                =       $d01a
+moby2                  =       $d017
+mobprior               =       $d01b
+mobmcm                 =       $d01c
+mobx2                  =       $d01d
+mobmobcol              =       $d01e
+mobbakcol              =       $d01f
+extclr                 =       $d020
+bakclr0                =       $d021
+bakclr1                =       $d022
+bakclr2                =       $d023
+bakclr3                =       $d024
+mcmclr0                =       $d025
+mcmclr1                =       $d026
+mob0clr                =       $d027
+mob1clr                =       $d028
+mob2clr                =       $d029
+mob3clr                =       $d02a
+mob4clr                =       $d02b
+mob5clr                =       $d02c
+mob6clr                =       $d02d
+mob7clr                =       $d02e
+keyreg                 =       $d02f
+clkreg                 =       $d030
+
+;
+vdcreg                 =       $d600
+vdcdata                =       $d601
+;
diff --git a/libsrc/geos/inc/geossym2.inc b/libsrc/geos/inc/geossym2.inc
new file mode 100644 (file)
index 0000000..0820c8e
--- /dev/null
@@ -0,0 +1,11 @@
+
+;GEOS various variables in OS_ROM area
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+bootName       =       $c006
+version        =       $c00f
+nationality    =       $c010
+sysFlgCopy     =       $c012
+c128Flag       =       $c013
+dateCopy        =       $c018
\ No newline at end of file
diff --git a/libsrc/geos/inc/inputdrv.inc b/libsrc/geos/inc/inputdrv.inc
new file mode 100644 (file)
index 0000000..cdb1dc4
--- /dev/null
@@ -0,0 +1,16 @@
+
+;GEOS Input Driver Jump Tab
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;for C64
+;MOUSE_JMP     =       $fe80
+SlowMouse      =       $fe83
+UpdateMouse    =       $fe86
+SetMouse       =       $fe89
+
+;for C128
+;MOUSE_JMP_128 =       $fd00
+SlowMouse_128  =       $fd03
+UpdateMouse_128        =       $fd06
+SetMouse_128   =       $fd09
diff --git a/libsrc/geos/inc/jumptab.inc b/libsrc/geos/inc/jumptab.inc
new file mode 100644 (file)
index 0000000..44bc614
--- /dev/null
@@ -0,0 +1,178 @@
+
+;GEOS System Jump Table
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;jump table
+InterruptMain          =       $c100
+InitProcesses          =       $c103
+RestartProcess         =       $c106
+EnableProcess          =       $c109
+BlockProcess           =       $c10c
+UnBlockProcess         =       $c10f
+FreezeProcess          =       $c112
+UnFreezeProcess        =       $c115
+HorizontalLine         =       $c118
+InvertLine             =       $c11b
+RecoverLine            =       $c11e
+VerticalLine           =       $c121
+Rectangle              =       $c124
+FrameRectangle         =       $c127
+InvertRectangle        =       $c12a
+RecoverRectangle       =       $c12d
+DrawLine               =       $c130
+DrawPoint              =       $c133
+GraphicsString         =       $c136
+SetPattern             =       $c139
+GetScanLine            =       $c13c
+TestPoint              =       $c13f
+BitmapUp               =       $c142
+PutChar                =       $c145
+PutString              =       $c148
+UseSystemFont          =       $c14b
+StartMouseMode         =       $c14e
+DoMenu                 =       $c151
+RecoverMenu            =       $c154
+RecoverAllMenus        =       $c157
+DoIcons                =       $c15a
+DShiftLeft             =       $c15d
+BBMult                 =       $c160
+BMult                  =       $c163
+DMult                  =       $c166
+Ddiv                   =       $c169
+DSdiv                  =       $c16c
+Dabs                   =       $c16f
+Dnegate                =       $c172
+Ddec                   =       $c175
+ClearRam               =       $c178
+FillRam                =       $c17b
+MoveData               =       $c17e
+InitRam                =       $c181
+PutDecimal             =       $c184
+GetRandom              =       $c187
+MouseUp                =       $c18a
+MouseOff               =       $c18d
+DoPreviousMenu         =       $c190
+ReDoMenu               =       $c193
+GetSerialNumber        =       $c196
+Sleep                  =       $c199
+ClearMouseMode         =       $c19c
+i_Rectangle            =       $c19f
+i_FrameRectangle       =       $c1a2
+i_RecoverRectangle     =       $c1a5
+i_GraphicsString       =       $c1a8
+i_BitmapUp             =       $c1ab
+i_PutString            =       $c1ae
+GetRealSize            =       $c1b1
+i_FillRam              =       $c1b4
+i_MoveData             =       $c1b7
+GetString              =       $c1ba
+GotoFirstMenu          =       $c1bd
+InitTextPrompt         =       $c1c0
+MainLoop               =       $c1c3
+DrawSprite             =       $c1c6
+GetCharWidth           =       $c1c9
+LoadCharSet            =       $c1cc
+PosSprite              =       $c1cf
+EnablSprite            =       $c1d2
+DisablSprite           =       $c1d5
+CallRoutine            =       $c1d8
+CalcBlksFree           =       $c1db
+ChkDkGEOS              =       $c1de
+NewDisk                =       $c1e1
+GetBlock               =       $c1e4
+PutBlock               =       $c1e7
+SetGEOSDisk            =       $c1ea
+SaveFile               =       $c1ed
+SetGDirEntry           =       $c1f0
+BldGDirEntry           =       $c1f3
+GetFreeDirBlk          =       $c1f6
+WriteFile              =       $c1f9
+BlkAlloc               =       $c1fc
+ReadFile               =       $c1ff
+SmallPutChar           =       $c202
+FollowChain            =       $c205
+GetFile                =       $c208
+FindFile               =       $c20b
+CRC                    =       $c20e
+LdFile                 =       $c211
+EnterTurbo             =       $c214
+LdDeskAcc              =       $c217
+ReadBlock              =       $c21a
+LdApplic               =       $c21d
+WriteBlock             =       $c220
+VerWriteBlock          =       $c223
+FreeFile               =       $c226
+GetFHdrInfo            =       $c229
+EnterDeskTop           =       $c22c
+StartAppl              =       $c22f
+ExitTurbo              =       $c232
+PurgeTurbo             =       $c235
+DeleteFile             =       $c238
+FindFTypes             =       $c23b
+RstrAppl               =       $c23e
+ToBASIC                =       $c241
+FastDelFile            =       $c244
+GetDirHead             =       $c247
+PutDirHead             =       $c24a
+NxtBlkAlloc            =       $c24d
+ImprintRectangle       =       $c250
+i_ImprintRectangle     =       $c253
+DoDlgBox               =       $c256
+RenameFile             =       $c259
+InitForIO              =       $c25c
+DoneWithIO             =       $c25f
+DShiftRight            =       $c262
+CopyString             =       $c265
+CopyFString            =       $c268
+CmpString              =       $c26b
+CmpFString             =       $c26e
+FirstInit              =       $c271
+OpenRecordFile         =       $c274
+CloseRecordFile        =       $c277
+NextRecord             =       $c27a
+PreviousRecord         =       $c27d
+PointRecord            =       $c280
+DeleteRecord           =       $c283
+InsertRecord           =       $c286
+AppendRecord           =       $c289
+ReadRecord             =       $c28c
+WriteRecord            =       $c28f
+SetNextFree            =       $c292
+UpdateRecordFile       =       $c295
+GetPtrCurDkNm          =       $c298
+PromptOn               =       $c29b
+PromptOff              =       $c29e
+OpenDisk               =       $c2a1
+DoInlineReturn         =       $c2a4
+GetNextChar            =       $c2a7
+BitmapClip             =       $c2aa
+FindBAMBit             =       $c2ad
+SetDevice              =       $c2b0
+IsMseInRegion          =       $c2b3
+ReadByte               =       $c2b6
+FreeBlock              =       $c2b9
+ChangeDiskDevice       =       $c2bc
+RstrFrmDialogue        =       $c2bf
+Panic                  =       $c2c2
+BitOtherClip           =       $c2c5
+StashRAM               =       $c2c8
+FetchRAM               =       $c2cb
+SwapRAM                =       $c2ce
+VerifyRAM              =       $c2d1
+DoRAMOp                =       $c2d4
+
+;only in GEOS 128
+TempHideMouse          =       $c2d7
+SetMousePicture        =       $c2da
+SetNewMode             =       $c2dd
+NormalizeX             =       $c2e0
+MoveBData              =       $c2e3
+SwapBData              =       $c2e6
+VerifyBData            =       $c2e9
+DoBOp                  =       $c2ec
+AccessCache            =       $c2ef
+HideOnlyMouse          =       $c2f2
+SetColorMode           =       $c2f5
+ColorCard              =       $c2f8
+ColorRectangle         =       $c2fb
diff --git a/libsrc/geos/inc/printdrv.inc b/libsrc/geos/inc/printdrv.inc
new file mode 100644 (file)
index 0000000..55dbc4e
--- /dev/null
@@ -0,0 +1,14 @@
+
+;GEOS Printer Driver Jump Table
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;jump table
+InitForPrint           =       $7900
+StartPrint             =       $7903
+PrintBuffer            =       $7906
+StopPrint              =       $7909
+GetDimensions          =       $790c
+PrinsASCII             =       $790f
+StartASCII             =       $7912
+SetNLQ                 =       $7915
diff --git a/libsrc/geos/memory/Makefile b/libsrc/geos/memory/Makefile
new file mode 100644 (file)
index 0000000..ae00d71
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = crc.o doublepop.o reuregs.o clearram.o fillram.o initram.o movedata.o\
+         stashram.o fetchram.o swapram.o verifyram.o\
+         doublespop.o copystring.o cmpstring.o copyfstring.o cmpfstring.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/memory/clearram.s b/libsrc/geos/memory/clearram.s
new file mode 100644 (file)
index 0000000..0c3ec35
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ClearRam         (char *dest, int length);
+
+           .import DoublePop
+           .export _ClearRam
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_ClearRam:
+           jsr DoublePop
+           jmp ClearRam
diff --git a/libsrc/geos/memory/cmpfstring.s b/libsrc/geos/memory/cmpfstring.s
new file mode 100644 (file)
index 0000000..5af3805
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CmpFString (char length, char *dest, char* source);
+
+           .import DoubleSPop
+           .import popa
+           .export _CmpFString
+
+           .include "../inc/jumptab.inc"
+
+_CmpFString:
+           jsr DoubleSPop
+           jsr popa
+           jmp CmpFString
diff --git a/libsrc/geos/memory/cmpstring.s b/libsrc/geos/memory/cmpstring.s
new file mode 100644 (file)
index 0000000..8ebe70a
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; char CmpString (char *dest, char* source);
+
+           .import DoubleSPop
+           .export _CmpString
+
+           .include "../inc/jumptab.inc"
+
+_CmpString:
+           jsr DoubleSPop
+           jmp CmpString
diff --git a/libsrc/geos/memory/copyfstring.s b/libsrc/geos/memory/copyfstring.s
new file mode 100644 (file)
index 0000000..50789f5
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CopyFString (char length, char *dest, char* source);
+
+           .import DoubleSPop
+           .import popa
+           .export _CopyFString
+
+           .include "../inc/jumptab.inc"
+
+_CopyFString:
+           jsr DoubleSPop
+           jsr popa
+           jmp CopyFString
diff --git a/libsrc/geos/memory/copystring.s b/libsrc/geos/memory/copystring.s
new file mode 100644 (file)
index 0000000..e990607
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CopyString (char *dest, char* source);
+
+           .import DoubleSPop
+           .export _CopyString
+
+           .include "../inc/jumptab.inc"
+
+_CopyString:
+           jsr DoubleSPop
+           jmp CopyString
diff --git a/libsrc/geos/memory/crc.s b/libsrc/geos/memory/crc.s
new file mode 100644 (file)
index 0000000..a46a32a
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; int CRC         (char *memory, int length);
+
+           .import DoublePop
+           .export _CRC
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_CRC:
+           jsr DoublePop
+           jsr CRC
+           lda r2L
+           ldx r2H
+           rts
+           
\ No newline at end of file
diff --git a/libsrc/geos/memory/doublepop.s b/libsrc/geos/memory/doublepop.s
new file mode 100644 (file)
index 0000000..f426b16
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 31.12.99
+
+           .import popax
+           .export DoublePop
+
+           .include "../inc/geossym.inc"
+
+DoublePop:
+           sta r0L
+           stx r0H
+           jsr popax
+           sta r1L
+           stx r1H
+           rts
diff --git a/libsrc/geos/memory/doublespop.s b/libsrc/geos/memory/doublespop.s
new file mode 100644 (file)
index 0000000..4fd6849
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+           .import popax
+           .importzp ptr3, ptr4
+           .export DoubleSPop
+
+           .include "../inc/geossym.inc"
+
+DoubleSPop:
+           sta ptr4
+           stx ptr4+1
+           jsr popax
+           sta ptr3
+           stx ptr3+1
+           lda #ptr4
+           ldx #ptr3
+           rts
diff --git a/libsrc/geos/memory/fetchram.s b/libsrc/geos/memory/fetchram.s
new file mode 100644 (file)
index 0000000..669284e
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void FetchRAM (char REUBank, int length, char *from, char *dest);
+
+           .import REURegs
+           .export _FetchRAM
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_FetchRAM:
+           jsr REURegs
+           jmp FetchRAM
diff --git a/libsrc/geos/memory/fillram.s b/libsrc/geos/memory/fillram.s
new file mode 100644 (file)
index 0000000..c08b05e
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void FillRam         (char what, char *dest, int length);
+
+           .import DoublePop, popa
+           .export _FillRam
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_FillRam:
+           jsr DoublePop
+           jsr popa
+           sta r2L
+           jmp FillRam
diff --git a/libsrc/geos/memory/initram.s b/libsrc/geos/memory/initram.s
new file mode 100644 (file)
index 0000000..8475c9d
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void InitRam         (struct inittab*);
+
+           .export _InitRam
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_InitRam:
+           sta r0L
+           stx r0H
+           jmp InitRam
diff --git a/libsrc/geos/memory/movedata.s b/libsrc/geos/memory/movedata.s
new file mode 100644 (file)
index 0000000..7902259
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MoveData         (char* source, char *dest, int length);
+
+           .import popax
+           .export _MoveData
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_MoveData:
+           sta r2L
+           stx r2H
+           jsr popax
+           sta r1L
+           stx r1H
+           jsr popax
+           sta r0L
+           stx r0H
+           jmp MoveData
diff --git a/libsrc/geos/memory/reuregs.s b/libsrc/geos/memory/reuregs.s
new file mode 100644 (file)
index 0000000..cfc2c44
--- /dev/null
@@ -0,0 +1,21 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 31.12.99
+
+           .import popax, popa
+           .import DoublePop
+           .export REURegs
+
+           .include "../inc/geossym.inc"
+
+REURegs:
+           jsr DoublePop
+           jsr popax
+           sta r2L
+           stx r2H
+           jsr popa
+           sta r3L
+           rts
+
diff --git a/libsrc/geos/memory/stashram.s b/libsrc/geos/memory/stashram.s
new file mode 100644 (file)
index 0000000..8b1ff6a
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void StashRAM (char REUBank, int length, char *dest, char *from);
+
+           .import REURegs
+           .export _StashRAM
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_StashRAM:
+           jsr REURegs
+           jmp StashRAM
diff --git a/libsrc/geos/memory/swapram.s b/libsrc/geos/memory/swapram.s
new file mode 100644 (file)
index 0000000..a5fceab
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void SwapRAM (char REUBank, int length, char *reuaddy, char *cpuaddy);
+;      note that in all REU procs last two pointers are identified like here
+
+           .import REURegs
+           .export _SwapRAM
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_SwapRAM:
+           jsr REURegs
+           jmp SwapRAM
diff --git a/libsrc/geos/memory/verifyram.s b/libsrc/geos/memory/verifyram.s
new file mode 100644 (file)
index 0000000..0ff3623
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char VerifyRAM (char REUBank, int length, char *reuaddy, char *cpuaddy);
+
+           .import REURegs
+           .export _VerifyRAM
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_VerifyRAM:
+           jsr REURegs
+           jsr VerifyRAM
+           txa
+           rts
diff --git a/libsrc/geos/menuicon/Makefile b/libsrc/geos/menuicon/Makefile
new file mode 100644 (file)
index 0000000..bf3a9bd
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = domenu.o dopreviousmenu.o redomenu.o recovermenu.o recoverallmenus.o\
+          gotofirstmenu.o doicons.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/doicons.s b/libsrc/geos/menuicon/doicons.s
new file mode 100644 (file)
index 0000000..9c5d430
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoIcons         (struct icontab *myicons);
+
+           .export _DoIcons
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_DoIcons:
+           sta r0L
+           stx r0H
+           jmp DoIcons
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/domenu.s b/libsrc/geos/menuicon/domenu.s
new file mode 100644 (file)
index 0000000..22408e7
--- /dev/null
@@ -0,0 +1,18 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoMenu         (struct menu *mymenu);
+
+           .export _DoMenu
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_DoMenu:
+           sta r0L
+           stx r0H
+           lda #0
+           jmp DoMenu
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/dopreviousmenu.s b/libsrc/geos/menuicon/dopreviousmenu.s
new file mode 100644 (file)
index 0000000..eeda979
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoPreviousMenu (void);
+
+           .export _DoPreviousMenu
+
+           .include "../inc/jumptab.inc"
+
+_DoPreviousMenu = DoPreviousMenu
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/gotofirstmenu.s b/libsrc/geos/menuicon/gotofirstmenu.s
new file mode 100644 (file)
index 0000000..5ce17de
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void GotoFirstMenu (void);
+
+           .export _GotoFirstMenu
+
+           .include "../inc/jumptab.inc"
+
+_GotoFirstMenu = GotoFirstMenu
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/recoverallmenus.s b/libsrc/geos/menuicon/recoverallmenus.s
new file mode 100644 (file)
index 0000000..1ae81a5
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void RecoverAllMenus (void);
+
+           .export _RecoverAllMenus
+
+           .include "../inc/jumptab.inc"
+
+_RecoverAllMenus = RecoverAllMenus
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/recovermenu.s b/libsrc/geos/menuicon/recovermenu.s
new file mode 100644 (file)
index 0000000..02975dc
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void RecoverMenu (void);
+
+           .export _RecoverMenu
+
+           .include "../inc/jumptab.inc"
+
+_RecoverMenu = RecoverMenu
\ No newline at end of file
diff --git a/libsrc/geos/menuicon/redomenu.s b/libsrc/geos/menuicon/redomenu.s
new file mode 100644 (file)
index 0000000..63c1a6d
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ReDoMenu (void);
+
+           .export _ReDoMenu
+
+           .include "../inc/jumptab.inc"
+
+_ReDoMenu = ReDoMenu
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/Makefile b/libsrc/geos/mousesprite/Makefile
new file mode 100644 (file)
index 0000000..30c48c7
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = startmousemode.o clearmousemode.o mouseup.o mouseoff.o\
+         drawsprite.o possprite.o enablsprite.o disablsprite.o\
+         ismseinregion.o inittextprompt.o promptoff.o prompton.o\
+         getnextchar.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/clearmousemode.s b/libsrc/geos/mousesprite/clearmousemode.s
new file mode 100644 (file)
index 0000000..2b6c2a8
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ClearMouseMode (void);
+
+           .export _ClearMouseMode
+
+           .include "../inc/jumptab.inc"
+
+_ClearMouseMode = ClearMouseMode
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/disablsprite.s b/libsrc/geos/mousesprite/disablsprite.s
new file mode 100644 (file)
index 0000000..97d1cdc
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DisablSprite (char spritenum);
+
+           .export _DisablSprite
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_DisablSprite:
+           sta r3L
+           jmp DisablSprite
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/drawsprite.s b/libsrc/geos/mousesprite/drawsprite.s
new file mode 100644 (file)
index 0000000..0bab133
--- /dev/null
@@ -0,0 +1,23 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void DrawSprite (char spritenum, char *tab63 );
+;
+
+           .import popa
+           .export _DrawSprite
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_DrawSprite:
+
+           sta r4L
+           stx r4H
+           jsr popa
+           sta r3L
+           jmp DrawSprite
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/enablsprite.s b/libsrc/geos/mousesprite/enablsprite.s
new file mode 100644 (file)
index 0000000..ffe3435
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void EnablSprite (char spritenum);
+
+           .export _EnablSprite
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_EnablSprite:
+           sta r3L
+           jmp EnablSprite
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/getnextchar.s b/libsrc/geos/mousesprite/getnextchar.s
new file mode 100644 (file)
index 0000000..85cd9e0
--- /dev/null
@@ -0,0 +1,14 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetNextChar (void);
+;      note that if it returns 0 (FALSE) then no characters are available
+
+           .export _GetNextChar
+
+           .include "../inc/jumptab.inc"
+
+_GetNextChar = GetNextChar
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/inittextprompt.s b/libsrc/geos/mousesprite/inittextprompt.s
new file mode 100644 (file)
index 0000000..d9ee5e1
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void InitTextPrompt (char height);
+
+           .export _InitTextPrompt
+
+           .include "../inc/jumptab.inc"
+
+_InitTextPrompt        = InitTextPrompt
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/ismseinregion.s b/libsrc/geos/mousesprite/ismseinregion.s
new file mode 100644 (file)
index 0000000..4d35fa8
--- /dev/null
@@ -0,0 +1,17 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char IsMseInRegion (struct window *mywindow);
+
+           .import RectRegs
+
+           .export _IsMseInRegion
+           
+           .include "../inc/jumptab.inc"
+
+_IsMseInRegion:
+           jsr RectRegs
+           jmp IsMseInRegion
diff --git a/libsrc/geos/mousesprite/mouseoff.s b/libsrc/geos/mousesprite/mouseoff.s
new file mode 100644 (file)
index 0000000..677eb43
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MouseOff (void);
+
+           .export _MouseOff
+
+           .include "../inc/jumptab.inc"
+
+_MouseOff = MouseOff
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/mouseup.s b/libsrc/geos/mousesprite/mouseup.s
new file mode 100644 (file)
index 0000000..318f3f6
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MouseUp (void);
+
+           .export _MouseUp
+
+           .include "../inc/jumptab.inc"
+
+_MouseUp = MouseUp
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/possprite.s b/libsrc/geos/mousesprite/possprite.s
new file mode 100644 (file)
index 0000000..9f440cd
--- /dev/null
@@ -0,0 +1,32 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void PosSprite (char spritenum, struct pixel *position );
+;
+
+           .importzp ptr4
+           .import popa
+           .export _PosSprite
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_PosSprite:
+           sta ptr4
+           stx ptr4+1
+           ldy #0
+           lda (ptr4),y
+           sta r4L
+           iny
+           lda (ptr4),y
+           sta r4H
+           iny
+           lda (ptr4),y
+           sta r5L
+           jsr popa
+           sta r3L
+           jmp PosSprite
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/promptoff.s b/libsrc/geos/mousesprite/promptoff.s
new file mode 100644 (file)
index 0000000..4551fdb
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PromptOff (void);
+
+           .export _PromptOff
+
+           .include "../inc/jumptab.inc"
+
+_PromptOff = PromptOff
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/prompton.s b/libsrc/geos/mousesprite/prompton.s
new file mode 100644 (file)
index 0000000..2af5f2e
--- /dev/null
@@ -0,0 +1,24 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PromptOn (struct pixel *);
+
+           .importzp ptr4
+           .export _PromptOn
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_PromptOn:
+           sta ptr4
+           stx ptr4+1
+           ldy #0
+promptLp:   lda (ptr4),y
+           sta stringX,y
+           iny
+           cpy #3
+           bne promptLp
+           jmp PromptOn
\ No newline at end of file
diff --git a/libsrc/geos/mousesprite/startmousemode.s b/libsrc/geos/mousesprite/startmousemode.s
new file mode 100644 (file)
index 0000000..3215085
--- /dev/null
@@ -0,0 +1,15 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void StartMouseMode (void);
+
+           .export _StartMouseMode
+
+           .include "../inc/jumptab.inc"
+
+_StartMouseMode:
+           clc
+           jmp StartMouseMode
\ No newline at end of file
diff --git a/libsrc/geos/process/Makefile b/libsrc/geos/process/Makefile
new file mode 100644 (file)
index 0000000..91ad9d2
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = processinitrestartenable.o processblock.o processfreeze.o sleep.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/process/processblock.s b/libsrc/geos/process/processblock.s
new file mode 100644 (file)
index 0000000..87720e5
--- /dev/null
@@ -0,0 +1,25 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void InitProcesses   (char number, struct process* proctab);
+; (rest)
+; void BlockProcess    (char number);
+; void UnBlockProcess  (char number);
+;
+
+           .export _BlockProcess
+           .export _UnBlockProcess
+
+           .include "../inc/jumptab.inc"
+           
+_BlockProcess:
+           tax
+           jmp BlockProcess
+           
+_UnBlockProcess:
+           tax
+           jmp UnBlockProcess
diff --git a/libsrc/geos/process/processfreeze.s b/libsrc/geos/process/processfreeze.s
new file mode 100644 (file)
index 0000000..0c2b311
--- /dev/null
@@ -0,0 +1,23 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void FreezeProcess   (char number);
+; void UnFreezeProcess (char number);
+;
+
+           .export _FreezeProcess
+           .export _UnFreezeProcess
+
+           .include "../inc/jumptab.inc"
+           
+_FreezeProcess:
+           tax
+           jmp FreezeProcess
+           
+_UnFreezeProcess:
+           tax
+           jmp UnFreezeProcess
diff --git a/libsrc/geos/process/processinitrestartenable.s b/libsrc/geos/process/processinitrestartenable.s
new file mode 100644 (file)
index 0000000..a9e4a6c
--- /dev/null
@@ -0,0 +1,34 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void InitProcesses   (char number, struct process* proctab);
+; void RestartProcess  (char number);
+; void EnableProcess   (char number);
+;
+
+           .import popa
+           .export _InitProcesses
+           .export _RestartProcess
+           .export _EnableProcess
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_InitProcesses:
+           
+           sta r0L
+           stx r0H
+           jsr popa
+           jmp InitProcesses
+           
+_RestartProcess:
+           tax
+           jmp RestartProcess
+           
+_EnableProcess:
+           tax
+           jmp EnableProcess
diff --git a/libsrc/geos/process/sleep.s b/libsrc/geos/process/sleep.s
new file mode 100644 (file)
index 0000000..7edac2f
--- /dev/null
@@ -0,0 +1,20 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void Sleep (int jiffies);
+;
+
+           .export _Sleep
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_Sleep:
+           
+           sta r0L
+           stx r0H
+           jmp Sleep
\ No newline at end of file
diff --git a/libsrc/geos/system/Makefile b/libsrc/geos/system/Makefile
new file mode 100644 (file)
index 0000000..8d0b810
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = callroutine.o enterdesktop.o firstinit.o getrandom.o getserialnumber.o\
+         initdoneio.o mainloop.o panic.o tobasic.o setdevice.o
+
+all: $(S_OBJS)
+
+clean:
+       @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
diff --git a/libsrc/geos/system/callroutine.s b/libsrc/geos/system/callroutine.s
new file mode 100644 (file)
index 0000000..97f0c0d
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void CallRoutine (myRoutine);
+
+           .export _CallRoutine
+
+           .include "../inc/jumptab.inc"
+
+_CallRoutine = CallRoutine
\ No newline at end of file
diff --git a/libsrc/geos/system/enterdesktop.s b/libsrc/geos/system/enterdesktop.s
new file mode 100644 (file)
index 0000000..a647e93
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void EnterDeskTop (void);
+
+           .export _EnterDeskTop
+
+           .include "../inc/jumptab.inc"
+
+_EnterDeskTop = EnterDeskTop
\ No newline at end of file
diff --git a/libsrc/geos/system/firstinit.s b/libsrc/geos/system/firstinit.s
new file mode 100644 (file)
index 0000000..608aa14
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void FirstInit (void);
+
+           .export _FirstInit
+
+           .include "../inc/jumptab.inc"
+
+_FirstInit = FirstInit
\ No newline at end of file
diff --git a/libsrc/geos/system/getrandom.s b/libsrc/geos/system/getrandom.s
new file mode 100644 (file)
index 0000000..c9245fd
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; int GetRandom (void);
+
+           .export _GetRandom
+
+           .include "../inc/jumptab.inc"
+
+_GetRandom = GetRandom
diff --git a/libsrc/geos/system/getserialnumber.s b/libsrc/geos/system/getserialnumber.s
new file mode 100644 (file)
index 0000000..2a74887
--- /dev/null
@@ -0,0 +1,19 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; int GetSerialNumber (void);
+
+           .export _GetSerialNumber
+
+           .include "../inc/jumptab.inc"
+           .include "../inc/geossym.inc"
+
+_GetSerialNumber:
+
+           jsr GetSerialNumber
+           lda r0L
+           ldx r0H
+           rts
diff --git a/libsrc/geos/system/initdoneio.s b/libsrc/geos/system/initdoneio.s
new file mode 100644 (file)
index 0000000..c3280c9
--- /dev/null
@@ -0,0 +1,16 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void InitForIO  (void);
+; void DoneWithIO (void);
+
+           .export _InitForIO, _DoneWithIO
+
+           .include "../inc/jumptab.inc"
+
+_InitForIO = InitForIO
+           
+_DoneWithIO = DoneWithIO
\ No newline at end of file
diff --git a/libsrc/geos/system/mainloop.s b/libsrc/geos/system/mainloop.s
new file mode 100644 (file)
index 0000000..f90a9f9
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MainLoop (void);
+
+           .export _MainLoop
+
+           .include "../inc/jumptab.inc"
+
+_MainLoop = MainLoop
\ No newline at end of file
diff --git a/libsrc/geos/system/panic.s b/libsrc/geos/system/panic.s
new file mode 100644 (file)
index 0000000..a489edd
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void Panic (void);
+
+           .export _Panic
+
+           .include "../inc/jumptab.inc"
+
+_Panic = Panic
\ No newline at end of file
diff --git a/libsrc/geos/system/setdevice.s b/libsrc/geos/system/setdevice.s
new file mode 100644 (file)
index 0000000..819a0be
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void SetDevice (char newDeviceNumber);
+
+           .export _SetDevice
+
+           .include "../inc/jumptab.inc"
+       
+_SetDevice     = SetDevice
diff --git a/libsrc/geos/system/tobasic.s b/libsrc/geos/system/tobasic.s
new file mode 100644 (file)
index 0000000..bc1d15e
--- /dev/null
@@ -0,0 +1,13 @@
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ToBASIC (void);
+
+           .export _ToBASIC
+
+           .include "../inc/jumptab.inc"
+
+_ToBASIC = ToBASIC
\ No newline at end of file
diff --git a/libsrc/pet/Makefile b/libsrc/pet/Makefile
new file mode 100644 (file)
index 0000000..8f393fe
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o break.o color.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/pet/break.s b/libsrc/pet/break.s
new file mode 100644 (file)
index 0000000..7fbf2b3
--- /dev/null
@@ -0,0 +1,109 @@
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+               .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+
+       .include        "pet.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     BRKVec
+       lda     #>brk_handler
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       pla
+       sta     _brk_y
+       pla
+       sta     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
+                             
diff --git a/libsrc/pet/cgetc.s b/libsrc/pet/cgetc.s
new file mode 100644 (file)
index 0000000..4113e13
--- /dev/null
@@ -0,0 +1,68 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+       .export         _cgetc
+       .import         cursor
+
+       .include        "pet.inc"
+
+_cgetc:        lda     KEY_COUNT       ; Get number of characters
+               bne     L3              ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+       lda     CURS_FLAG
+       pha
+       lda     cursor
+       jsr     setcursor
+L1:    lda     KEY_COUNT
+       beq     L1
+       ldx     #0
+       pla
+       bne     L2
+       inx
+L2:    txa
+       jsr     setcursor
+
+; Fetch the character from the keyboard buffer
+
+L3:            sei
+       ldy     KEY_BUF
+       ldx     #$00
+L4:    lda     KEY_BUF+1,x
+       sta     KEY_BUF,x
+       inx
+       cpx     KEY_COUNT
+       bne     L4
+       dec     KEY_COUNT
+       cli
+       ldx     #$00            ; Clear high byte
+       tya
+       rts
+
+; Switch the cursor on or off
+
+setcursor:
+               tax                     ; On or off?
+       bne     seton           ; Go set it on
+               lda     CURS_FLAG       ; Is the cursor currently off?
+       bne     crs9            ; Jump if yes
+       lda     #1
+       sta     CURS_FLAG       ; Mark it as off
+       lda     CURS_STATE      ; Cursor currently displayed?
+       beq     crs8            ; Jump if no
+       ldy     CURS_X          ; Get the character column
+               lda     (SCREEN_PTR),y  ; Get character
+       eor     #$80
+       sta     (SCREEN_PTR),y  ; Store character back
+crs8:  lda     #0
+       sta     CURS_STATE      ; Cursor not displayed
+crs9:  rts
+
+seton:         lda     #0
+       sta     CURS_FLAG
+       rts
+
diff --git a/libsrc/pet/clrscr.s b/libsrc/pet/clrscr.s
new file mode 100644 (file)
index 0000000..2cabcc0
--- /dev/null
@@ -0,0 +1,50 @@
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+       .import         plot
+               .importzp       ptr1
+       .import         xsize
+
+       .include        "pet.inc"
+
+_clrscr:
+
+; Set the screen base address
+
+       lda     #$00
+       sta     ptr1
+       lda     #$80
+       sta     ptr1+1
+
+; Determine, how many pages to fill
+
+       ldx     #4
+       lda     xsize
+       cmp     #40
+               beq     L1
+       ldx     #8
+
+; Clear the screen
+
+L1:            lda     #$20            ; Screen code for blank
+       ldy     #$00
+L2:    sta     (ptr1),y
+       iny
+       bne     L2
+       inc     ptr1+1
+       dex
+       bne     L2
+
+; Set the cursor to 0/0
+
+       lda     #0
+       sta     CURS_X
+       sta     CURS_Y
+       jmp     plot
+
+       rts
+
diff --git a/libsrc/pet/color.s b/libsrc/pet/color.s
new file mode 100644 (file)
index 0000000..6fbca56
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+       .export         _textcolor, _bgcolor, _bordercolor
+       .import         return0, return1
+
+_textcolor     = return1
+
+_bgcolor       = return0
+
+_bordercolor   = return0
+
+
diff --git a/libsrc/pet/conio.s b/libsrc/pet/conio.s
new file mode 100644 (file)
index 0000000..19e7533
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio
+       .import         xsize, ysize
+       .exportzp       CURS_X, CURS_Y
+
+       .include        "pet.inc"
+
+.code
+
+initconio:
+               ldx     SCR_LINELEN
+       inx                     ; Variable is one less
+               stx     xsize
+       lda     #25
+       sta     ysize
+       rts
+
+
+
diff --git a/libsrc/pet/cputc.s b/libsrc/pet/cputc.s
new file mode 100644 (file)
index 0000000..3c8b21d
--- /dev/null
@@ -0,0 +1,120 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc, cputdirect, putchar
+       .export         advance, newline, plot
+       .import         popa, _gotoxy
+       .import         xsize, revers
+
+       .include        "pet.inc"
+       .include        "../cbm/cbm.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     CURS_X
+               beq     plot            ; Recalculate pointers
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       ldy     CURS_Y
+       iny
+       bne     newline         ; Recalculate pointers
+
+; Printable char of some sort
+
+L2:            cmp     #' '
+       bcc     cputdirect      ; Other control char
+       tay
+       bmi     L10
+       cmp     #$60
+       bcc     L3
+       and     #$DF
+       bne     cputdirect      ; Branch always
+L3:    and     #$3F
+
+cputdirect:
+       jsr     putchar         ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+       iny
+       cpy     xsize
+       bne     L9
+       ldy     #0              ; new line
+newline:
+       clc
+       lda     xsize
+       adc     SCREEN_PTR
+       sta     SCREEN_PTR
+       bcc     L4
+       inc     SCREEN_PTR+1
+L4:    inc     CURS_Y
+L9:            sty     CURS_X
+       rts
+
+; Handle character if high bit set
+
+L10:   and     #$7F
+               cmp     #$7E            ; PI?
+       bne     L11
+       lda     #$5E            ; Load screen code for PI
+       bne     cputdirect
+L11:   ora     #$40
+       bne     cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot:  ldy     CURS_Y
+       lda     ScrLo,y
+       sta     SCREEN_PTR
+       lda     ScrHi,y
+       ldy     xsize
+       cpy     #40
+               beq     @L1
+               asl     SCREEN_PTR              ; 80 column mode
+       rol     a
+@L1:   ora     #$80                    ; Screen at $8000
+       sta     SCREEN_PTR+1
+       rts
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+       ora     revers          ; Set revers bit
+               ldy     CURS_X
+       sta     (SCREEN_PTR),y  ; Set char
+       rts
+
+; Screen address tables - offset to real screen
+
+.rodata
+
+ScrLo:         .byte   $00, $28, $50, $78, $A0, $C8, $F0, $18
+       .byte   $40, $68, $90, $B8, $E0, $08, $30, $58
+       .byte   $80, $A8, $D0, $F8, $20, $48, $70, $98
+       .byte   $C0
+
+ScrHi: .byte   $00, $00, $00, $00, $00, $00, $00, $01
+       .byte   $01, $01, $01, $01, $01, $02, $02, $02
+       .byte   $02, $02, $02, $02, $03, $03, $03, $03
+       .byte   $03
+
+
diff --git a/libsrc/pet/crt0.s b/libsrc/pet/crt0.s
new file mode 100644 (file)
index 0000000..58e67eb
--- /dev/null
@@ -0,0 +1,125 @@
+;
+; Startup code for cc65 (PET version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+               .import         __hinit, initconio, zerobss, push0, doatexit
+       .import         _main
+
+       .include        "pet.inc"
+       .include        "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+
+sp             =       $02             ; stack pointer
+sreg   =       $04             ; secondary register/high 16 bit for longs
+regsave        =       $06             ; slot to save/restore (E)AX into
+ptr1   =       $0A             ;
+ptr2   =       $0C
+ptr3   =       $0E
+ptr4   =       $10
+tmp1   =       $12
+tmp2   =       $13
+tmp3   =       $14
+tmp4   =       $15
+regbank        =       $16             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+       .org    $3FF
+        .word   Head            ; Load address
+Head:   .word   @Next
+        .word   1000            ; Line number
+        .byte   $9E,"1037"      ; SYS 1037
+        .byte   $00             ; End of BASIC line
+@Next:  .word   0               ; BASIC end marker
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y        ; Save the zero page locations we need
+       dey
+               bpl     L1
+
+; Close open files
+
+       jsr     CLRCH
+
+; Switch to second charset
+
+       lda     #14
+;      sta     $E84C           ; See PET FAQ
+       jsr     BSOUT
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Save system stuff and setup the stack
+
+               tsx
+               stx     spsave          ; Save the system stack ptr
+
+       lda     MEMSIZE
+       sta     sp
+       lda     MEMSIZE+1
+               sta     sp+1            ; Set argument stack ptr
+
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       jsr     initconio
+
+; Pass an empty command line
+
+       jsr     push0           ; argc
+       jsr     push0           ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr     doatexit        ; call exit functions
+
+       ldx     spsave
+       txs                     ; Restore stack pointer
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+               bpl     L2
+
+; Back to basic
+
+               rts
+
+
+.data
+
+zpsave:        .res    zpspace
+
+.bss
+
+spsave:        .res    1
+mmusave:.res   1
+
diff --git a/libsrc/pet/kbhit.s b/libsrc/pet/kbhit.s
new file mode 100644 (file)
index 0000000..272bad7
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+
+       .include        "pet.inc"
+
+_kbhit:
+       lda     KEY_COUNT       ; Get number of characters
+       bne     L1
+       jmp     return0
+L1:    jmp     return1
+
+
+
+
diff --git a/libsrc/pet/pet.inc b/libsrc/pet/pet.inc
new file mode 100644 (file)
index 0000000..4dcb739
--- /dev/null
@@ -0,0 +1,32 @@
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+MEMSIZE                = $34           ; Size of memory installed
+ST                     = $96           ; IEC status byte
+SECADR         = $D3           ; Secondary address
+DEVNUM         = $D4           ; Device number
+KEY_COUNT              = $9E           ; Number of keys in input buffer
+CURS_FLAG      = $A7           ; 1 = cursor off
+CURS_BLINK     = $A8           ; Blink counter
+CURS_CHAR      = $A9           ; Character under the cursor
+CURS_STATE             = $AA           ; Cursor blink state
+SCREEN_PTR             = $C4           ; Pointer to current char in text screen
+CURS_X                 = $C6           ; Cursor column
+CURS_Y                 = $D8           ; Cursor row
+SCR_LINELEN    = $D5           ; Screen line length
+
+KEY_BUF                = $26F          ; Keyboard buffer
+
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec         = $0090
+BRKVec         = $0092
+NMIVec         = $0094
+
diff --git a/libsrc/plus4/Makefile b/libsrc/plus4/Makefile
new file mode 100644 (file)
index 0000000..ae624cf
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o:           %.c
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+       @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o:   %.s
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o\
+                color.o readjoy.o break.o
+
+all:   $(C_OBJS) $(S_OBJS)
+
+clean:
+       @rm -f $(C_OBJS:.c=.s)
+       @rm -f $(C_OBJS)
+       @rm -f $(S_OBJS)
+       @rm -f crt0.o
+
diff --git a/libsrc/plus4/break.s b/libsrc/plus4/break.s
new file mode 100644 (file)
index 0000000..4365534
--- /dev/null
@@ -0,0 +1,108 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+               .export         _set_brk, _reset_brk
+       .export         _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+       .import         _atexit
+
+       .include        "plus4.inc"
+
+
+.bss
+_brk_a:                .res    1
+_brk_x:                .res    1
+_brk_y:                .res    1
+_brk_sr:       .res    1
+_brk_pc:       .res    2
+
+oldvec:        .res    2               ; Old vector
+
+
+.data
+uservec:       jmp     $FFFF           ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc  _set_brk
+
+       sta     uservec+1
+       stx     uservec+2       ; Set the user vector
+
+       lda     oldvec
+       ora     oldvec+1        ; Did we save the vector already?
+               bne     L1              ; Jump if we installed the handler already
+
+       lda     BRKVec
+       sta     oldvec
+       lda     BRKVec+1
+       sta     oldvec+1        ; Save the old vector
+
+       lda     #<_reset_brk
+       ldx     #>_reset_brk
+       jsr     _atexit         ; Install an exit handler
+
+L1:    lda     #<brk_handler   ; Set the break vector to our routine
+       sta     BRKVec
+       lda     #>brk_handler
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+; Reset the break vector
+.proc  _reset_brk
+
+       lda     oldvec
+       sta     BRKVec
+       lda     oldvec+1
+       sta     BRKVec+1
+       rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc  brk_handler
+
+       pla
+       sta     _brk_y
+       pla
+       sta     _brk_x
+       pla
+       sta     _brk_a
+       pla
+       and     #$EF            ; Clear break bit
+       sta     _brk_sr
+       pla                     ; PC low
+       sec
+       sbc     #2              ; Point to start of brk
+       sta     _brk_pc
+       pla                     ; PC high
+       sbc     #0
+       sta     _brk_pc+1
+
+       jsr     uservec         ; Call the user's routine
+
+       lda     _brk_pc+1
+       pha
+       lda     _brk_pc
+       pha
+       lda     _brk_sr
+       pha
+       ldx     _brk_x
+       ldy     _brk_y
+       lda     _brk_a
+       rti                     ; Jump back...
+
+.endproc
+
+
diff --git a/libsrc/plus4/cgetc.s b/libsrc/plus4/cgetc.s
new file mode 100644 (file)
index 0000000..493bbf1
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+               .export         _cgetc
+               .import         cursor
+
+               .include        "plus4.inc"
+
+
+_cgetc:        lda     KEY_COUNT       ; Get number of characters
+               ora     FKEY_COUNT      ; Or with number of function key chars
+               bne     L2              ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+               ldy     CURS_X
+               lda     (CRAM_PTR),y    ; Get current char
+               pha                     ; And save it
+               lda     CHARCOLOR
+               sta     (CRAM_PTR),y
+
+               lda     cursor
+               beq     L1              ; Jump if no cursor
+               tya
+               clc
+               adc     SCREEN_PTR
+               sta     TED_CURSLO
+               lda     SCREEN_PTR+1
+               adc     #$00
+               sbc     #$0B            ; + carry = $C00 (screen address)
+               sta     TED_CURSHI
+
+L1:            lda     KEY_COUNT
+               ora     FKEY_COUNT
+               beq     L1
+               pla
+               sta     (CRAM_PTR),y
+               lda     #$ff
+               sta     TED_CURSLO      ; Cursor off
+               sta     TED_CURSHI
+
+L2:            jsr     KBDREAD         ; Read char and return in A
+               ldx     #0
+               rts
+
diff --git a/libsrc/plus4/clrscr.s b/libsrc/plus4/clrscr.s
new file mode 100644 (file)
index 0000000..4b6c483
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+       .export         _clrscr
+
+       .include        "plus4.inc"
+
+_clrscr        = CLRSCR
+
+
+
+
diff --git a/libsrc/plus4/color.s b/libsrc/plus4/color.s
new file mode 100644 (file)
index 0000000..9d7107d
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+       .export         _textcolor, _bgcolor, _bordercolor
+
+       .include        "plus4.inc"
+
+_textcolor:
+       ldx     CHARCOLOR       ; get old value
+       sta     CHARCOLOR       ; set new value
+       txa
+       rts
+
+
+_bgcolor:
+               ldx     TED_BGCOLOR     ; get old value
+       sta     TED_BGCOLOR     ; set new value
+       txa
+       rts
+
+
+_bordercolor:
+               ldx     TED_BORDERCOLOR ; get old value
+       sta     TED_BORDERCOLOR ; set new value
+       txa
+       rts
+
+
diff --git a/libsrc/plus4/conio.s b/libsrc/plus4/conio.s
new file mode 100644 (file)
index 0000000..11d5307
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+       .export         initconio, doneconio
+       .exportzp       CURS_X, CURS_Y
+       .import         xsize, ysize
+
+       .include        "plus4.inc"
+       .include        "../cbm/cbm.inc"
+
+.code
+
+initconio:
+       jsr     SCREEN
+       stx     xsize
+       sty     ysize
+       ldy     #15
+L1:    lda     fnkeys,y
+       sta     FKEY_SPACE,y
+       dey
+       bpl     L1
+       rts
+
+
+doneconio:
+       ldx     #$39            ; Copy the original function keys
+L2:    lda     FKEY_ORIG,x
+       sta     FKEY_SPACE,x
+       dex
+       bpl     L2
+       rts
+
+; Function key table, readonly
+
+.rodata
+fnkeys:        .byte   $01, $01, $01, $01, $01, $01, $01, $01
+       .byte   133, 137, 134, 138, 135, 139, 136, 140
+
diff --git a/libsrc/plus4/cputc.s b/libsrc/plus4/cputc.s
new file mode 100644 (file)
index 0000000..4bf9d2e
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+       .export         _cputcxy, _cputc, cputdirect, putchar
+       .export         advance, newline, plot
+       .import         popa, _gotoxy
+       .import         xsize, revers
+
+       .include        "plus4.inc"
+       .include        "../cbm/cbm.inc"
+
+_cputcxy:
+       pha                     ; Save C
+       jsr     popa            ; Get Y
+       jsr     _gotoxy         ; Set cursor, drop x
+       pla                     ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp    #$0D            ; CR?
+       bne     L1
+       lda     #0
+       sta     CURS_X
+               beq     plot            ; Recalculate pointers
+
+L1:    cmp     #$0A            ; LF?
+               bne     L2
+       ldy     CURS_Y
+       iny
+       bne     newline         ; Recalculate pointers
+
+; Printable char of some sort
+
+L2:            cmp     #' '
+       bcc     cputdirect      ; Other control char
+       tay
+       bmi     L10
+       cmp     #$60
+       bcc     L3
+       and     #$DF
+       bne     cputdirect      ; Branch always
+L3:    and     #$3F
+
+cputdirect:
+       jsr     putchar         ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+       iny
+       cpy     xsize
+       bne     L9
+       ldy     #0              ; new line
+newline:
+       clc
+       lda     xsize
+       adc     SCREEN_PTR
+       sta     SCREEN_PTR
+       bcc     L4
+       inc     SCREEN_PTR+1
+L4:    clc
+       lda     xsize
+       adc     CRAM_PTR
+       sta     CRAM_PTR
+       bcc     L5
+       inc     CRAM_PTR+1
+L5:    inc     CURS_Y
+L9:            sty     CURS_X
+       rts
+
+; Handle character if high bit set
+
+L10:   and     #$7F
+               cmp     #$7E            ; PI?
+       bne     L11
+       lda     #$5E            ; Load screen code for PI
+       bne     cputdirect
+L11:   ora     #$40
+       bne     cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot:  ldy     CURS_X
+       ldx     CURS_Y
+       clc
+       jmp     PLOT            ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+       ora     revers          ; Set revers bit
+               ldy     CURS_X
+       sta     (SCREEN_PTR),y  ; Set char
+       lda     CHARCOLOR
+       sta     (CRAM_PTR),y    ; Set color
+       rts
diff --git a/libsrc/plus4/crt0.s b/libsrc/plus4/crt0.s
new file mode 100644 (file)
index 0000000..72fce20
--- /dev/null
@@ -0,0 +1,129 @@
+;
+; Startup code for cc65 (Plus/4 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+       .export         _exit
+       .import         __hinit, push0, doatexit, _main
+       .import         initconio, doneconio, zerobss
+
+       .include        "plus4.inc"
+       .include        "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+       .exportzp       sp, sreg, regsave
+       .exportzp       ptr1, ptr2, ptr3, ptr4
+       .exportzp       tmp1, tmp2, tmp3, tmp4
+       .exportzp       regbank, zpspace
+
+sp             =       $02             ; stack pointer
+sreg   =       $04             ; secondary register/high 16 bit for longs
+regsave        =       $06             ; slot to save/restore (E)AX into
+ptr1   =       $0A             ;
+ptr2   =       $0C
+ptr3   =       $0E
+ptr4   =       $10
+tmp1   =       $12
+tmp2   =       $13
+tmp3   =       $14
+tmp4   =       $15
+regbank        =       $16             ; 6 byte register bank
+zpspace        =       $1A             ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+       .org    $0FFF
+        .word   Head            ; Load address
+Head:   .word   @Next
+        .word   1000            ; Line number
+        .byte   $9E,"4109"     ; SYS 4109
+        .byte   $00             ; End of BASIC line
+@Next:  .word   0               ; BASIC end marker
+       .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+       ldy     #zpspace-1
+L1:    lda     sp,y
+       sta     zpsave,y        ; save the zero page locations we need
+       dey
+               bpl     L1
+
+; Close open files
+
+       jsr     CLRCH
+
+; Switch to second charset
+
+       lda     #14
+       jsr     BSOUT
+
+; Clear the BSS data
+
+       jsr     zerobss
+
+; Save system stuff and setup the stack
+
+               tsx
+               stx     spsave          ; save system stk ptr
+
+       sec
+       jsr     MEMTOP          ; Get top memory
+       cpy     #$80            ; We can only use the low 32K :-(
+       bcc     MemOk
+       ldy     #$80
+       ldx     #$00
+MemOk: stx     sp
+       sty     sp+1            ; set argument stack ptr
+
+; Initialize the heap
+
+       jsr     __hinit
+
+; Initialize conio stuff
+
+       jsr     initconio
+
+; Pass an empty command line
+
+               jsr     push0           ; argc
+       jsr     push0           ; argv
+
+       ldy     #4              ; Argument size
+               jsr     _main           ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr     doatexit        ; call exit functions
+       ldx     spsave
+       txs
+
+; Reset the conio stuff
+
+       jsr     doneconio
+
+; Copy back the zero page stuff
+
+       ldy     #zpspace-1
+L2:    lda     zpsave,y
+       sta     sp,y
+       dey
+               bpl     L2
+
+; Reset changed vectors
+
+       jmp     RESTOR
+
+
+.data
+zpsave:        .res    zpspace
+
+.bss
+spsave:        .res    1
+
+
diff --git a/libsrc/plus4/kbhit.s b/libsrc/plus4/kbhit.s
new file mode 100644 (file)
index 0000000..2a804cd
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+       .export         _kbhit
+       .import         return0, return1
+       
+       .include        "plus4.inc"
+
+_kbhit:
+       lda     KEY_COUNT       ; Get number of characters
+       ora     FKEY_COUNT      ; Or with number of chars from function keys
+       bne     L1
+       jmp     return0
+L1:    jmp     return1
+
+
+
+
diff --git a/libsrc/plus4/plus4.inc b/libsrc/plus4/plus4.inc
new file mode 100644 (file)
index 0000000..5b8ab26
--- /dev/null
@@ -0,0 +1,66 @@
+;
+; Plus/4 generic definitions.
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST             = $90           ; IEC status byte
+
+FNAM_LEN               = $AB           ; Length of filename
+SECADR         = $AD           ; Secondary address
+DEVNUM         = $AE           ; Device number
+KEY_COUNT              = $EF           ; Number of keys in input buffer
+CURS_X         = $CA           ; Cursor column
+CURS_Y         = $CD           ; Cursor row
+SCREEN_PTR     = $C8           ; Pointer to current char in text screen
+CRAM_PTR       = $EA           ; Pointer to current char in color RAM
+
+CHARCOLOR       = $53B
+FKEY_COUNT     = $55D          ; Characters for function key
+FKEY_SPACE     = $55F          ; Function key definitions
+FKEY_ORIG      = $F3D2         ; Original definitions
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CLRSCR         = $D88B
+KBDREAD                = $D8C1
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec         = $0314
+BRKVec         = $0316
+NMIVec         = $0318
+
+; ---------------------------------------------------------------------------
+; I/O
+
+TED_T1LO       = $FF00
+TED_T1HI       = $FF01
+TED_T2LO       = $FF02
+TED_T2HI       = $FF03
+TED_T3LO       = $FF04
+TED_T4HI       = $FF05
+TED_KBD                = $FF08
+TED_CURSHI     = $FF0C
+TED_CURSLO     = $FF0D
+TED_V1FRQLO    = $FF0E
+TED_V2FRQLO    = $FF0F
+TED_V2FRQHI    = $FF10
+TED_BGCOLOR    = $FF15
+TED_COLOR1     = $FF16
+TED_COLOR2     = $FF17
+TED_COLOR3     = $FF18
+TED_BORDERCOLOR        = $FF19
+TED_VLINEHI    = $FF1C
+TED_VLINELO    = $FF1D
+TED_HPOS       = $FF1E
+TED_ROMSEL     = $FF3E
+TED_RAMSEL     = $FF3F
+
+
+
diff --git a/libsrc/plus4/readjoy.s b/libsrc/plus4/readjoy.s
new file mode 100644 (file)
index 0000000..3385589
--- /dev/null
@@ -0,0 +1,29 @@
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+       .export         _readjoy
+
+       .include        "plus4.inc"
+
+
+.proc  _readjoy
+
+       ldy     #$FA            ; Load index for joystick #1
+       tax                     ; Test joystick number
+       beq     L1
+       ldy     #$FB            ; Load index for joystick #2
+L1:            sei
+       sty     TED_KBD
+       lda     TED_KBD
+       cli
+       ldx     #$00            ; Clear high byte
+       and     #$1F
+       eor     #$1F
+       rts
+
+.endproc
+
+
diff --git a/libsrc/runtime/Makefile b/libsrc/runtime/Makefile
new file mode 100644 (file)
index 0000000..775d60f
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+.c.s:
+       @echo $<
+       @$(CC) $(CFLAGS) $<
+
+.s.o:
+       @echo $<
+       @$(AS) -g -o $@ $(AFLAGS) $<
+
+OBJS   = runtime.o mul.o div.o push.o inc.o dec.o shl.o shr.o add.o\
+        sub.o rsub.o or.o xor.o and.o neg.o bneg.o compl.o icmp.o\
+        call.o swap.o switch.o gt.o ugt.o ge.o makebool.o ldau0sp.o\
+        uge.o lt.o ult.o le.o ule.o eq.o ne.o test.o subeqsp.o\
+        udiv.o umod.o mod.o shelp.o aslax1.o asrax1.o shrax1.o\
+         aslax2.o asrax2.o shrax2.o aslax3.o asrax3.o shrax3.o\
+        enter.o leave.o leaysp.o popsreg.o ldai.o ldaxi.o ldauisp.o\
+        ldaui.o pushw.o pushb.o staxsp.o ldaxsp.o addeqsp.o\
+        ldasp.o ldausp.o bpushbsp.o pushwsp.o pushbsp.o
+
+LOBJS  = lruntime.o lconvert.o ladd.o lsub.o lrsub.o leq.o lne.o\
+        lneg.o lbneg.o lcompl.o lpush.o land.o lor.o lxor.o ldeaxi.o\
+        ltest.o llt.o lle.o lge.o lgt.o lsave.o asleax1.o laddeqsp.o\
+        asreax1.o shreax1.o asleax2.o asreax2.o shreax2.o lsubeqsp.o\
+        asleax3.o asreax3.o shreax3.o lmul.o lshelp.o ludiv.o lumod.o\
+        ldiv.o lmod.o lswitch.o steaxsp.o lshr.o lshl.o lcmp.o lugt.o\
+        luge.o lult.o lule.o linc.o ldec.o lswap.o lpop.o ldeax.o\
+        lsubeq.o laddeq.o
+
+all:   $(OBJS) $(LOBJS)
+
+clean:
+       @rm -f *~
+       @rm -f $(COBJS:.o=.s)
+       @rm -f $(OBJS)
+       @rm -f $(LOBJS)
+
+
diff --git a/libsrc/runtime/add.s b/libsrc/runtime/add.s
new file mode 100644 (file)
index 0000000..5d83ef9
--- /dev/null
@@ -0,0 +1,47 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: add ints
+;
+
+; Make this as fast as possible, even if it needs more space since it's
+; called a lot!
+
+               .export         tosadda0, tosaddax
+       .importzp       sp, tmp1
+
+tosadda0:
+       ldx     #0
+tosaddax:
+       ldy     #0
+       clc
+       adc     (sp),y          ; lo byte
+       sta     tmp1            ; save it
+       txa
+       iny
+       adc     (sp),y          ; hi byte
+       tax
+       clc
+       lda     sp
+       adc     #2
+       sta     sp
+       bcc     L1
+       inc     sp+1
+L1:    txa                     ; Test high byte
+       bmi     L2
+       bne     L3
+       lda     tmp1            ; Get low byte
+       rts
+
+; Value is negative
+
+L2:    lda     tmp1            ; Get low byte
+       ldy     #$FF            ; Force negative
+       rts
+
+; Value is positive != 0
+
+L3:    lda     tmp1            ; Get low byte
+       ldy     #1
+       rts
+
diff --git a/libsrc/runtime/addeqsp.s b/libsrc/runtime/addeqsp.s
new file mode 100644 (file)
index 0000000..d667e36
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: += operator for ints on the stack
+;
+
+               .export         addeq0sp, addeqysp
+       .importzp       sp
+
+addeq0sp:
+       ldy     #0
+addeqysp:
+       clc
+       adc     (sp),y
+       sta     (sp),y
+       pha
+       iny
+       txa
+       adc     (sp),y
+       sta     (sp),y
+       tax
+       pla
+       rts
+
diff --git a/libsrc/runtime/and.s b/libsrc/runtime/and.s
new file mode 100644 (file)
index 0000000..cf1d10e
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: and on ints
+;
+
+               .export         tosanda0, tosandax
+       .import         addysp1
+       .importzp       sp, ptr4
+
+tosanda0:
+       ldx     #$00
+tosandax:
+       ldy     #0
+               and     (sp),y
+       sta     ptr4
+       iny
+       txa
+       and     (sp),y
+       tax
+       lda     ptr4
+       jmp     addysp1         ; drop TOS, set condition codes
+
diff --git a/libsrc/runtime/aslax1.s b/libsrc/runtime/aslax1.s
new file mode 100644 (file)
index 0000000..eddb527
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+               .export         aslax1, shlax1
+       .importzp       tmp1
+                           
+aslax1:
+shlax1: stx    tmp1
+       asl     A
+       rol     tmp1
+       ldx     tmp1
+       rts
+
+
diff --git a/libsrc/runtime/aslax2.s b/libsrc/runtime/aslax2.s
new file mode 100644 (file)
index 0000000..e6e56b0
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+               .export         aslax2, shlax2
+       .importzp       tmp1
+
+aslax2:
+shlax2:        stx     tmp1
+               asl     a
+               rol     tmp1
+               asl     a
+               rol     tmp1
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/aslax3.s b/libsrc/runtime/aslax3.s
new file mode 100644 (file)
index 0000000..9c9bbb8
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+       .export         aslax3, shlax3
+       .importzp       tmp1
+
+aslax3:
+shlax3:        stx     tmp1
+               asl     a
+               rol     tmp1
+               asl     a
+               rol     tmp1
+               asl     a
+               rol     tmp1
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/asleax1.s b/libsrc/runtime/asleax1.s
new file mode 100644 (file)
index 0000000..8f30a18
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 2
+;
+
+               .export         asleax1, shleax1
+       .importzp       sreg, tmp1
+
+asleax1:
+shleax1:
+       stx     tmp1
+       asl     a
+       rol     tmp1
+       rol     sreg
+       rol     sreg+1
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asleax2.s b/libsrc/runtime/asleax2.s
new file mode 100644 (file)
index 0000000..772a37d
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+       .export         asleax2, shleax2
+       .importzp       sreg, tmp1
+
+asleax2:
+shleax2:
+       stx     tmp1
+       asl     a
+       rol     tmp1
+       rol     sreg
+       rol     sreg+1
+       asl     a
+       rol     tmp1
+       rol     sreg
+       rol     sreg+1
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asleax3.s b/libsrc/runtime/asleax3.s
new file mode 100644 (file)
index 0000000..1c45320
--- /dev/null
@@ -0,0 +1,27 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+       .export         asleax3, shleax3
+       .importzp       sreg, tmp1
+
+asleax3:
+shleax3:
+               stx     tmp1
+               asl     a
+               rol     tmp1
+               rol     sreg
+               rol     sreg+1
+               asl     a
+       rol     tmp1
+       rol     sreg
+       rol     sreg+1
+               asl     a
+       rol     tmp1
+       rol     sreg
+       rol     sreg+1
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asrax1.s b/libsrc/runtime/asrax1.s
new file mode 100644 (file)
index 0000000..bf7646a
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+               .export         asrax1
+       .importzp       tmp1
+
+asrax1: stx    tmp1
+       cpx     #$80            ; Put bit 7 into carry
+       ror     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asrax2.s b/libsrc/runtime/asrax2.s
new file mode 100644 (file)
index 0000000..b6cb3f7
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+               .export         asrax2
+       .importzp       tmp1
+
+asrax2:        stx     tmp1
+       cpx     #$80            ; Put bit 7 into carry
+       ror     tmp1
+       ror     a
+       cpx     #$80
+       ror     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asrax3.s b/libsrc/runtime/asrax3.s
new file mode 100644 (file)
index 0000000..e3286d4
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+       .export         asrax3
+       .importzp       tmp1
+
+asrax3:        stx     tmp1
+       cpx     #$80            ; Put bit 7 into carry
+       ror     tmp1
+       ror     a
+       ldx     tmp1
+       cpx     #$80
+       ror     tmp1
+       ror     a
+       ldx     tmp1
+       cpx     #$80
+       ror     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/asreax1.s b/libsrc/runtime/asreax1.s
new file mode 100644 (file)
index 0000000..ab02ed9
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+               .export         asreax1
+       .importzp       sreg, tmp1
+
+asreax1:
+       stx     tmp1
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/asreax2.s b/libsrc/runtime/asreax2.s
new file mode 100644 (file)
index 0000000..40c94c0
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+       .export         asreax2
+       .importzp       sreg, tmp1
+
+asreax2:
+       stx     tmp1
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/asreax3.s b/libsrc/runtime/asreax3.s
new file mode 100644 (file)
index 0000000..64f005f
--- /dev/null
@@ -0,0 +1,32 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+       .export         asreax3
+       .importzp       sreg, tmp1
+
+asreax3:
+               stx     tmp1
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     sreg+1
+               cpx     #$80            ; Get bit 7 into carry
+               ror     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/bneg.s b/libsrc/runtime/bneg.s
new file mode 100644 (file)
index 0000000..034d716
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: boolean negation
+;
+
+               .export         bnega, bnegax
+       .import         return0, return1
+
+bnegax:        cpx     #0
+       bne     L0
+bnega: cmp     #0
+       bne     L0
+L1:    ldx     #0
+       lda     #1
+       rts
+
+L0:    ldx     #0
+       txa
+       rts
+
diff --git a/libsrc/runtime/bpushbsp.s b/libsrc/runtime/bpushbsp.s
new file mode 100644 (file)
index 0000000..f4d8d53
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from stack slot and push as byte
+;
+
+       .export         bpushbsp, bpushbysp
+       .import         pusha
+       .importzp       sp
+
+bpushbsp:
+       ldy     #0
+bpushbysp:
+       lda     (sp),y
+       jmp     pusha
+
+
+
diff --git a/libsrc/runtime/call.s b/libsrc/runtime/call.s
new file mode 100644 (file)
index 0000000..0600177
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: call function via pointer in ax
+;
+
+       .export         callax
+       .importzp       ptr1
+
+callax:        sta     ptr1
+       stx     ptr1+1
+       jmp     (ptr1)          ; jump there
+
diff --git a/libsrc/runtime/compl.s b/libsrc/runtime/compl.s
new file mode 100644 (file)
index 0000000..5e96263
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: integer complement
+;
+
+               .export         complax
+
+complax:
+       eor     #$FF            ; Not A
+       pha
+       txa
+       eor     #$FF            ; Not X
+       tax
+       pla
+       rts
+
diff --git a/libsrc/runtime/dec.s b/libsrc/runtime/dec.s
new file mode 100644 (file)
index 0000000..784e73f
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Decrement ax by constant or value in Y
+;
+
+               .export         decaxy
+       .export         decax2, decax1
+       .importzp       tmp1
+
+
+decaxy:        sty     tmp1
+       sec
+       sbc     tmp1
+       bcs     *+3
+       dex
+       rts
+
+decax2:        sec
+       sbc     #2
+       bcs     *+3
+       dex
+       rts
+
+decax1:        sec
+       sbc     #1
+       bcs     *+3
+       dex
+       rts
+
+                             
diff --git a/libsrc/runtime/div.s b/libsrc/runtime/div.s
new file mode 100644 (file)
index 0000000..b995b9e
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: division for signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+               .export         tosdiva0, tosdivax
+       .import         popsargs, udiv16, adjsres
+       .importzp       sreg
+
+tosdiva0:
+       ldx     #0
+tosdivax:
+       jsr     popsargs        ; Get arguments from stack, adjust sign
+       jsr     udiv16          ; Do the division
+       lda     sreg            ; Result is in sreg, remainder in ptr1
+       ldx     sreg+1
+       jmp     adjsres         ; Adjust the sign of the result if needed
+
diff --git a/libsrc/runtime/enter.s b/libsrc/runtime/enter.s
new file mode 100644 (file)
index 0000000..a246d5e
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: function prologue
+;
+
+               .export         enter
+       .importzp       sp
+
+enter: tya                     ; get arg size
+               ldy     sp
+       bne     L1
+       dec     sp+1
+L1:    dec     sp
+       ldy     #0
+       sta     (sp),y          ; Store the arg count
+       rts
+
diff --git a/libsrc/runtime/eq.s b/libsrc/runtime/eq.s
new file mode 100644 (file)
index 0000000..28e5205
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare == for ints
+;
+
+       .export         toseq00, toseqa0, toseqax
+       .import         tosicmp, booleq
+       .importzp       sp, tmp1
+
+toseq00:
+       lda     #$00
+toseqa0:
+       ldx     #$00
+toseqax:
+       jsr     tosicmp         ; Set flags
+       jmp     booleq          ; Convert to boolean
diff --git a/libsrc/runtime/ge.s b/libsrc/runtime/ge.s
new file mode 100644 (file)
index 0000000..17d4bb9
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare >= for signed ints
+;
+
+       .export         tosge00, tosgea0, tosgeax
+               .import         tosicmp, boolge
+
+
+tosge00:
+       lda     #$00
+tosgea0:
+       ldx     #$00
+tosgeax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolge          ; Convert to boolean
diff --git a/libsrc/runtime/gt.s b/libsrc/runtime/gt.s
new file mode 100644 (file)
index 0000000..b6ba7b6
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare > for signed ints
+;
+
+       .export         tosgt00, tosgta0, tosgtax
+               .import         tosicmp, boolgt
+
+
+tosgt00:
+       lda     #$00
+tosgta0:
+       ldx     #$00
+tosgtax:
+               jsr     tosicmp         ; Set the flags
+       jmp     boolgt          ; Convert to boolean
+
diff --git a/libsrc/runtime/icmp.s b/libsrc/runtime/icmp.s
new file mode 100644 (file)
index 0000000..e3b2bba
--- /dev/null
@@ -0,0 +1,44 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; Integer compare function - used by the compare operators
+;
+
+       .export         tosicmp
+       .import         incsp2
+       .importzp       sp, sreg
+
+
+tosicmp:
+       sta     sreg
+       stx     sreg+1          ; Save ax
+
+       ldy     #$01
+               lda     (sp),y          ; Get high byte
+       tax
+       dey
+       lda     (sp),y          ; Get low byte
+
+; Inline incsp2 for better performance
+
+       inc     sp              ; 5
+               bne     @L1             ; 3
+       inc     sp+1            ; (5)
+@L1:   inc     sp              ; 5
+       bne     @L2             ; 3
+       inc     sp+1            ; (5)
+
+; Do the compare.
+
+@L2:   cpx     sreg+1          ; Compare high byte
+       bne     @L3
+       cmp     sreg            ; Compare low byte
+               beq     @L3
+               bcs     @L4
+               lda     #$FF            ; Set the N flag
+@L3:   rts
+
+@L4:           lda     #$01            ; Clear the N flag
+       rts
+
+
diff --git a/libsrc/runtime/inc.s b/libsrc/runtime/inc.s
new file mode 100644 (file)
index 0000000..043d27d
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: Increment ax by constant or value in Y
+;
+
+               .export         incaxy
+       .export         incax8, incax7, incax6, incax5
+       .export         incax4, incax3, incax2, incax1
+       .importzp       tmp1
+
+
+incax8:        ldy     #8
+               bne     incaxy
+
+incax7:        ldy     #7
+       bne     incaxy
+
+incax6:        ldy     #6
+       bne     incaxy
+
+incax5:        ldy     #5
+       bne     incaxy
+
+incax4:        ldy     #4
+       bne     incaxy
+
+incax3:        ldy     #3
+;      bne     incaxy
+incaxy:        sty     tmp1
+       clc
+       adc     tmp1
+       bcc     *+3
+       inx
+       rts
+                  
+incax2:        clc
+       adc     #2
+       bcc     *+3
+       inx
+       rts
+
+incax1:        clc
+       adc     #1
+       bcc     *+3
+       inx
+       rts
+
diff --git a/libsrc/runtime/ladd.s b/libsrc/runtime/ladd.s
new file mode 100644 (file)
index 0000000..fabedc9
--- /dev/null
@@ -0,0 +1,32 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long add
+;
+
+       .export         tosaddeax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1
+
+; EAX = TOS + EAX
+
+tosaddeax:
+       ldy     #0
+       clc
+       adc     (sp),y          ; byte 0
+       sta     tmp1            ; use as temp storage
+       iny
+       txa
+       adc     (sp),y          ; byte 1
+       tax
+       iny
+       lda     sreg
+       adc     (sp),y          ; byte 2
+       sta     sreg
+       iny
+       lda     sreg+1
+       adc     (sp),y          ; byte 3
+       sta     sreg+1
+       lda     tmp1            ; load byte 0
+               jmp     addysp1         ; drop TOS
+
diff --git a/libsrc/runtime/laddeq.s b/libsrc/runtime/laddeq.s
new file mode 100644 (file)
index 0000000..6478017
--- /dev/null
@@ -0,0 +1,53 @@
+;
+; Ullrich von Bassewitz, 07.04.2000
+;
+; CC65 runtime: += operator
+;
+; On entry, the low byte of the address of the variable to increment is
+; in ptr1, the high byte is in Y, and the increment is in eax.
+;
+
+               .export         laddeq1, laddeqa, laddeq
+               .importzp       sreg, ptr1, tmp1
+
+
+laddeq1:
+               lda     #$01
+
+laddeqa:
+       ldx     #$00
+       stx     sreg
+       stx     sreg+1
+
+laddeq:        sty     ptr1+1                  ; Store high byte of address
+       ldy     #$00                    ; Address low byte
+       clc
+
+       adc     (ptr1),y
+       sta     (ptr1),y
+               pha                             ; Save byte 0 of result for later
+
+       iny                             ; Address byte 1
+       txa
+       adc     (ptr1),y                ; Load byte 1
+       sta     (ptr1),y
+       tax
+
+       iny                             ; Address byte 2
+       lda     sreg
+       adc     (ptr1),y
+       sta     (ptr1),y
+       sta     sreg
+
+       iny                             ; Address byte 3
+       lda     sreg+1
+       adc     (ptr1),y
+       sta     (ptr1),y
+       sta     sreg+1
+
+       pla                             ; Retrieve byte 0 of result
+
+       rts                             ; Done
+
+
+
diff --git a/libsrc/runtime/laddeqsp.s b/libsrc/runtime/laddeqsp.s
new file mode 100644 (file)
index 0000000..e5a1f04
--- /dev/null
@@ -0,0 +1,34 @@
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: += operator for longs on the stack
+;
+
+               .export         laddeq0sp, laddeqysp
+       .importzp       sp, sreg
+
+laddeq0sp:
+       ldy     #0
+laddeqysp:
+       clc
+       adc     (sp),y
+       sta     (sp),y
+       pha
+       iny
+       txa
+       adc     (sp),y
+       sta     (sp),y
+       tax
+       iny
+       lda     sreg
+       adc     (sp),y
+       sta     (sp),y
+       sta     sreg
+       iny
+       lda     sreg+1
+       adc     (sp),y
+       sta     (sp),y
+       sta     sreg+1
+       pla
+       rts
+
diff --git a/libsrc/runtime/land.s b/libsrc/runtime/land.s
new file mode 100644 (file)
index 0000000..1ee2a29
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: and on longs
+;
+
+       .export         tosandeax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1
+
+tosandeax:
+               ldy     #0
+               and     (sp),y          ; byte 0
+       sta     tmp1
+       iny
+       txa
+       and     (sp),y          ; byte 1
+       tax
+       iny
+       lda     sreg
+       and     (sp),y          ; byte 2
+       sta     sreg
+       iny
+       lda     sreg+1
+       and     (sp),y          ; byte 3
+       sta     sreg+1
+
+       lda     tmp1
+               jmp     addysp1
+
diff --git a/libsrc/runtime/lbneg.s b/libsrc/runtime/lbneg.s
new file mode 100644 (file)
index 0000000..cd508e5
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: boolean negation for longs
+;
+
+       .export         bnegeax
+       .import         return0, return1
+       .importzp       sreg
+
+bnegeax:
+       cmp     #0
+       bne     L1
+       cpx     #0
+       bne     L1
+               lda     sreg
+       bne     L1
+               lda     sreg+1
+       bne     L1
+       jmp     return1
+L1:    jmp     return0
+
diff --git a/libsrc/runtime/lcmp.s b/libsrc/runtime/lcmp.s
new file mode 100644 (file)
index 0000000..c2cb9ff
--- /dev/null
@@ -0,0 +1,50 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; Long int compare function - used by the compare operators
+;
+
+       .export         lcmp
+       .import         incsp4
+       .importzp       sp, sreg, ptr1
+
+
+lcmp:          sta     ptr1
+       stx     ptr1+1          ; EAX now in sreg:ptr1
+
+       ldy     #$03
+               lda     (sp),y
+       cmp     sreg+1
+       bne     L4
+
+       dey
+       lda     (sp),y
+       cmp     sreg
+       bne     L1
+
+       dey
+       lda     (sp),y
+       cmp     ptr1+1
+       bne     L1
+
+       dey
+       lda     (sp),y
+       cmp     ptr1
+
+L1:    php                     ; Save flags
+       jsr     incsp4          ; Drop TOS
+       plp                     ; Restore the flags
+       beq     L2
+       bcs     L3
+       lda     #$FF            ; Set the N flag
+L2:    rts
+
+L3:    lda     #$01            ; Clear the N flag
+       rts
+
+L4:    php                     ; Save flags
+       jsr     incsp4          ; Drop TOS
+       plp                     ; Restore flags
+       rts
+
+                 
diff --git a/libsrc/runtime/lcompl.s b/libsrc/runtime/lcompl.s
new file mode 100644 (file)
index 0000000..fff31d9
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: long complement
+;
+
+       .export         compleax
+       .importzp       sreg
+
+; eax = ~eax
+
+compleax:
+       eor     #$FF
+       pha
+       txa
+       eor     #$FF
+       tax
+       lda     sreg
+       eor     #$FF
+       sta     sreg
+       lda     sreg+1
+       eor     #$FF
+       sta     sreg+1
+       pla
+       rts
+
diff --git a/libsrc/runtime/lconvert.s b/libsrc/runtime/lconvert.s
new file mode 100644 (file)
index 0000000..f33c754
--- /dev/null
@@ -0,0 +1,88 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long conversion routines
+;
+
+;
+; Convert TOS from long to int by cutting of the high 16bit
+;
+               .export         tosint, tosulong, toslong, axulong, axlong
+       .import         incsp2, decsp2
+       .importzp       sp, sreg
+
+tosint:        pha
+       ldy     #0
+       lda     (sp),y          ; sp+1
+       ldy     #2
+       sta     (sp),y
+       ldy     #1
+       lda     (sp),y
+       ldy     #3
+       sta     (sp),y
+       pla
+               jmp     incsp2          ; Drop 16 bit
+
+;
+; Convert TOS from int to long
+;
+
+tosulong:
+               pha
+       jsr     decsp2          ; Make room
+       ldy     #2
+       lda     (sp),y
+       ldy     #0
+               sta     (sp),y
+       ldy     #3
+       lda     (sp),y
+       ldy     #1
+       sta     (sp),y
+       lda     #0              ; Zero extend
+toslong2:
+       iny
+       sta     (sp),y
+       iny
+       sta     (sp),y
+       pla
+       rts
+
+toslong:
+               pha
+       jsr     decsp2          ; Make room
+       ldy     #2
+       lda     (sp),y
+       ldy     #0
+               sta     (sp),y
+       ldy     #3
+       lda     (sp),y
+       bmi     toslong1
+       ldy     #1
+       sta     (sp),y
+       lda     #$00            ; Positive, high word is zero
+       bne     toslong2
+toslong1:
+       ldy     #1
+       sta     (sp),y
+       lda     #$FF
+       bne     toslong2
+
+;
+; Convert AX from int to long in EAX
+;
+
+axulong:
+       ldy     #0
+       sty     sreg
+       sty     sreg+1
+               rts
+
+axlong:        cpx     #$80            ; Positive?
+       bcc     axulong         ; Yes, handle like unsigned type
+       ldy     #$ff
+       sty     sreg
+       sty     sreg+1
+       rts
+
+
+
diff --git a/libsrc/runtime/ldai.s b/libsrc/runtime/ldai.s
new file mode 100644 (file)
index 0000000..0dc1ef2
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a indirect from address in ax
+;
+
+       .export         ldai, ldaidx
+       .importzp       ptr1
+
+ldai:  ldy     #$00
+ldaidx:        sta     ptr1
+       stx     ptr1+1
+       ldx     #$00
+       lda     (ptr1),y
+       bpl     L9
+       dex
+L9:    rts
+
diff --git a/libsrc/runtime/ldasp.s b/libsrc/runtime/ldasp.s
new file mode 100644 (file)
index 0000000..ae08868
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from offset in stack
+;
+
+               .export         ldasp, ldaysp
+       .importzp       sp
+
+ldasp: ldy     #0
+ldaysp:        ldx     #0
+       lda     (sp),y
+       bpl     L9              ; Jump if positive
+       dex
+L9:    rts
+
+
diff --git a/libsrc/runtime/ldau0sp.s b/libsrc/runtime/ldau0sp.s
new file mode 100644 (file)
index 0000000..e967f7a
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 11.04.1999
+;
+; CC65 runtime: Load an unsigned char indirect from pointer somewhere in stack
+;
+
+       .export         ldau00sp, ldau0ysp
+       .importzp       sp, ptr1
+
+ldau00sp:
+       ldy     #1
+ldau0ysp:
+       lda     (sp),y
+       sta     ptr1+1
+       dey
+       lda     (sp),y
+       sta     ptr1
+       ldx     #0
+       lda     (ptr1,x)
+       rts
+
diff --git a/libsrc/runtime/ldaui.s b/libsrc/runtime/ldaui.s
new file mode 100644 (file)
index 0000000..b61ff1f
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a unsigned indirect from address in ax
+;
+
+       .export         ldaui, ldauidx
+       .importzp       ptr1
+          
+ldaui: 
+       ldy     #0
+ldauidx:
+       sta     ptr1
+       stx     ptr1+1
+       ldx     #0
+       lda     (ptr1),y
+       rts
+
diff --git a/libsrc/runtime/ldauisp.s b/libsrc/runtime/ldauisp.s
new file mode 100644 (file)
index 0000000..7e15329
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 11.04.1999
+;
+; CC65 runtime: Load an unsigned char indirect from pointer somewhere in stack
+;
+
+       .export         ldaui0sp, ldauiysp
+       .importzp       sp, ptr1
+
+ldaui0sp:
+       ldy     #1
+ldauiysp:
+       lda     (sp),y
+       sta     ptr1+1
+       dey
+       lda     (sp),y
+       sta     ptr1
+       txa
+       tay
+       ldx     #0
+       lda     (ptr1),y
+       rts
+
+                                  
diff --git a/libsrc/runtime/ldausp.s b/libsrc/runtime/ldausp.s
new file mode 100644 (file)
index 0000000..aaa47c2
--- /dev/null
@@ -0,0 +1,16 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a unsigned from offset in stack
+;
+
+               .export         ldausp, ldauysp
+       .importzp       sp
+
+ldausp:        ldy     #0
+ldauysp:
+       ldx     #0
+       lda     (sp),y
+       rts
+
+
diff --git a/libsrc/runtime/ldaxi.s b/libsrc/runtime/ldaxi.s
new file mode 100644 (file)
index 0000000..a03c610
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load ax indirect from address in ax
+;
+
+       .export         ldaxi, ldaxidx
+       .importzp       ptr1
+
+ldaxi: ldy     #1
+ldaxidx:
+       sta     ptr1
+       stx     ptr1+1
+       lda     (ptr1),y
+       tax
+       dey
+       lda     (ptr1),y
+       rts
+
diff --git a/libsrc/runtime/ldaxsp.s b/libsrc/runtime/ldaxsp.s
new file mode 100644 (file)
index 0000000..b72e237
--- /dev/null
@@ -0,0 +1,28 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load ax from offset in stack
+;
+
+               .export         ldax0sp, ldaxysp
+       .importzp       sp
+
+; Beware: The optimizer knows about the value in Y after return!
+
+ldax0sp:
+       ldy     #1
+ldaxysp:
+       lda     (sp),y          ; get high byte
+       tax                     ; and save it
+               bne     L1              ; Try to generate FAST code
+       dey                     ; point to lo byte
+       lda     (sp),y          ; load low byte
+       rts
+
+L1:    php                     ; Save Z flag
+       dey
+       lda     (sp),y
+       plp
+       rts
+
+
diff --git a/libsrc/runtime/ldeax.s b/libsrc/runtime/ldeax.s
new file mode 100644 (file)
index 0000000..9912a52
--- /dev/null
@@ -0,0 +1,38 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Load eax from immidiate value following the call
+;
+
+       .export         ldeax
+       .importzp       sreg, ptr4
+
+
+ldeax: pla                     ; Low byte of return address
+       sta     ptr4
+       pla                     ; high byte of return address
+       sta     ptr4+1
+       ldy     #4              ; high byte of value
+       lda     (ptr4),y
+       sta     sreg+1
+       dey
+       lda     (ptr4),y
+       sta     sreg
+       dey
+       lda     (ptr4),y
+       tax
+       dey
+       lda     (ptr4),y
+       tay                     ; Save low byte
+       clc
+       lda     #4
+       adc     ptr4
+       sta     ptr4
+       lda     ptr4+1
+       adc     #$00
+       pha                     ; High byte of new return address
+       lda     ptr4
+       pha                     ; Low byte of new return address
+       tya                     ; Low byte of fetched value
+       rts
+
diff --git a/libsrc/runtime/ldeaxi.s b/libsrc/runtime/ldeaxi.s
new file mode 100644 (file)
index 0000000..a1f9e64
--- /dev/null
@@ -0,0 +1,25 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load eax indirect from address in ax
+;
+
+       .export         ldeaxidx, ldeaxi
+       .importzp       sreg, ptr1
+
+ldeaxi:        ldy     #3
+ldeaxidx:
+       sta     ptr1
+       stx     ptr1+1
+       lda     (ptr1),y
+       dey
+       sta     sreg+1
+       lda     (ptr1),y
+       dey
+       sta     sreg
+       lda     (ptr1),y
+       dey
+       tax
+       lda     (ptr1),y
+       rts
+
diff --git a/libsrc/runtime/ldec.s b/libsrc/runtime/ldec.s
new file mode 100644 (file)
index 0000000..404019b
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Decrement eax by value in Y
+;
+
+               .export         deceaxy
+       .importzp       ptr4, sreg
+
+deceaxy:
+       sty     ptr4
+       sec
+       sbc     ptr4
+       sta     ptr4
+       txa
+       sbc     #0
+       tax
+       lda     sreg
+       sbc     #0
+       sta     sreg
+       lda     sreg+1
+       sbc     #0
+       sta     sreg+1
+       lda     ptr4
+       rts
+
diff --git a/libsrc/runtime/ldiv.s b/libsrc/runtime/ldiv.s
new file mode 100644 (file)
index 0000000..f08354d
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: division for signed long ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $80000000, in which case the negate will fail.
+
+               .export         tosdiveax
+       .import         poplsargs, udiv32, adjlsres
+       .importzp       ptr1
+
+tosdiveax:
+               jsr     poplsargs       ; Get arguments from stack, adjust sign
+               jsr     udiv32          ; Do the division
+       lda     ptr1            ; Result is in (ptr1:sreg)
+       ldx     ptr1+1
+       jmp     adjlsres        ; Adjust the sign of the result if needed
+
diff --git a/libsrc/runtime/le.s b/libsrc/runtime/le.s
new file mode 100644 (file)
index 0000000..a615b3f
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare <= for signed ints
+;
+
+       .export         tosle00, toslea0, tosleax
+               .import         tosicmp, boolle
+
+tosle00:
+       lda     #$00
+toslea0:
+       ldx     #$00
+tosleax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolle          ; Convert to boolean
+
diff --git a/libsrc/runtime/leave.s b/libsrc/runtime/leave.s
new file mode 100644 (file)
index 0000000..4846b9e
--- /dev/null
@@ -0,0 +1,37 @@
+;  
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: function epilogue
+;
+
+; exit a function.  pop stack and rts. The function comes in different
+; flavours that provide default values for the return val, or drop a local
+; stack frame with size in y.
+
+       .export         leave00, leave0, leavey00, leavey0, leavey
+       .export         leave
+       .import         addysp
+       .importzp       sp
+
+leave00:
+       lda     #0
+leave0:        ldx     #0
+       beq     leave
+
+leavey00:
+       lda     #0              ; "return 0"
+leavey0:
+       ldx     #0              ; return < 256
+leavey:
+       jsr     addysp          ; drop stack frame
+leave: pha                     ; save A a sec
+       ldy     #0
+       lda     (sp),y          ; that's the pushed arg size
+       sec                     ; Count the byte, the count's stored in
+       adc     sp
+       sta     sp
+       bcc     L1
+       inc     sp+1
+L1:    pla                     ; Get return value back
+               rts
+
diff --git a/libsrc/runtime/leaysp.s b/libsrc/runtime/leaysp.s
new file mode 100644 (file)
index 0000000..2e5c161
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 21.08.1998
+;
+; CC65 runtime: Load effective address with offset in Y relative to SP
+;
+
+       .export         lea0sp, leaysp, plea0sp, pleaysp
+       .import         pushax
+       .importzp       sp
+
+lea0sp:        ldy     #0              ; Load offset zero
+leaysp:        tya
+       ldx     sp+1            ; Get high byte
+       clc
+       adc     sp
+       bcc     L8
+       inx
+L8:    rts
+
+
+plea0sp:
+       ldy     #0
+pleaysp:
+       tya
+       ldx     sp+1            ; Get high byte
+       clc
+       adc     sp
+       bcc     L9
+       inx
+L9:    jmp     pushax
+
+
+
diff --git a/libsrc/runtime/leq.s b/libsrc/runtime/leq.s
new file mode 100644 (file)
index 0000000..5f8d6d3
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long equal
+;
+
+       .export         toseqeax
+       .import         lcmp, booleq
+
+toseqeax:
+       jsr     lcmp            ; Set flags
+       jmp     booleq          ; Convert to boolean
+
+
+     
diff --git a/libsrc/runtime/lge.s b/libsrc/runtime/lge.s
new file mode 100644 (file)
index 0000000..f98d9fb
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare >= for long ints
+;
+
+       .export         tosgeeax
+               .import         lcmp, boolge
+
+tosgeeax:
+               jsr     lcmp            ; Set the flags
+               jmp     boolge          ; Convert to boolean
+
diff --git a/libsrc/runtime/lgt.s b/libsrc/runtime/lgt.s
new file mode 100644 (file)
index 0000000..de08c47
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare > for long ints
+;
+
+       .export         tosgteax
+       .import         lcmp, boolgt
+
+tosgteax:
+               jsr     lcmp            ; Set the flags
+       jmp     boolgt          ; Convert to boolean
+
+
diff --git a/libsrc/runtime/linc.s b/libsrc/runtime/linc.s
new file mode 100644 (file)
index 0000000..1922a07
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Increment eax by value in Y
+;
+
+               .export         inceaxy
+       .importzp       ptr4, sreg
+
+inceaxy:
+               sty     ptr4
+               clc
+               adc     ptr4
+               bcc     inceax9
+               inx
+               bne     inceax9
+               inc     sreg
+               bne     inceax9
+               inc     sreg+1
+inceax9:
+               rts
+
diff --git a/libsrc/runtime/lle.s b/libsrc/runtime/lle.s
new file mode 100644 (file)
index 0000000..06d6e0a
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare <= for long ints
+;
+
+       .export         tosleeax
+       .import         lcmp, boolle
+
+tosleeax:
+               jsr     lcmp            ; Set the flags
+       jmp     boolle          ; Convert to boolean
+
diff --git a/libsrc/runtime/llt.s b/libsrc/runtime/llt.s
new file mode 100644 (file)
index 0000000..5654212
--- /dev/null
@@ -0,0 +1,12 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare < for long ints
+;
+
+       .export         toslteax
+               .import         lcmp, boollt
+
+toslteax:
+               jsr     lcmp            ; Set the flags
+       jmp     boollt          ; Convert to boolean
diff --git a/libsrc/runtime/lmod.s b/libsrc/runtime/lmod.s
new file mode 100644 (file)
index 0000000..8c62d27
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for long signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+               .export         tosmodeax
+       .import         poplsargs, udiv32, adjlsres
+       .importzp       sreg, ptr1, ptr2, tmp3, tmp4
+
+tosmodeax:
+               jsr     poplsargs       ; Get arguments from stack, adjust sign
+       jsr     udiv32          ; Do the division
+       lda     ptr1            ; Remainder is in (ptr2:tmp3:tmp4)
+       lda     ptr2
+       ldx     ptr2+1
+       ldy     tmp3
+       sty     sreg
+       ldy     tmp4
+       sty     sreg+1
+       jmp     adjlsres        ; Adjust the sign of the result if needed
+
+
diff --git a/libsrc/runtime/lmul.s b/libsrc/runtime/lmul.s
new file mode 100644 (file)
index 0000000..1a909a3
--- /dev/null
@@ -0,0 +1,63 @@
+;
+; Ullrich von Bassewitz, 13.08.1998
+;
+; CC65 runtime: multiplication for long (unsigned) ints
+;
+
+               .export         tosumuleax, tosmuleax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr3, ptr4
+
+tosmuleax:
+tosumuleax:
+mul32: sta     ptr1
+       stx     ptr1+1          ; op2 now in ptr1/sreg
+       ldy     #0
+       lda     (sp),y
+       sta     ptr3
+       iny
+       lda     (sp),y
+       sta     ptr3+1
+       iny
+       lda     (sp),y
+       sta     ptr4
+       iny
+       lda     (sp),y
+       sta     ptr4+1          ; op1 in pre3/ptr4
+               jsr     addysp1         ; Drop TOS
+
+; Do (ptr1:sreg)*(ptr3:ptr4) --> EAX.
+
+       lda     #0
+       sta     tmp4
+       sta     tmp3
+       sta     tmp2
+       ldy     #32
+L0:    lsr     tmp4
+       ror     tmp3
+       ror     tmp2
+       ror     a
+       ror     sreg+1
+       ror     sreg
+       ror     ptr1+1
+       ror     ptr1
+       bcc     L1
+       clc
+       adc     ptr3
+       pha
+       lda     ptr3+1
+       adc     tmp2
+       sta     tmp2
+       lda     ptr4
+       adc     tmp3
+       sta     tmp3
+       lda     ptr4+1
+       adc     tmp4
+       sta     tmp4
+       pla
+L1:    dey
+               bpl     L0
+       lda     ptr1            ; Load the low result word
+       ldx     ptr1+1
+       rts
+
diff --git a/libsrc/runtime/lne.s b/libsrc/runtime/lne.s
new file mode 100644 (file)
index 0000000..d948fc2
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long not equal
+;
+
+       .export         tosneeax
+       .import         lcmp, boolne
+
+tosneeax:
+       jsr     lcmp            ; Set flags
+       jmp     boolne          ; Convert to boolean
+
+
diff --git a/libsrc/runtime/lneg.s b/libsrc/runtime/lneg.s
new file mode 100644 (file)
index 0000000..12b744b
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: negation on longs
+;
+
+;
+; eax = -eax
+;
+       .export         negeax
+       .importzp       sreg
+
+negeax:        clc
+       eor     #$FF
+       adc     #1
+       pha
+       txa
+       eor     #$FF
+       adc     #0
+       tax
+       lda     sreg
+       eor     #$FF
+       adc     #0
+       sta     sreg
+       lda     sreg+1
+       eor     #$FF
+       adc     #0
+       sta     sreg+1
+       pla
+       rts
+
diff --git a/libsrc/runtime/lor.s b/libsrc/runtime/lor.s
new file mode 100644 (file)
index 0000000..62051a2
--- /dev/null
@@ -0,0 +1,30 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: or on longs
+;
+
+       .export         tosoreax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1
+
+tosoreax:
+               ldy     #0
+               ora     (sp),y          ; byte 0
+       sta     tmp1
+       iny
+       txa
+       ora     (sp),y          ; byte 1
+       tax
+       iny
+       lda     sreg
+       ora     (sp),y          ; byte 2
+       sta     sreg
+       iny
+       lda     sreg+1
+       ora     (sp),y          ; byte 3
+       sta     sreg+1
+
+       lda     tmp1
+               jmp     addysp1
+
diff --git a/libsrc/runtime/lpop.s b/libsrc/runtime/lpop.s
new file mode 100644 (file)
index 0000000..ff0d59b
--- /dev/null
@@ -0,0 +1,25 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: long pop
+;
+
+       .export         popeax
+       .import         incsp4
+       .importzp       sp, sreg
+
+
+popeax:        ldy     #3
+       lda     (sp),y
+       sta     sreg+1
+       dey
+       lda     (sp),y
+       sta     sreg
+       dey
+       lda     (sp),y
+       tax
+       dey
+       lda     (sp),y
+       jmp     incsp4
+
+
diff --git a/libsrc/runtime/lpush.s b/libsrc/runtime/lpush.s
new file mode 100644 (file)
index 0000000..7724f49
--- /dev/null
@@ -0,0 +1,34 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: long push
+;
+
+;
+; push eax on stack
+;
+       .export         push0ax, pusheax
+       .import         decsp4
+       .importzp       sp, sreg
+
+push0ax:
+       ldy     #0
+       sty     sreg
+       sty     sreg+1
+pusheax:
+       jsr     decsp4
+       pha
+       ldy     #0
+       sta     (sp),y
+       iny
+       txa
+       sta     (sp),y
+       iny
+       lda     sreg
+       sta     (sp),y
+       iny
+       lda     sreg+1
+       sta     (sp),y
+       pla
+       rts
+
diff --git a/libsrc/runtime/lrsub.s b/libsrc/runtime/lrsub.s
new file mode 100644 (file)
index 0000000..607b7fe
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long sub reversed
+;
+
+;
+; EAX = EAX - TOS
+;
+       .export         tosrsubeax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1
+
+tosrsubeax:
+       ldy     #0
+               sec
+       sbc     (sp),y          ; byte 0
+               sta     tmp1            ; use as temp storage
+       txa
+       iny
+       sbc     (sp),y          ; byte 1
+       tax
+       iny
+       lda     sreg
+       sbc     (sp),y          ; byte 2
+       sta     sreg
+       iny
+       lda     sreg+1
+       sbc     (sp),y          ; byte 3
+       sta     sreg+1
+       lda     tmp1
+               jmp     addysp1         ; drop TOS
+
diff --git a/libsrc/runtime/lruntime.s b/libsrc/runtime/lruntime.s
new file mode 100644 (file)
index 0000000..756c141
--- /dev/null
@@ -0,0 +1,100 @@
+;
+; lruntime.s
+;
+; Ullrich von Bassewitz, 22.06.1998
+;
+
+; Runtime support for longs.
+
+       .import         popax, pusheax, staspic
+       .importzp       sp, sreg, tmp2, ptr1
+
+;
+; leax    (sp),y
+;
+       .export         ldeax0sp, ldeaxysp
+
+ldeax0sp:
+       ldy     #3
+ldeaxysp:
+       lda     (sp),y
+       sta     sreg+1
+       dey
+       lda     (sp),y
+       sta     sreg
+       dey
+       lda     (sp),y
+       tax
+       dey
+       lda     (sp),y
+       rts
+
+;
+; push a long from (sp),y
+;
+       .export         pushlysp
+
+pushlysp:
+       iny
+       iny
+       lda     (sp),y
+       iny
+       sta     sreg
+       lda     (sp),y
+       sta     sreg+1
+       dey
+       dey
+       lda     (sp),y
+       dey
+       tax
+       lda     (sp),y
+       jmp     pusheax
+
+;
+; eax --> ((sp)); pop
+;
+       .export         steaxspp
+
+steaxspp:
+       pha
+       txa
+       pha
+       jsr     popax           ; get address
+       sta     ptr1
+       stx     ptr1+1
+       ldy     #3
+       lda     sreg+1
+       sta     (ptr1),y
+       dey
+       lda     sreg
+       sta     (ptr1),y
+       dey
+       pla
+       tax
+       sta     (ptr1),y
+       dey
+       pla
+       sta     (ptr1),y
+       rts
+
+;
+; eax --> ((sp)),y
+;
+       .export         steaxspidx
+
+steaxspidx:
+       jsr     staspic         ; Get pointer, store a
+       pha
+       iny
+       lda     tmp2
+       sta     (ptr1),y
+       iny
+       tax
+       lda     sreg
+       sta     (ptr1),y
+       iny
+       lda     sreg+1
+       sta     (ptr1),y
+       pla
+       rts
+
diff --git a/libsrc/runtime/lsave.s b/libsrc/runtime/lsave.s
new file mode 100644 (file)
index 0000000..e9ccfc3
--- /dev/null
@@ -0,0 +1,28 @@
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; CC65 runtime: save ax into temp storage/restore ax from temp storage
+;
+
+       .export         saveeax, resteax
+       .importzp       sreg, regsave
+
+saveeax:
+       sta     regsave
+       stx     regsave+1
+       lda     sreg
+       sta     regsave+2
+       lda     sreg+1
+       sta     regsave+3
+       lda     regsave
+       rts
+
+resteax:
+       lda     regsave+3
+       sta     sreg+1
+       lda     regsave+2
+       sta     sreg
+       ldx     regsave+1
+       lda     regsave
+       rts
+
diff --git a/libsrc/runtime/lshelp.s b/libsrc/runtime/lshelp.s
new file mode 100644 (file)
index 0000000..9d8f366
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; Ullrich von Bassewitz, 13.08.1998
+;
+; CC65 runtime: helper stuff for mod/div/mul with long signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $80000000, in which case the negate will fail.
+
+               .export         poplsargs, adjlsres
+       .import         getlop, negeax
+       .importzp       sreg, tmp1, ptr1, ptr3, ptr4
+
+poplsargs:
+       jsr     getlop          ; Get the operands
+
+; Calculate the sign of the result, that is sign(op1) * sign(op2) and
+; remember it.
+
+       lda     sreg+1
+       eor     ptr4+1
+       sta     tmp1            ; Save it across call
+
+; Make both operands positive
+
+       lda     sreg+1          ; Is the operand negative?
+       bpl     L1              ; Jump if not
+
+       clc                     ; Make it positive
+       lda     ptr1
+       eor     #$FF
+       adc     #$01
+       sta     ptr1
+       lda     ptr1+1
+       eor     #$FF
+       adc     #$00
+       sta     ptr1+1
+       lda     sreg
+       eor     #$FF
+       adc     #$00
+       sta     sreg
+       lda     sreg+1
+       eor     #$FF
+       adc     #$00
+       sta     sreg+1
+
+L1:    lda     ptr4+1          ; Is the operand nagative?
+       bpl     L2              ; Jump if not
+
+       clc                     ; Make it positive
+       lda     ptr3
+       eor     #$FF
+       adc     #$01
+       sta     ptr3
+       lda     ptr3+1
+       eor     #$FF
+       adc     #$00
+       sta     ptr3+1
+       lda     ptr4
+       eor     #$FF
+       adc     #$00
+       sta     ptr4
+       lda     ptr4+1
+       eor     #$FF
+       adc     #$00
+       sta     ptr4+1
+
+L2:    rts
+
+; Adjust the result of a mod/div/mul operation
+
+adjlsres:
+       ldy     tmp1            ; Check if we must adjust the sign
+       bpl     L2
+       jmp     negeax          ; Netage value
+
diff --git a/libsrc/runtime/lshl.s b/libsrc/runtime/lshl.s
new file mode 100644 (file)
index 0000000..d481fa6
--- /dev/null
@@ -0,0 +1,95 @@
+;
+; Ullrich von Bassewitz, 20.09.1998
+;
+; CC65 runtime: left shift support for longs
+;
+
+
+       .export         tosasleax, tosshleax
+       .import         addysp1
+       .importzp       sp, sreg, ptr1, ptr2
+
+
+tosshleax:
+tosasleax:
+
+; Get the lhs from stack into ptr1/ptr2
+
+       pha
+       ldy     #0
+       lda     (sp),y
+       sta     ptr1
+       iny
+       lda     (sp),y
+       sta     ptr1+1
+       iny
+       lda     (sp),y
+       sta     ptr2
+       iny
+       lda     (sp),y
+       sta     ptr2+1
+       pla
+               jsr     addysp1
+
+; Check for shift overflow or zero shift
+
+               tay                     ; Low byte of shift count into y
+               txa                     ; Get byte 2
+       ora     sreg
+               ora     sreg+1          ; Check high 24 bit
+       bne     @L6             ; Shift count too large
+       cpy     #32
+       bcs     @L6
+
+       cpy     #0              ; Shift count zero?
+       beq     @L5
+
+; We must shift. Shift by multiples of eight if possible
+
+       tya
+@L1:   cmp     #8
+       bcc     @L3
+       sbc     #8
+               ldx     ptr2
+       stx     ptr2+1
+       ldx     ptr1+1
+       stx     ptr2
+       ldx     ptr1
+       stx     ptr1+1
+       ldx     #0
+       stx     ptr1
+               beq     @L1
+
+; Shift count is now less than eight. Do a real shift.
+
+@L3:   tay                     ; Shift count to Y
+       lda     ptr1            ; Get one byte into A for speed
+       cpy     #0
+               beq     @L4a            ; Jump if done
+@L4:   asl     a
+       rol     ptr1+1
+       rol     ptr2
+       rol     ptr2+1
+       dey
+       bne     @L4
+
+; Put the result in place
+
+@L4a:          ldx     ptr2
+       stx     sreg
+       ldx     ptr2+1
+       stx     sreg+1
+       ldx     ptr1+1
+@L5:   rts
+
+; Jump here if shift count overflow
+
+@L6:   lda     #0
+       sta     sreg+1
+       sta     sreg
+       tax
+       rts
+
+
+
+
diff --git a/libsrc/runtime/lshr.s b/libsrc/runtime/lshr.s
new file mode 100644 (file)
index 0000000..2e3e051
--- /dev/null
@@ -0,0 +1,185 @@
+;
+; Ullrich von Bassewitz, 20.09.1998
+;
+; CC65 runtime: right shift support for longs
+;
+
+
+       .export         tosasreax, tosshreax
+       .import         addysp1
+       .importzp       sp, sreg, ptr1, ptr2
+
+; --------------------------------------------------------------------
+; signed shift
+
+.proc  tosasreax
+
+               jsr     getlhs          ; Get the lhs from the stack
+
+               jsr     checkovf        ; Check for overflow
+       bcs     L6              ; Jump if shift count too large
+
+       cpy     #0              ; Shift count zero?
+       beq     L5
+
+; We must shift. Shift by multiples of eight if possible
+
+       tya
+L1:    cmp     #8
+       bcc     L3
+       sbc     #8
+               ldx     ptr1+1
+       stx     ptr1
+       ldx     ptr2
+       stx     ptr1+1
+       ldy     #0
+       ldx     ptr2+1
+       stx     ptr2
+       bpl     L2
+       dey                     ; Get sign
+L2:    sty     ptr2+1
+       jmp     L1
+
+; Shift count is now less than eight. Do a real shift.
+               
+L3:    tay                     ; Shift count to Y
+       lda     ptr2+1          ; Get one byte into A for speed
+       cpy     #0
+               beq     L4a             ; Jump if done
+L4:    cmp     #$80            ; Get sign bit into C
+       ror     a
+       ror     ptr2
+       ror     ptr1+1
+       ror     ptr1
+       dey
+       bne     L4
+
+; Put the result in place
+
+L4a:   sta     sreg+1
+       lda     ptr2
+       sta     sreg
+       ldx     ptr1+1
+       lda     ptr1
+L5:    rts
+
+; Jump here if shift count overflow
+
+L6:    ldx     #0
+       lda     ptr2+1          ; Check sign
+               bpl     L7
+       dex
+L7:    stx     sreg+1
+       stx     sreg
+       txa
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------
+; unsigned shift
+
+.proc  tosshreax
+
+               jsr     getlhs          ; Get the lhs from the stack
+
+       jsr     checkovf        ; Check for overflow
+               bcs     L6              ; Jump if shift count too large
+
+       cpy     #0              ; Shift count zero?
+       beq     L5
+
+; We must shift. Shift by multiples of eight if possible
+
+       tya
+L1:    cmp     #8
+       bcc     L3
+       sbc     #8
+               ldx     ptr1+1
+       stx     ptr1
+       ldx     ptr2
+       stx     ptr1+1
+       ldx     ptr2+1
+       stx     ptr2
+       ldx     #0
+       stx     ptr2+1
+               beq     L1
+
+; Shift count is now less than eight. Do a real shift.
+
+L3:    tay                     ; Shift count to Y
+       lda     ptr2+1          ; Get one byte into A for speed
+       cpy     #0
+               beq     L4a             ; Jump if done
+L4:    lsr     a
+       ror     ptr2
+       ror     ptr1+1
+       ror     ptr1
+       dey
+       bne     L4
+
+; Put the result in place
+
+L4a:   sta     sreg+1
+       lda     ptr2
+       sta     sreg
+       ldx     ptr1+1
+       lda     ptr1
+L5:    rts
+
+; Jump here if shift count overflow
+
+L6:    lda     #0
+       sta     sreg+1
+       sta     sreg
+       tax
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------
+; Helpers
+
+.proc          getlhs                  ; Get the lhs from stack into ptr1/ptr2
+
+       pha
+       ldy     #0
+       lda     (sp),y
+       sta     ptr1
+       iny
+       lda     (sp),y
+       sta     ptr1+1
+       iny
+       lda     (sp),y
+       sta     ptr2
+       iny
+       lda     (sp),y
+       sta     ptr2+1
+       pla
+               jmp     addysp1
+
+.endproc
+
+
+.proc  checkovf                ; Check for shift overflow
+
+               tay                     ; Low byte of shift count into y
+               txa                     ; Get byte 2
+       ora     sreg
+       ora     sreg+1          ; Check high 24 bit
+       bne     TooLarge        ; Shift count too large
+       cpy     #32
+       bcc     Ok
+TooLarge:
+       sec
+Ok:    rts
+
+.endproc
+
+
+
+
+
+
+
+
diff --git a/libsrc/runtime/lsub.s b/libsrc/runtime/lsub.s
new file mode 100644 (file)
index 0000000..8854e9e
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long sub
+;
+
+;
+; EAX = TOS - EAX
+;
+       .export         tossubeax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1, tmp2
+
+tossubeax:
+       ldy     #0
+               sec
+       sta     tmp1
+       lda     (sp),y
+       sbc     tmp1            ; byte 0
+       sta     tmp2            ; use as temp storage
+       iny
+       stx     tmp1
+       lda     (sp),y
+       sbc     tmp1            ; byte 1
+       tax
+       iny
+       lda     (sp),y
+       sbc     sreg            ; byte 2
+       sta     sreg
+       iny
+       lda     (sp),y
+       sbc     sreg+1          ; byte 3
+       sta     sreg+1
+       lda     tmp2            ; load byte 0
+               jmp     addysp1         ; drop TOS
+
diff --git a/libsrc/runtime/lsubeq.s b/libsrc/runtime/lsubeq.s
new file mode 100644 (file)
index 0000000..974626c
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; Ullrich von Bassewitz, 07.04.2000
+;
+; CC65 runtime: -= operator
+;
+; On entry, the low byte of the address of the variable to decrement is
+; in ptr1, the high byte is in Y, and the decrement is in eax.
+;
+
+               .export         lsubeq1, lsubeqa, lsubeq
+               .importzp       sreg, ptr1, tmp1
+
+
+lsubeq1:
+               lda     #$01
+
+lsubeqa:
+       ldx     #$00
+       stx     sreg
+       stx     sreg+1
+
+lsubeq:        sty     ptr1+1                  ; Store high byte of address
+       ldy     #$00                    ; Address low byte
+       sec
+
+       sta     tmp1
+       lda     (ptr1),y                ; Load byte 0
+       sbc     tmp1
+       sta     (ptr1),y
+               pha                             ; Save byte 0 of result for later
+
+       iny                             ; Address byte 1
+       stx     tmp1
+       lda     (ptr1),y                ; Load byte 1
+       sbc     tmp1
+       sta     (ptr1),y
+       tax
+
+       iny                             ; Address byte 2
+       lda     (ptr1),y
+       sbc     sreg
+       sta     (ptr1),y
+       sta     sreg
+
+       iny                             ; Address byte 3
+       lda     (ptr1),y
+       sbc     sreg+1
+       sta     (ptr1),y
+       sta     sreg+1
+
+       pla                             ; Retrieve byte 0 of result
+
+       rts                             ; Done
+
+
+
+
diff --git a/libsrc/runtime/lsubeqsp.s b/libsrc/runtime/lsubeqsp.s
new file mode 100644 (file)
index 0000000..6474f40
--- /dev/null
@@ -0,0 +1,37 @@
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: -= operator for longs on the stack
+;                          
+
+               .export         lsubeq0sp, lsubeqysp
+       .importzp       sp, sreg, tmp1, tmp2
+
+lsubeq0sp:
+       ldy     #0
+lsubeqysp:
+       sec
+       sta     tmp1
+       stx     tmp2
+               lda     (sp),y
+       sbc     tmp1
+       sta     (sp),y
+       pha
+       iny
+               lda     (sp),y
+       sbc     tmp2
+       sta     (sp),y
+       tax
+       iny
+               lda     (sp),y
+       sbc     sreg
+       sta     (sp),y
+       sta     sreg
+       iny
+               lda     (sp),y
+       sbc     sreg+1
+       sta     (sp),y
+       sta     sreg+1
+       pla
+       rts
+
diff --git a/libsrc/runtime/lswap.s b/libsrc/runtime/lswap.s
new file mode 100644 (file)
index 0000000..0e03cf2
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Exchange lo and hi part of eax
+;
+
+       .export         swapeax
+       .importzp       sreg
+
+swapeax:
+       ldy     sreg
+               sta     sreg
+       lda     sreg+1
+       stx     sreg+1
+       tax
+       tya
+       rts
+
diff --git a/libsrc/runtime/lswitch.s b/libsrc/runtime/lswitch.s
new file mode 100644 (file)
index 0000000..9173b15
--- /dev/null
@@ -0,0 +1,87 @@
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: switch statement with long selector
+;
+
+; Subroutine to handle a switch statement with an int selector. The table
+; is located at the return address from the function. It contains the negative
+; of the case label count as first word, followed by three words for each case
+; label, the first two being the value, and the second one the label to jump
+; to in case of a match. The default case is located at the end of the table.
+
+       .export         lswitch
+       .importzp       sreg, ptr1, ptr2, ptr3
+
+lswitch:
+       sta     ptr1
+               stx     ptr1+1          ; Save AX
+       clc
+       pla
+       adc     #1
+       sta     ptr2
+       pla
+       adc     #0
+       sta     ptr2+1          ; Get pointer to table
+
+       ldy     #0
+       lda     (ptr2),y
+       sta     ptr3
+       iny
+       lda     (ptr2),y
+       sta     ptr3+1          ; Remember the count of labels
+
+       ldy     #0
+       clc                     ; Skip the label count
+       lda     ptr2
+       adc     #2
+       sta     ptr2
+       bcc     L2
+       inc     ptr2+1
+       bne     L2              ; Branch always
+
+; Search for the label
+
+L0:    lda     (ptr2),y
+       cmp     ptr1
+               bne     L1
+       iny
+       lda     (ptr2),y
+       cmp     ptr1+1
+       bne     L1
+       iny
+       lda     (ptr2),y
+       cmp     sreg
+       bne     L1
+       iny
+       lda     (ptr2),y
+       cmp     sreg+1
+       beq     L3
+L1:    clc
+       lda     ptr2
+       adc     #6              ; Skip table entry
+       sta     ptr2
+       bcc     L2
+       inc     ptr2+1
+
+; Check if there are any labels left
+
+L2:    inc     ptr3
+       bne     L0
+       inc     ptr3+1
+       bne     L0
+
+; Out of labels
+
+       jmp     (ptr2)
+
+; Label found
+
+L3:    ldy     #4              ; Jump label offset
+       lda     (ptr2),y
+       sta     ptr3
+       iny
+       lda     (ptr2),y
+       sta     ptr3+1
+       jmp     (ptr3)
+
diff --git a/libsrc/runtime/lt.s b/libsrc/runtime/lt.s
new file mode 100644 (file)
index 0000000..1b681f5
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare < for signed ints
+;
+
+       .export         toslt00, toslta0, tosltax
+               .import         tosicmp, boollt
+
+toslt00:
+       lda     #$00
+toslta0:
+       ldx     #$00
+tosltax:
+       jsr     tosicmp         ; Set flags
+       jmp     boollt          ; Convert to boolean
+
diff --git a/libsrc/runtime/ltest.s b/libsrc/runtime/ltest.s
new file mode 100644 (file)
index 0000000..2c66300
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: test long in eax
+;
+
+               .export         utsteax, tsteax
+       .importzp       sreg, tmp1
+
+tsteax:
+utsteax:
+       tay                     ; Save value
+       stx     tmp1
+       ora     tmp1
+       ora     sreg
+       ora     sreg+1
+       beq     L9
+       tya
+       ldy     #1              ; Force NE
+L9:    rts                               
+
+
diff --git a/libsrc/runtime/ludiv.s b/libsrc/runtime/ludiv.s
new file mode 100644 (file)
index 0000000..1d8dc73
--- /dev/null
@@ -0,0 +1,93 @@
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: division for long unsigned ints
+;
+
+               .export         tosudiveax, getlop, udiv32
+       .import         addysp1
+       .importzp       sp, sreg, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
+
+tosudiveax:
+       jsr     getlop          ; Get the paramameters
+       jsr     udiv32          ; Do the division
+       lda     ptr1            ; Result is in ptr1:sreg
+       ldx     ptr1+1
+       rts
+
+; Pop the parameters for the long division and put it into the relevant
+; memory cells. Called from the signed divisions also.
+
+getlop:        sta     ptr3            ; Put right operand in place
+               stx     ptr3+1
+       lda     sreg
+       sta     ptr4
+       lda     sreg+1
+       sta     ptr4+1
+
+       ldy     #0              ; Put left operand in place
+       lda     (sp),y
+       sta     ptr1
+       iny
+       lda     (sp),y
+       sta     ptr1+1
+       iny
+       lda     (sp),y
+       sta     sreg
+       iny
+       lda     (sp),y
+       sta     sreg+1
+       jmp     addysp1         ; Drop parameters
+
+; Do (ptr1:sreg) / (ptr3:ptr4) --> (ptr1:sreg), remainder in (ptr2:tmp3:tmp4)
+; This is also the entry point for the signed division
+
+udiv32:        lda     #0
+       sta     ptr2+1
+       sta     tmp3
+       sta     tmp4
+;      sta     ptr1+1
+       ldy     #32
+L0:    asl     ptr1
+       rol     ptr1+1
+       rol     sreg
+       rol     sreg+1
+       rol     a
+       rol     ptr2+1
+       rol     tmp3
+       rol     tmp4
+
+; Do a subtraction. we do not have enough space to store the intermediate
+; result, so we may have to do the subtraction twice.
+
+       pha
+       cmp     ptr3
+       lda     ptr2+1
+       sbc     ptr3+1
+       lda     tmp3
+       sbc     ptr4
+       lda     tmp4
+       sbc     ptr4+1
+       bcc     L1
+
+; Overflow, do the subtraction again, this time store the result
+
+       sta     ptr4+1          ; We have the high byte already
+       pla
+       sbc     ptr3            ; byte 0
+       pha
+       lda     ptr2+1
+       sbc     ptr3+1
+       sta     ptr2+1          ; byte 1
+       lda     tmp3
+       sbc     ptr4
+       sta     tmp3            ; byte 2
+       inc     ptr1            ; Set result bit
+
+L1:    pla
+       dey
+       bne     L0
+       sta     ptr2
+       rts
+
+
diff --git a/libsrc/runtime/luge.s b/libsrc/runtime/luge.s
new file mode 100644 (file)
index 0000000..803640c
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare >= for long unsigneds
+;
+
+       .export         tosugeeax
+               .import         lcmp, booluge
+
+tosugeeax:                 
+               jsr     lcmp            ; Set the flags
+               jmp     booluge         ; Convert to boolean
+
diff --git a/libsrc/runtime/lugt.s b/libsrc/runtime/lugt.s
new file mode 100644 (file)
index 0000000..eb47121
--- /dev/null
@@ -0,0 +1,14 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare > for long unsigneds
+;
+
+       .export         tosugteax
+       .import         lcmp, boolugt
+
+tosugteax:                 
+               jsr     lcmp            ; Set the flags
+       jmp     boolugt         ; Convert to boolean
+
+
diff --git a/libsrc/runtime/lule.s b/libsrc/runtime/lule.s
new file mode 100644 (file)
index 0000000..7b080df
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare <= for long unsigneds
+;
+
+       .export         tosuleeax
+       .import         lcmp, boolule
+
+tosuleeax:
+               jsr     lcmp            ; Set the flags
+       jmp     boolule         ; Convert to boolean
+
diff --git a/libsrc/runtime/lult.s b/libsrc/runtime/lult.s
new file mode 100644 (file)
index 0000000..85b8b9a
--- /dev/null
@@ -0,0 +1,12 @@
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare < for long unsigneds
+;
+
+       .export         tosulteax
+               .import         lcmp, boolult
+
+tosulteax:                 
+               jsr     lcmp            ; Set the flags
+       jmp     boolult         ; Convert to boolean
diff --git a/libsrc/runtime/lumod.s b/libsrc/runtime/lumod.s
new file mode 100644 (file)
index 0000000..526db7f
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; CC65 runtime: modulo operation for long unsigned ints
+;
+
+               .export         tosumodeax
+               .import         getlop, udiv32
+               .importzp       sreg, tmp3, tmp4, ptr2
+
+tosumodeax:
+       jsr     getlop          ; Get the paramameters
+       jsr     udiv32          ; Do the division
+       lda     tmp3            ; Remainder is in ptr2:tmp3:tmp4
+       sta     sreg
+       lda     tmp4
+       sta     sreg
+       lda     ptr2
+       ldx     ptr2+1
+       rts
+
diff --git a/libsrc/runtime/lxor.s b/libsrc/runtime/lxor.s
new file mode 100644 (file)
index 0000000..f772ebb
--- /dev/null
@@ -0,0 +1,32 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: xor on longs
+;
+
+       .export         tosxoreax
+       .import         addysp1
+       .importzp       sp, sreg, tmp1
+
+tosxoreax:
+               ldy     #0
+               eor     (sp),y          ; byte 0
+       sta     tmp1
+       iny
+       txa
+       eor     (sp),y          ; byte 1
+       tax
+       iny
+       lda     sreg
+       eor     (sp),y          ; byte 2
+       sta     sreg
+       iny
+       lda     sreg+1
+       eor     (sp),y          ; byte 3
+       sta     sreg+1
+
+       lda     tmp1
+               jmp     addysp1
+
+
+
diff --git a/libsrc/runtime/makebool.s b/libsrc/runtime/makebool.s
new file mode 100644 (file)
index 0000000..3429ff0
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; Ullrich von Bassewitz, 05.10.1998
+;
+; CC65 runtime: Make boolean according to flags
+;
+
+               .export         boolne, booleq, boollt, boolle, boolgt, boolge
+       .export         boolult, boolule, boolugt, booluge
+
+
+boolne:        bne     ret1
+       ldx     #$00
+       txa
+       rts
+
+
+booleq:        beq     ret1
+               ldx     #$00
+               txa
+               rts
+
+
+boolle:        beq     ret1
+boollt:        bmi     ret1
+       ldx     #$00
+       txa
+       rts
+
+
+boolgt: beq    L0
+boolge:        bpl     ret1
+L0:            ldx     #$00
+               txa
+               rts
+
+
+boolule:
+       beq     ret1
+boolult:
+       bcc     ret1
+       ldx     #$00
+       txa
+       rts
+
+
+boolugt:
+       beq     L1
+booluge:
+       bcs     ret1
+L1:    ldx     #$00
+       txa
+       rts
+
+
+ret1:  ldx     #$00
+       lda     #$01
+       rts
+
+
+
diff --git a/libsrc/runtime/mod.s b/libsrc/runtime/mod.s
new file mode 100644 (file)
index 0000000..9e2a73e
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+               .export         tosmoda0, tosmodax
+       .import         popsargs, udiv16, adjsres
+       .importzp       ptr1
+
+tosmoda0:
+       ldx     #0
+tosmodax:
+       jsr     popsargs        ; Get arguments from stack, adjust sign
+       jsr     udiv16          ; Do the division
+       lda     ptr1            ; Result is in sreg, remainder in ptr1
+       ldx     ptr1+1
+       jmp     adjsres         ; Adjust the sign of the result if needed
+
+
diff --git a/libsrc/runtime/mul.s b/libsrc/runtime/mul.s
new file mode 100644 (file)
index 0000000..67caf52
--- /dev/null
@@ -0,0 +1,43 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: multiplication for ints
+;
+
+               .export         tosumula0, tosumulax, tosmula0, tosmulax
+       .import         popsreg
+       .importzp       sreg, tmp1, ptr4
+
+tosmula0:
+tosumula0:
+       ldx     #0
+tosmulax:
+tosumulax:
+mul16: sta     ptr4
+       stx     ptr4+1          ; Save right operand
+       jsr     popsreg         ; Get left operand
+
+; Do ptr4*sreg --> AX (see mult-div.s from "The Fridge").
+
+       lda     #0
+       sta     tmp1
+       ldx     sreg+1          ; Get into register for speed
+       ldy     #16             ; Number of bits
+L0:    lsr     tmp1
+       ror     a
+       ror     ptr4+1
+       ror     ptr4
+       bcc     L1
+       clc
+       adc     sreg
+       pha
+               txa                     ; hi byte of left op
+       adc     tmp1
+       sta     tmp1
+       pla
+L1:    dey
+               bpl     L0
+       lda     ptr4            ; Load the result
+       ldx     ptr4+1
+       rts                     ; Done
+
diff --git a/libsrc/runtime/ne.s b/libsrc/runtime/ne.s
new file mode 100644 (file)
index 0000000..ce9b817
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare != for ints
+;
+
+       .export         tosne00, tosnea0, tosneax
+       .import         tosicmp, boolne
+
+tosne00:
+       lda     #$00
+tosnea0:
+       ldx     #$00
+tosneax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolne          ; Convert to boolean
+
+
diff --git a/libsrc/runtime/neg.s b/libsrc/runtime/neg.s
new file mode 100644 (file)
index 0000000..62807c7
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: negation on ints
+;
+
+       .export         negax
+
+negax: clc
+       eor     #$FF
+       adc     #1
+       pha
+       txa
+       eor     #$FF
+       adc     #0
+       tax
+       pla
+       rts
+
+
+
diff --git a/libsrc/runtime/or.s b/libsrc/runtime/or.s
new file mode 100644 (file)
index 0000000..f953549
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: or on ints
+;
+
+               .export         tosora0, tosorax
+       .import         addysp1
+       .importzp       sp, tmp1
+
+tosora0:
+       ldx     #$00
+tosorax:
+       ldy     #0
+               ora     (sp),y
+       sta     tmp1
+       iny
+       txa
+       ora     (sp),y
+       tax
+       lda     tmp1
+       jmp     addysp1         ; drop TOS, set condition codes
+
diff --git a/libsrc/runtime/popsreg.s b/libsrc/runtime/popsreg.s
new file mode 100644 (file)
index 0000000..a79f9dc
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 21.08.1998
+;
+; CC65 runtime: Pop TOS into sreg
+;
+
+       .export         popsreg
+       .import         incsp2
+               .importzp       sp, sreg
+
+popsreg:
+       pha                     ; save A
+       ldy     #0
+       lda     (sp),y          ; get lo byte
+       sta     sreg            ; store it
+       iny
+       lda     (sp),y          ; get hi byte
+       sta     sreg+1          ; store it
+       pla                     ; get A back
+       jmp     incsp2          ; bump stack and return
+
+
diff --git a/libsrc/runtime/push.s b/libsrc/runtime/push.s
new file mode 100644 (file)
index 0000000..0f2ff3c
--- /dev/null
@@ -0,0 +1,83 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: Push ints onto the stack
+;
+
+;
+; push/pop things on stack
+;
+       .export         push0, push1, push2, push3, push4, push5
+       .export         push6, push7, pusha0, pushaFF, pushax
+       .export         pusha, pushaysp, pushc0, pushc1, pushc2
+       .importzp       sp
+
+pushaFF:
+       ldx     #$FF
+       bne     pushax
+
+push7: lda     #7
+       bne     pusha0
+push6: lda     #6
+       bne     pusha0
+push5: lda     #5
+       bne     pusha0
+push4: lda     #4
+       bne     pusha0
+push3: lda     #3
+       bne     pusha0
+push2: lda     #2
+       bne     pusha0
+push1: lda     #1
+       bne     pusha0
+push0: lda     #0
+;      beq     pusha0
+pusha0:        ldx     #0
+
+; This function is used *a lot*, so don't call any subroutines here.
+; Beware: The value in ax must not be changed by this function!
+; Beware^2: The optimizer knows about the value of Y after the function
+;           returns!
+
+pushax:        ldy     sp
+               beq     @L1
+               dey
+               beq     @L2
+               dey
+@L0:   sty     sp
+       ldy     #0              ; get index
+       sta     (sp),y          ; store lo byte
+       pha                     ; save it
+       txa                     ; get hi byte
+       iny                     ; bump idx
+       sta     (sp),y          ; store hi byte
+       pla                     ; get A back
+       rts                     ; done
+
+@L1:   dey
+@L2:   dey
+       dec     sp+1
+       bne     @L0             ; Branch always
+
+; Push for chars, same warning as above: The optimizer expects the value
+; 0 in the Y register after this function.
+
+pushc2:        lda     #2
+       bne     pusha
+pushc1:        lda     #1
+       bne     pusha
+pushc0:        lda     #0
+       beq     pusha
+pushaysp:           
+       lda     (sp),y
+pusha: ldy     sp
+               beq     @L1
+       dec     sp
+       ldy     #0
+       sta     (sp),y
+       rts
+
+@L1:   dec     sp+1
+       dec     sp
+       sta     (sp),y
+       rts
diff --git a/libsrc/runtime/pushb.s b/libsrc/runtime/pushb.s
new file mode 100644 (file)
index 0000000..a0b37fa
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Push word from stack
+;
+
+               .export         pushb, pushbidx
+       .import         pushax
+       .importzp       ptr1                          
+
+pushbidx:
+       sty     ptr1
+       clc
+       adc     ptr1
+       bcc     pushb
+       inx
+pushb: sta     ptr1
+       stx     ptr1+1
+       ldx     #0              ; Load index/high byte
+       lda     (ptr1,x)
+       bpl     L1
+       dex                     ; Make high byte FF
+L1:    jmp     pushax
+
diff --git a/libsrc/runtime/pushbsp.s b/libsrc/runtime/pushbsp.s
new file mode 100644 (file)
index 0000000..2ae0625
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from stack slot and push as word
+;
+
+       .export         pushbsp, pushbysp
+       .import         pusha0
+       .importzp       sp
+
+pushbsp:
+       ldy     #0
+pushbysp:
+       lda     (sp),y          ; get lo byte
+               jmp     pusha0          ; promote to unsigned and push
+
+
diff --git a/libsrc/runtime/pushw.s b/libsrc/runtime/pushw.s
new file mode 100644 (file)
index 0000000..a560bef
--- /dev/null
@@ -0,0 +1,25 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Push word from stack
+;
+
+       .export         pushw, pushwidx
+       .import         pushax
+       .importzp       ptr1
+
+pushwidx:
+       sty     ptr1
+       clc
+       adc     ptr1
+       bcc     pushw
+       inx
+pushw: sta     ptr1
+       stx     ptr1+1
+       ldy     #1
+       lda     (ptr1),y
+       tax
+       dey
+       lda     (ptr1),y
+       jmp     pushax
+
diff --git a/libsrc/runtime/pushwsp.s b/libsrc/runtime/pushwsp.s
new file mode 100644 (file)
index 0000000..1c940e0
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load word from stack slot and push
+;
+
+               .export         pushwysp, pushw0sp
+       .import         pushax
+       .importzp       sp
+
+pushw0sp:
+       ldy     #1
+pushwysp:
+       lda     (sp),y          ; get hi byte
+       tax
+       dey
+       lda     (sp),y          ; get lo byte
+               jmp     pushax          ; push that
+
+
diff --git a/libsrc/runtime/rsub.s b/libsrc/runtime/rsub.s
new file mode 100644 (file)
index 0000000..2b722e0
--- /dev/null
@@ -0,0 +1,29 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: sub ints reversed
+;
+
+               .export         tosrsuba0, tosrsubax
+       .import         addysp1
+       .importzp       sp, tmp1
+
+;
+; AX = AX - TOS
+;
+
+tosrsuba0:
+       ldx     #0
+tosrsubax:
+       ldy     #0
+       sec
+       sbc     (sp),y          ; lo byte
+       sta     tmp1            ; save lo byte
+       txa
+       iny
+       sbc     (sp),y          ; hi byte
+       tax
+       lda     tmp1
+       jmp     addysp1         ; drop TOS, set condition codes
+
+
diff --git a/libsrc/runtime/runtime.s b/libsrc/runtime/runtime.s
new file mode 100644 (file)
index 0000000..095da25
--- /dev/null
@@ -0,0 +1,265 @@
+;
+; Runtime code for cc65.
+;
+
+
+       .import         ldai, ldaxi, pushax
+       .importzp       sp, tmp1, tmp2, tmp3, ptr1, ptr4
+
+
+; Pop a from stack
+       .export         popa
+
+popa:  ldy     #0
+       lda     (sp),y          ; Read byte
+       inc     sp
+       bne     *+4
+       inc     sp+1
+       rts
+
+;
+; pop a from stack and load x with zero
+;
+
+       .export         popa0
+
+popa0: ldy     #0
+       lda     (sp),y          ; load low byte
+       ldx     #0
+       beq     incsp2
+
+;
+; pop a/x from stack. This function will run directly into incsp2
+;
+
+       .export         popax           ; pop stack into AX
+
+popax: ldy     #1
+       lda     (sp),y          ; get hi byte
+               tax                     ; into x
+       dey
+       lda     (sp),y          ; get lo byte
+
+;
+; routines for inc/dec'ing sp
+;
+
+       .export         addysp, addysp1
+               .export         incsp1, incsp2, incsp3, incsp4
+       .export         incsp5, incsp6, incsp7, incsp8
+
+; do this by hand, cause it gets used a lot
+
+incsp2:        ldy     sp              ; 3
+               iny                     ; 2
+               beq     @L1             ; 2
+               iny                     ; 2
+               beq     @L2             ; 2
+               sty     sp              ; 3
+               rts
+
+@L1:           iny                     ; 2
+@L2:           sty     sp              ; 3
+               inc     sp+1            ; 5
+               rts
+
+; Hand optimize this one also...
+
+incsp1:        inc     sp
+       bne     *+4
+       inc     sp+1
+       rts
+
+incsp3:        ldy     #3
+       bne     addysp
+
+incsp4:        ldy     #4
+       bne     addysp
+
+incsp5:        ldy     #5
+       bne     addysp
+
+incsp6:        ldy     #6
+       bne     addysp
+
+incsp7:        ldy     #7
+       bne     addysp
+
+incsp8:        ldy     #8
+       bne     addysp
+
+addysp1:
+       iny
+addysp:        pha                     ; save A
+       clc
+       tya                     ; get the value
+       adc     sp              ; add lo byte
+       sta     sp              ; put it back
+       bcc     addysp_1        ; if no carry, we're done
+       inc     sp+1            ; inc hi byte
+addysp_1:
+       pla                     ; get A back
+       rts
+
+
+;
+;
+       .export         subysp          ; sub Y from SP
+       .export         decsp1, decsp2, decsp3, decsp4
+       .export         decsp5, decsp6, decsp7, decsp8
+
+; Do this one by hand, cause it gets used a lot
+
+decsp2:        ldy     sp
+               beq     @L1
+               dey
+               beq     @L2
+               dey
+               sty     sp
+               rts
+
+@L1:   dey
+@L2:    dey
+               sty     sp
+               dec     sp+1
+       rts
+
+; Decrement by 1 also done as fast as possible
+
+decsp1:        ldy     sp
+       bne     *+4
+       dec     sp+1
+       dec     sp
+       rts
+
+decsp3:        ldy     #3
+       bne     subysp
+
+decsp4:        ldy     #4
+       bne     subysp
+
+decsp5:        ldy     #5
+       bne     subysp
+
+decsp6:        ldy     #6
+       bne     subysp
+
+decsp7:        ldy     #7
+       bne     subysp
+
+decsp8:        ldy     #8
+;      bne     subysp
+
+subysp:        pha                     ; save A
+               sty     tmp1            ; save the value
+       lda     sp              ; get lo byte
+       sec
+       sbc     tmp1            ; sub y val
+       sta     sp              ; put it back
+       bcs     *+4
+       dec     sp+1
+       pla                     ; get A back
+       rts                     ; done
+
+;
+; Various kinds of store operators
+;
+; store AX at SP@@(Y)
+
+       .export         staxspidx, staspidx, staspic
+staxspidx:
+       jsr     staspic         ; use common part
+       pha
+       iny
+       lda     tmp2
+       sta     (ptr4),y
+       tax
+       pla
+       rts
+staspidx:
+       jsr     staspic         ; use common part
+       ldx     tmp2
+       rts
+
+staspic:
+       sta     tmp1
+       stx     tmp2
+       sty     tmp3
+       jsr     popax           ; get the pointer
+       sta     ptr4
+       stx     ptr4+1
+       ldy     tmp3
+       lda     tmp1
+       sta     (ptr4),y
+       rts
+
+; ax --> (sp),y
+
+
+       .export         staxspp         ; store AX thru (sp), and pop
+staxspp:
+       ldy     #0
+       pha
+       lda     (sp),y
+       sta     ptr1
+       iny
+       lda     (sp),y
+       sta     ptr1+1
+       txa
+       sta     (ptr1),y
+       pla
+       dey
+       sta     (ptr1),y
+       jmp     incsp2          ; Drop address
+
+
+       .export         staspp          ; store A thru (sp), and pop
+staspp:
+       ldy     #1
+       pha
+       lda     (sp),y
+       sta     ptr1+1
+       dey
+       lda     (sp),y
+       sta     ptr1
+       pla
+       sta     (ptr1),y
+               jmp     incsp2          ; Drop address
+
+
+;
+; Boolean function return entries.
+;
+
+       .export         return0, return1
+
+return1:
+       ldx     #0
+       lda     #1
+       rts
+
+return0:
+       lda     #0
+       tax
+       rts
+
+;
+; random stuff
+;
+
+; (a/x) 16--> (--sp)
+
+       .export         pushwaxi
+pushwaxi:                              ; push word at (ax)
+       jsr     ldaxi
+       jmp     pushax
+
+; (a/x) 8--> (--sp)
+
+       .export         pushbaxi        ; push byte at (ax)
+pushbaxi:
+       jsr     ldai
+       jmp     pushax
+
+
+
diff --git a/libsrc/runtime/shelp.s b/libsrc/runtime/shelp.s
new file mode 100644 (file)
index 0000000..631ff47
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: helper stuff for mod/div/mul with signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+               .export         popsargs, adjsres
+       .import         negax, popax
+       .importzp       sreg, tmp1, tmp2, ptr4
+
+popsargs:
+       stx     tmp1            ; Remember sign
+       cpx     #0
+       bpl     L1
+       jsr     negax           ; Negate accumulator
+L1:    sta     ptr4
+       stx     ptr4+1          ; Save right operand
+
+       jsr     popax
+       stx     tmp2            ; Remember sign
+       cpx     #0
+       bpl     L2
+       jsr     negax
+L2:    sta     sreg
+       stx     sreg+1
+
+; Calculate the sign of the result, that is sign(op1) * sign(op2)
+
+       lda     tmp1
+       eor     tmp2
+       sta     tmp2            ; Save it across call
+L3:    rts
+
+; Adjust the result of a mod/div/mul operation
+
+adjsres:
+
+; Check if we must adjust the sign
+
+       ldy     tmp2
+       bpl     L3
+       jmp     negax           ; Adjust sign
+
+
+
diff --git a/libsrc/runtime/shl.s b/libsrc/runtime/shl.s
new file mode 100644 (file)
index 0000000..73f4831
--- /dev/null
@@ -0,0 +1,69 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: left shift support for ints
+;
+
+       .export         tosasla0, tosaslax, tosshla0, tosshlax
+       .import         popsreg, return0
+       .importzp       sreg
+
+tosshla0:
+tosasla0:
+       ldx     #0
+tosshlax:
+tosaslax:
+       jsr     popsreg         ; get TOS into sreg
+       cpx     #0
+       bne     TooLarge
+       cmp     #16
+       bcs     TooLarge
+
+               cmp     #8              ; Shift count greater 8?
+       beq     L3              ; Jump if exactly 8
+               bcc     L1              ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+       ldy     sreg
+       sty     sreg+1
+               stx     sreg            ; Low byte = 0
+       sec
+       sbc     #8
+
+; Shift count less than 8 if we come here
+
+L1:    tay                     ; Shift count --> Y
+       beq     Zero            ; Done if shift count zero
+
+       lda     sreg            ; get low byte for faster shift
+
+; Do the actual shift
+
+L2:            asl     a
+       rol     sreg+1
+       dey
+               bne     L2
+
+; Done with shift
+
+       ldx     sreg+1
+       rts
+
+; Shift count == 8
+
+L3:    txa                     ; X == 0, now A == 0
+       ldx     sreg
+       rts
+
+; Shift count was zero
+
+Zero:  lda     sreg
+       ldx     sreg+1
+       rts
+
+; Shift count too large, result is zero
+
+TooLarge:
+       jmp     return0
+
diff --git a/libsrc/runtime/shr.s b/libsrc/runtime/shr.s
new file mode 100644 (file)
index 0000000..2b51500
--- /dev/null
@@ -0,0 +1,127 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: right shift support for ints
+;
+
+
+; --------------------------------------------------------------------
+; signed shift
+
+       .export         tosasra0, tosasrax
+       .import         popsreg, return0
+       .importzp       sreg
+
+tosasra0:
+       ldx     #0
+tosasrax:
+       jsr     popsreg         ; get TOS into sreg
+       cpx     #0
+       bne     TooLarge
+       cmp     #16
+       bcs     TooLarge
+
+               cmp     #8              ; Shift count greater 8?
+       beq     L4              ; Jump if exactly 8
+               bcc     L2              ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+       ldy     #0
+       ldx     sreg+1
+       stx     sreg
+       bpl     L1
+       dey                     ; Create correct sign bits
+L1:    sty     sreg+1
+       sec
+       sbc     #8
+
+; Shift count less than 8 if we come here
+
+L2:    tay                     ; Shift count --> Y
+       beq     Zero            ; Done if shift count zero
+
+       lda     sreg            ; get low byte for faster shift
+       ldx     sreg+1          ; get high byte
+
+; Do the actual shift
+
+L3:    cpx     #$80            ; get bit 7 into carry
+       ror     sreg+1
+       ror     a
+       dey
+               bne     L3
+
+; Done with shift
+
+       ldx     sreg+1
+       rts
+
+; Shift count == 8
+
+L4:    lda     sreg+1          ; X is zero
+       bpl     *+3
+       dex                     ; X == 0xFF
+       rts
+
+; Shift count was zero
+
+Zero:  lda     sreg
+       ldx     sreg+1
+       rts
+
+; Shift count too large, result is zero
+
+TooLarge:
+       jmp     return0
+
+
+; --------------------------------------------------------------------
+; unsigned shift
+
+       .export         tosshra0, tosshrax
+
+tosshra0:
+       ldx     #0
+tosshrax:
+       jsr     popsreg         ; get TOS into sreg
+       cpx     #0
+       bne     TooLarge
+       cmp     #16
+       bcs     TooLarge
+
+               cmp     #8              ; Shift count greater 8?
+       beq     L8              ; Jump if exactly 8
+               bcc     L6              ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+       sbc     #8              ; Carry already set
+       ldy     sreg+1
+       sty     sreg
+               stx     sreg+1          ; High byte = 0
+
+; Shift count less than 8 if we come here
+
+L6:    tay                     ; Shift count --> Y
+       beq     Zero            ; Done if shift count zero
+
+       lda     sreg            ; get low byte for faster shift
+
+; Do the actual shift
+
+L7:            lsr     sreg+1
+       ror     a
+       dey
+               bne     L7
+
+; Done with shift
+
+       ldx     sreg+1
+       rts
+
+; Shift count == 8
+
+L8:    lda     sreg+1          ; X is zero
+       rts
+
diff --git a/libsrc/runtime/shrax1.s b/libsrc/runtime/shrax1.s
new file mode 100644 (file)
index 0000000..f7b6b72
--- /dev/null
@@ -0,0 +1,15 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+       .export         shrax1
+       .importzp       tmp1
+
+shrax1: stx            tmp1
+       lsr     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
diff --git a/libsrc/runtime/shrax2.s b/libsrc/runtime/shrax2.s
new file mode 100644 (file)
index 0000000..074ab8e
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+       .export         shrax2
+       .importzp       tmp1
+
+shrax2: stx    tmp1
+       lsr     tmp1
+       ror     a
+       lsr     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
+
diff --git a/libsrc/runtime/shrax3.s b/libsrc/runtime/shrax3.s
new file mode 100644 (file)
index 0000000..07e1e1f
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+       .export         shrax3
+       .importzp       tmp1
+
+shrax3: stx    tmp1
+       lsr     tmp1
+       ror     a
+       lsr     tmp1
+       ror     a
+       lsr     tmp1
+       ror     a
+       ldx     tmp1
+       rts
+
+
diff --git a/libsrc/runtime/shreax1.s b/libsrc/runtime/shreax1.s
new file mode 100644 (file)
index 0000000..f4d808f
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 2
+;
+
+               .export         shreax1
+       .importzp       sreg, tmp1
+
+shreax1:
+       stx     tmp1
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/shreax2.s b/libsrc/runtime/shreax2.s
new file mode 100644 (file)
index 0000000..1f2a23d
--- /dev/null
@@ -0,0 +1,22 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+       .export         shreax2
+       .importzp       sreg, tmp1
+
+shreax2:
+       stx     tmp1
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/shreax3.s b/libsrc/runtime/shreax3.s
new file mode 100644 (file)
index 0000000..8111253
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+       .export         shreax3
+       .importzp       sreg, tmp1
+
+shreax3:
+       stx     tmp1
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               lsr     sreg+1
+               ror     sreg
+               ror     tmp1
+               ror     a
+               ldx     tmp1
+               rts
+
diff --git a/libsrc/runtime/staxsp.s b/libsrc/runtime/staxsp.s
new file mode 100644 (file)
index 0000000..07828e3
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Store ax at (sp),y
+;
+
+       .export         staxysp, stax0sp
+       .importzp       sp
+
+stax0sp:
+       ldy     #0
+staxysp:
+       sta     (sp),y
+       iny
+       pha
+       txa
+       sta     (sp),y
+       pla
+       rts
+
diff --git a/libsrc/runtime/steaxsp.s b/libsrc/runtime/steaxsp.s
new file mode 100644 (file)
index 0000000..de134e2
--- /dev/null
@@ -0,0 +1,27 @@
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Store eax at (sp),y
+;
+
+       .export         steaxysp, steax0sp
+       .importzp       sp, sreg
+
+steax0sp:
+       ldy     #0
+steaxysp:
+       sta     (sp),y
+       iny
+       pha
+       txa
+       sta     (sp),y
+       iny
+       lda     sreg
+       sta     (sp),y
+       iny
+       lda     sreg+1
+       sta     (sp),y
+       pla
+       rts
+
+
diff --git a/libsrc/runtime/sub.s b/libsrc/runtime/sub.s
new file mode 100644 (file)
index 0000000..9108b27
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: sub ints
+;
+
+               .export         tossuba0, tossubax
+       .import         addysp1         
+       .importzp       sp, ptr1
+
+;
+; AX = TOS - AX
+;
+
+tossuba0:
+       ldx     #0
+tossubax:
+       ldy     #0
+       sta     ptr1
+       stx     ptr1+1
+       lda     (sp),y          ; lo byte
+       sec
+       sbc     ptr1
+       sta     ptr1            ; save lo byte
+       iny
+       lda     (sp),y
+       sbc     ptr1+1
+       tax
+       lda     ptr1
+       jmp     addysp1         ; drop TOS, set condition codes
+
diff --git a/libsrc/runtime/subeqsp.s b/libsrc/runtime/subeqsp.s
new file mode 100644 (file)
index 0000000..a6f7579
--- /dev/null
@@ -0,0 +1,27 @@
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: -= operator for ints on the stack
+;
+
+               .export         subeq0sp, subeqysp
+       .importzp       sp, tmp1, tmp2
+
+subeq0sp:
+       ldy     #0
+subeqysp:
+       sec
+       sta     tmp1
+       stx     tmp2
+       lda     (sp),y
+       sbc     tmp1
+       sta     (sp),y
+       pha
+       iny
+               lda     (sp),y
+       sbc     tmp2
+       sta     (sp),y
+       tax
+       pla
+       rts
+
diff --git a/libsrc/runtime/swap.s b/libsrc/runtime/swap.s
new file mode 100644 (file)
index 0000000..e2f882f
--- /dev/null
@@ -0,0 +1,25 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: swap ax with TOS
+;
+
+       .export         swapstk
+       .importzp       sp, ptr4
+
+swapstk:
+       sta     ptr4
+       stx     ptr4+1
+       ldy     #1              ; index
+       lda     (sp),y
+       tax
+       lda     ptr4+1
+       sta     (sp),y
+       dey
+       lda     (sp),y
+       pha
+       lda     ptr4
+       sta     (sp),y
+       pla
+       rts                     ; whew!
+
diff --git a/libsrc/runtime/switch.s b/libsrc/runtime/switch.s
new file mode 100644 (file)
index 0000000..22dc4b7
--- /dev/null
@@ -0,0 +1,88 @@
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: switch statement with int selector
+;
+
+; Subroutine to handle a switch statement with an int selector. The table
+; is located at the return address from the function. It contains the negative
+; of the case label count as first word, followed by two words for each case
+; label, the first one being the value, and the second one the label to jump
+; to in case of a match. The default case is located at the end of the table.
+
+       .export         switch
+       .importzp       ptr1, ptr2, ptr3
+
+switch:        sta     ptr1
+               stx     ptr1+1          ; Save AX
+       clc
+       pla
+       adc     #1
+       sta     ptr2
+       pla
+       adc     #0
+       sta     ptr2+1          ; Get pointer to table
+
+       ldy     #0
+       lda     (ptr2),y
+       sta     ptr3
+       iny
+       lda     (ptr2),y
+       sta     ptr3+1          ; Remember the count of labels
+
+       ldy     #0
+       clc                     ; Skip the label count
+       lda     ptr2
+       adc     #2
+       sta     ptr2
+       bcc     L2
+       inc     ptr2+1
+       bne     L2              ; Branch always
+
+; Search for the label
+
+L0:    lda     (ptr2),y
+       iny
+       cmp     ptr1
+               beq     L4
+L1:    iny
+       iny
+       iny                     ; Overflow only here
+       bne     L2
+       inc     ptr2+1          ; Bump high byte
+
+; Check if there are any labels left
+
+L2:    inc     ptr3
+       bne     L0
+       inc     ptr3+1
+       bne     L0
+
+; Out of labels
+
+       tya
+       clc
+       adc     ptr2
+       sta     ptr2
+       bcc     L3
+       inc     ptr2+1
+L3:    jmp     (ptr2)
+
+
+; Check high byte
+
+L4:    lda     (ptr2),y
+       cmp     ptr1+1
+               bne     L1
+
+; Label found
+
+       iny
+       lda     (ptr2),y
+       sta     ptr3
+       iny
+       lda     (ptr2),y
+       sta     ptr3+1
+       jmp     (ptr3)
+
+
diff --git a/libsrc/runtime/test.s b/libsrc/runtime/test.s
new file mode 100644 (file)
index 0000000..a1dc396
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: test int in ax
+;
+
+               .export         utsta0, utstax, tsta0, tstax
+
+tsta0:
+utsta0:        ldx     #0
+tstax:
+utstax:        cpx     #0
+       bne     L1
+       cmp     #0
+L1:    rts
+
+  
diff --git a/libsrc/runtime/udiv.s b/libsrc/runtime/udiv.s
new file mode 100644 (file)
index 0000000..e82d5bf
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: division for unsigned ints
+;
+
+               .export         tosudiva0, tosudivax, udiv16
+       .import         popsreg
+       .importzp       sreg, ptr1, ptr4
+
+tosudiva0:
+               ldx     #0
+tosudivax:
+               sta     ptr4
+               stx     ptr4+1          ; Save right operand
+               jsr     popsreg         ; Get left operand
+
+; Do the division
+
+       jsr     udiv16
+
+; Result is in sreg, remainder in ptr1
+
+       lda     sreg
+       ldx     sreg+1
+       rts
+
+; Do (sreg/ptr4) -> sreg (see mult-div.s from "The Fridge").
+; This is also the entry point for the signed division
+
+udiv16:        lda     #0
+       sta     ptr1+1
+       ldy     #16
+L0:    asl     sreg
+       rol     sreg+1
+       rol     a
+       rol     ptr1+1
+       pha
+       cmp     ptr4
+       lda     ptr1+1
+       sbc     ptr4+1
+       bcc     L1
+       sta     ptr1+1
+       pla
+       sbc     ptr4
+       pha
+       inc     sreg
+L1:    pla
+       dey
+       bne     L0
+       sta     ptr1
+       rts
+
+
diff --git a/libsrc/runtime/uge.s b/libsrc/runtime/uge.s
new file mode 100644 (file)
index 0000000..96e9497
--- /dev/null
@@ -0,0 +1,20 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare >= for unsigned ints
+;
+
+               .export         tosuge00, tosugea0, tosugeax
+       .import         tosicmp, booluge
+
+
+tosuge00:
+       lda     #$00
+tosugea0:
+       ldx     #$00
+tosugeax:
+       jsr     tosicmp         ; Set flags
+       jmp     booluge         ; Convert to boolean
+
+
+
diff --git a/libsrc/runtime/ugt.s b/libsrc/runtime/ugt.s
new file mode 100644 (file)
index 0000000..a8befbf
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare > for unsigned ints
+;
+
+               .export         tosugt00, tosugta0, tosugtax
+       .import         tosicmp, boolugt
+
+
+tosugt00:
+       lda     #$00
+tosugta0:
+       ldx     #$00
+tosugtax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolugt         ; Convert to boolean
+
diff --git a/libsrc/runtime/ule.s b/libsrc/runtime/ule.s
new file mode 100644 (file)
index 0000000..5e0817d
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare <= for unsigned ints
+;
+
+       .export         tosule00, tosulea0, tosuleax
+               .import         tosicmp, boolule
+
+tosule00:
+       lda     #$00
+tosulea0:
+       ldx     #$00
+tosuleax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolule         ; Convert to boolean
+
+
diff --git a/libsrc/runtime/ult.s b/libsrc/runtime/ult.s
new file mode 100644 (file)
index 0000000..d2895d0
--- /dev/null
@@ -0,0 +1,18 @@
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare < for unsigned ints
+;
+
+               .export         tosult00, tosulta0, tosultax
+       .import         tosicmp, boolult, return0
+
+
+tosult00       = return0       ; This is always false
+
+tosulta0:
+       ldx     #$00
+tosultax:
+       jsr     tosicmp         ; Set flags
+       jmp     boolult         ; Convert to boolean
+
diff --git a/libsrc/runtime/umod.s b/libsrc/runtime/umod.s
new file mode 100644 (file)
index 0000000..b465d90
--- /dev/null
@@ -0,0 +1,28 @@
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for unsigned ints
+;
+
+               .export         tosumoda0, tosumodax
+       .import         popsreg, udiv16
+       .importzp       ptr1, ptr4
+
+tosumoda0:
+               ldx     #0
+tosumodax:
+               sta     ptr4
+               stx     ptr4+1          ; Save right operand
+               jsr     popsreg         ; Get right operand
+
+; Do the division
+
+               jsr     udiv16
+
+; Result is in sreg, remainder in ptr1
+
+               lda     ptr1
+               ldx     ptr1+1
+               rts
+
+          
diff --git a/libsrc/runtime/xor.s b/libsrc/runtime/xor.s
new file mode 100644 (file)
index 0000000..9027cb1
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: xor on ints
+;
+
+       .export         tosxora0, tosxorax
+       .import         addysp1
+       .importzp       sp, tmp1
+
+tosxora0:
+       ldx     #$00
+tosxorax:
+       ldy     #0
+               eor     (sp),y
+       sta     tmp1
+       iny
+       txa
+       eor     (sp),y
+       tax
+       lda     tmp1
+       jmp     addysp1         ; drop TOS, set condition codes
+
diff --git a/samples/.cvsignore b/samples/.cvsignore
new file mode 100644 (file)
index 0000000..65f1ae9
--- /dev/null
@@ -0,0 +1,7 @@
+nachtm
+hello
+sieve
+*.map
+*.d64
+*.s
+*.lbl
diff --git a/samples/Makefile b/samples/Makefile
new file mode 100644 (file)
index 0000000..72074e8
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Makefile for cc65 samples
+#
+
+# Enter the target system here
+SYS    = c64
+
+CRT0   = ../lib/$(SYS).o
+CLIB   = ../lib/$(SYS).lib
+CC     = ../cc65/cc65
+CL     = ../cl65/cl65
+AS     = ../binutils/ca65/ca65
+LD     = ../binutils/ld65/ld65
+C1541          = c1541
+
+
+.c.o:
+       @echo $<
+       @$(CL) -c -Oirs -t $(SYS) -I../include/ $<
+
+.s.o:
+       @echo $<
+       @$(CL) -c $(basename $<).s
+
+
+.PHONY:        all
+all:           nachtm hello sieve
+
+nachtm:        $(CRT0) nachtm.o $(CLIB)
+       @$(LD) -t $(SYS) -m nachtm.map -Ln nachtm.lbl -o $@ $^
+
+hello:         $(CRT0) hello.o $(CLIB)
+       @$(LD) -t $(SYS) -m hello.map -Ln hello.lbl -o $@ $^
+
+sieve:         $(CRT0) sieve.o $(CLIB)
+       @$(LD) -t $(SYS) -m sieve.map -Ln sieve.lbl -o $@ $^
+
+.PHONY:        disk
+disk:  c64.d64
+
+c64.d64:       all
+       $(C1541) < c1541.rsp
+
+.PHONY:        clean
+clean:
+       rm -f *~ *.map *.o *.s *.lbl
+
+.PHONY:        zap
+zap:   clean
+       rm -f nachtm hello
+
+
+
+
diff --git a/samples/c1541.rsp b/samples/c1541.rsp
new file mode 100644 (file)
index 0000000..0c46dec
--- /dev/null
@@ -0,0 +1,9 @@
+att c64.d64
+
+delete nachtm
+delete hello
+write nachtm
+write hello
+quit
+
+
diff --git a/samples/hello.c b/samples/hello.c
new file mode 100644 (file)
index 0000000..cdbfab7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Fancy hello world program using cc65.
+ *
+ * Ullrich von Bassewitz (ullrich@von-bassewitz.de)
+ *
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+static const char Text [] = "Hello world!";
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int main (void)
+{
+    unsigned char XSize, YSize;
+
+    /* Set screen colors, hide the cursor */
+    textcolor (COLOR_WHITE);
+    bordercolor (COLOR_BLACK);
+    bgcolor (COLOR_BLACK);
+    cursor (0);
+
+    /* Clear the screen, put cursor in upper left corner */
+    clrscr ();
+
+    /* Ask for the screen size */
+    screensize (&XSize, &YSize);
+
+    /* Draw a border around the screen */
+
+    /* Top line */
+    cputc (CH_ULCORNER);
+    chline (XSize - 2);
+    cputc (CH_URCORNER);
+
+    /* Vertical line, left side */
+    cvlinexy (0, 1, YSize - 2);
+
+    /* Bottom line */
+    cputc (CH_LLCORNER);
+    chline (XSize - 2);
+    cputc (CH_LRCORNER);
+
+    /* Vertical line, right side */
+    cvlinexy (XSize - 1, 1, YSize - 2);
+
+    /* Write the greeting in the mid of the screen */
+    gotoxy ((XSize - strlen (Text)) / 2, YSize / 2);
+    cprintf ("%s", Text);
+
+    /* Wait for the user to press a key */
+    (void) cgetc ();
+
+    /* Clear the screen again */
+    clrscr ();
+
+    /* Done */
+    return EXIT_SUCCESS;
+}
+
+
+
diff --git a/samples/nachtm.c b/samples/nachtm.c
new file mode 100644 (file)
index 0000000..816aa9f
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * "Eine kleine Nachtmusik" by Wolfgang Amadeus Mozart, KV 525
+ *
+ * First version in 1987 by
+ *   Joachim von Bassewitz (joachim@von-bassewitz.de) and
+ *   Ullrich von Bassewitz (ullrich@von-bassewitz.de).
+ *
+ * C conversion in 1998 by
+ *   Ullrich von Bassewitz (ullrich@von-bassewitz.de)
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <time.h>
+#include <conio.h>
+#include <cbm.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Tables with voice data.
+ *
+ *  Bit            Description
+ * -------------------------------------------
+ *  15     Pause bit.
+ *  12-14   Octave
+ *  8-11    Tone (index into frequency table)
+ *  7       Unused. Was thought as a control bit in the original version to
+ *          change SID parameters, but this was never implemented.
+ *  0-6     Length of the tone in ticks.
+ *
+ */
+
+
+
+static int Voice1 [] = {
+    0x5708,0x8004,0x5204,0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,
+    0x6208,0x8008,0x6008,0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,
+    0x5604,0x5904,0x5208,0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5904,0x5704,0x5704,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+    0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,
+    0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,
+    0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,
+    0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,
+    0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,
+    0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,
+    0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,
+    0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,
+    0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,
+    0x4701,0x4701,0x4701,0x4701,0x4601,0x4601,0x4601,0x4601,0x4401,0x4401,
+    0x4401,0x4401,0x4604,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,
+    0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4704,
+    0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B04,0x4B01,0x4B01,0x4901,0x4B01,
+    0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,0x5408,0x5608,0x5708,0x5908,
+    0x5B08,0x6108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,
+    0x6101,0x5902,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,
+    0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6204,0x6208,0x6208,0x6208,
+    0x6201,0x6201,0x6201,0x6201,0x6204,0x6208,0x6208,0x6208,0x6204,0x6104,
+    0x5904,0x6204,0x5904,0x6004,0x5904,0x6204,0x5904,0x6104,0x4904,0x4904,
+    0x4904,0x4908,0x8008,0x590A,0x5702,0x5602,0x5402,0x5204,0x8004,0x5B04,
+    0x8004,0x5704,0x8004,0x5404,0x8004,0x5B04,0x800C,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5201,
+    0x5201,0x5101,0x5101,0x4B04,0x8004,0x5704,0x8004,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5408,0x8008,0x5901,0x5901,0x5901,0x5901,0x5901,
+    0x5901,0x5901,0x5901,0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5401,
+    0x5401,0x5204,0x8004,0x5B04,0x8004,0x5704,0x8004,0x5404,0x8004,0x5908,
+    0x8004,0x5704,0x6104,0x6204,0x8004,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5904,0x8004,0x5104,0x5208,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,
+    0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,
+    0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x6204,0x6104,0x5B04,
+    0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,
+    0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,
+    0x5901,0x5701,0x5701,0x5601,0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,
+    0x5601,0x5601,0x5401,0x5401,0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x6101,0x6101,0x6201,0x6201,0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5904,0x5604,0x5904,0x5901,0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,
+    0x5208,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,
+    0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5904,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,
+    0x6101,0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,
+    0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,
+    0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,
+    0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,
+    0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,0x5204,0x4904,0x4B04,0x5104,
+    0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5201,0x5201,0x5401,0x5401,
+    0x5604,0x5104,0x5204,0x5404,0x5604,0x5604,0x5701,0x5701,0x5701,0x5701,
+    0x5601,0x5601,0x5701,0x5701,0x5904,0x5904,0x5A04,0x5802,0x5A02,0x5B08,
+    0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x5404,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,
+    0x5101,0x5101,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,
+    0x6204,0x8004,0x6604,0x8004,0x6204,0x800C,0x5708,0x8004,0x5204,0x5708,
+    0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x8008,0x6008,0x8004,
+    0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,0x5904,0x5208,0x8008,
+    0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,0x5704,
+    0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5901,0x5901,
+    0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,
+    0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+    0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,
+    0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5701,0x5701,0x5902,
+    0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x6001,0x6001,
+    0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5008,
+    0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,0x4701,0x4701,0x4701,0x4604,
+    0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,0x4B04,0x800C,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,0x5201,0x5201,0x5201,0x5004,
+    0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x4B04,0x4B04,0x4B04,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4701,0x4701,0x4701,0x4701,
+    0x4601,0x4601,0x4601,0x4601,0x4401,0x4401,0x4401,0x4401,0x4604,0x4701,
+    0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,
+    0x4701,0x4701,0x4701,0x4701,0x4701,0x4704,0x4701,0x4701,0x4601,0x4701,
+    0x4901,0x4901,0x4901,0x4901,0x4604,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B04,0x4B01,0x4B01,0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,
+    0x4904,0x5210,0x5408,0x5608,0x5708,0x5908,0x5B08,0x6108,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,0x6101,
+    0x6101,0x6101,0x6101,0x6101,0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,
+    0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,0x6101,0x6101,0x6101,0x6101,
+    0x6101,0x5902,0x6204,0x6208,0x6208,0x6208,0x6201,0x6201,0x6201,0x6201,
+    0x6204,0x6208,0x6208,0x6208,0x6204,0x6104,0x5904,0x6204,0x5904,0x6004,
+    0x5904,0x6204,0x5904,0x6104,0x4904,0x4904,0x4904,0x4908,0x8008,0x590A,
+    0x5702,0x5602,0x5402,0x5204,0x8004,0x5B04,0x8004,0x5704,0x8004,0x5404,
+    0x8004,0x5B04,0x800C,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5401,0x5401,0x5201,0x5201,0x5101,0x5101,0x4B04,
+    0x8004,0x5704,0x8004,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5408,
+    0x8008,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,
+    0x5901,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,0x5204,0x8004,0x5B04,
+    0x8004,0x5704,0x8004,0x5404,0x8004,0x5908,0x8004,0x5704,0x6104,0x6204,
+    0x8004,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5104,0x5208,
+    0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,
+    0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5904,0x8004,0x5904,0x6204,0x6104,0x5B04,0x5904,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,
+    0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,
+    0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,
+    0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,
+    0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,0x5208,0x8004,0x5904,0x6201,
+    0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,
+    0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+    0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+    0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8008,
+    0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5708,0x8008,0x590A,
+    0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,0x5608,0x8008,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,0x6104,0x5B04,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,0x5901,0x5901,0x5901,0x5704,
+    0x5604,0x5404,0x5204,0x4904,0x4B04,0x5104,0x5204,0x5204,0x5401,0x5401,
+    0x5401,0x5401,0x5201,0x5201,0x5401,0x5401,0x5604,0x5104,0x5204,0x5404,
+    0x5604,0x5604,0x5701,0x5701,0x5701,0x5701,0x5601,0x5601,0x5701,0x5701,
+    0x5904,0x5904,0x5A04,0x5802,0x5A02,0x5B08,0x8008,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5404,
+    0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,0x6204,0x8004,0x6604,0x8004,
+    0x6204,0x800C,0x5208,0x8004,0x4904,0x5208,0x8004,0x4904,0x5204,0x4904,
+    0x5204,0x5604,0x5908,0x8008,0x5908,0x8004,0x5604,0x5908,0x8004,0x5604,
+    0x5904,0x5604,0x5304,0x5604,0x4B08,0x8014,0x5704,0x6001,0x6001,0x6001,
+    0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,0x5704,
+    0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,0x5704,0x5704,
+    0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x6001,0x6001,
+    0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,
+    0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,0x5704,
+    0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x6001,
+    0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,
+    0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5804,0x8004,0x5804,0x5804,
+    0x5804,0x5804,0x5804,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+    0x6001,0x6001,0x6001,0x6001,0x5A01,0x5A01,0x5A01,0x5A01,0x5901,0x5901,
+    0x5901,0x5901,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x8004,0x5604,
+    0x5604,0x5604,0x5604,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,
+    0x5304,0x5704,0x5504,0x5304,0x5204,0x5201,0x5201,0x5201,0x5201,0x5104,
+    0x8004,0x5104,0x5104,0x5104,0x5104,0x5104,0x5401,0x5401,0x5401,0x5401,
+    0x5204,0x8004,0x4201,0x4201,0x4201,0x4201,0x4401,0x4401,0x4401,0x4401,
+    0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,
+    0x4901,0x4901,0x5001,0x5001,0x5001,0x5001,0x4A04,0x8004,0x4601,0x4601,
+    0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,0x4901,0x4901,
+    0x4A01,0x4A01,0x4A01,0x4A01,0x5101,0x5101,0x5101,0x5101,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x8004,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,
+    0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,0x5701,0x5701,
+    0x5901,0x5901,0x5901,0x5901,0x5A01,0x5A01,0x5A01,0x5A01,0x5A01,0x5A01,
+    0x5A01,0x5A01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6108,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6210,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5708,0x8004,0x5204,
+    0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x8008,0x6008,
+    0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,0x5904,0x5208,
+    0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,
+    0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+    0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,
+    0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,
+    0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,
+    0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,
+    0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,
+    0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,
+    0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,
+    0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,
+    0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,
+    0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4714,0x4701,0x4701,
+    0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B14,0x4B01,0x4B01,
+    0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,0x5408,0x5608,
+    0x5708,0x5908,0x5B08,0x5108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,
+    0x6101,0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,
+    0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,
+    0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,0x5902,0x6204,0x5904,
+    0x6104,0x5904,0x6204,0x5904,0x6104,0x5904,0x6204,0x4204,0x4204,0x4204,
+    0x4208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,0x8004,
+    0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5204,0x800C,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,
+    0x5701,0x5701,0x5601,0x5601,0x5404,0x8004,0x6004,0x8004,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5908,0x8008,0x8004,0x6204,0x6204,0x6204,
+    0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6201,0x6201,
+    0x6201,0x6201,0x6001,0x6001,0x6001,0x6001,0x5901,0x5901,0x5901,0x5901,
+    0x5604,0x5601,0x5601,0x5601,0x5601,0x5704,0x8004,0x5404,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x8004,0x4604,0x4708,0x8004,0x5204,0x5701,0x5701,
+    0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,
+    0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,
+    0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5704,
+    0x5604,0x5404,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,
+    0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,
+    0x540A,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x5008,0x8008,0x520A,
+    0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4B08,0x8008,0x5401,0x5401,
+    0x5401,0x5401,0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x4B04,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,
+    0x4B04,0x4904,0x4708,0x8004,0x5204,0x5701,0x5701,0x5701,0x5701,0x5601,
+    0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,0x5401,
+    0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5701,0x5701,0x5701,0x5701,
+    0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,0x5401,
+    0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,0x640A,0x6201,0x6201,0x6001,
+    0x6001,0x5B01,0x5B01,0x6008,0x8008,0x620A,0x6001,0x6001,0x5B01,0x5B01,
+    0x5901,0x5901,0x5B08,0x8008,0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,
+    0x5701,0x5701,0x5604,0x5404,0x5204,0x5704,0x5B04,0x6204,0x6201,0x6201,
+    0x6201,0x6201,0x6004,0x5B04,0x5904,0x5704,0x4204,0x4404,0x4604,0x4704,
+    0x4704,0x4901,0x4901,0x4901,0x4901,0x4701,0x4701,0x4901,0x4901,0x4B04,
+    0x4604,0x4704,0x4904,0x4B04,0x4B04,0x5001,0x5001,0x5001,0x5001,0x4B01,
+    0x4B01,0x5001,0x5001,0x5204,0x5204,0x5301,0x5301,0x5301,0x5301,0x5101,
+    0x5101,0x5301,0x5301,0x5408,0x8008,0x440C,0x4904,0x4704,0x4604,0x4404,
+    0x4204,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,
+    0x5001,0x5001,0x5001,0x4B01,0x4B01,0x4B01,0x4B01,0x5201,0x5201,0x5201,
+    0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,0x5001,0x5001,0x5001,0x4B04,
+    0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4904,0x4701,0x4701,0x4701,0x4701,0x4601,0x4601,0x4601,
+    0x4601,0x4401,0x4401,0x4401,0x4401,0x4204,0x5201,0x5201,0x5201,0x5201,
+    0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,
+    0x5701,0x5701,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,0x5401,0x5401,
+    0x5601,0x5601,0x5601,0x5601,0x5704,0x5908,0x8008,0x6208,0x8008,0x5708,
+    0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,0x5204,0x5704,0x5B04,
+    0x6208,0x5608,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,
+    0x5204,0x5704,0x5B04,0x6208,0x5608,0x5708,0x8008,0x5708,0x8008,0x5708,
+    0x4706,0x4702,0x4708,0x8008,0x5208,0x8004,0x4904,0x5208,0x8004,0x4904,
+    0x5204,0x4904,0x5204,0x5604,0x5908,0x8008,0x5908,0x8004,0x5604,0x5908,
+    0x8004,0x5604,0x5904,0x5604,0x5304,0x5604,0x4B08,0x8014,0x5704,0x6001,
+    0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,
+    0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,
+    0x5704,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,
+    0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,
+    0x5901,0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,
+    0x5704,0x5704,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,
+    0x5704,0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,
+    0x5901,0x5901,0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5804,0x8004,
+    0x5804,0x5804,0x5804,0x5804,0x5804,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,
+    0x8004,0x5904,0x6001,0x6001,0x6001,0x6001,0x5A01,0x5A01,0x5A01,0x5A01,
+    0x5901,0x5901,0x5901,0x5901,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,
+    0x8004,0x5604,0x5604,0x5604,0x5604,0x5604,0x5901,0x5901,0x5901,0x5901,
+    0x5704,0x8004,0x5304,0x5704,0x5504,0x5304,0x5204,0x5201,0x5201,0x5201,
+    0x5201,0x5104,0x8004,0x5104,0x5104,0x5104,0x5104,0x5104,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x8004,0x4201,0x4201,0x4201,0x4201,0x4401,0x4401,
+    0x4401,0x4401,0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,
+    0x4901,0x4901,0x4901,0x4901,0x5001,0x5001,0x5001,0x5001,0x4A04,0x8004,
+    0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,
+    0x4901,0x4901,0x4A01,0x4A01,0x4A01,0x4A01,0x5101,0x5101,0x5101,0x5101,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5201,0x5201,0x5201,0x5201,
+    0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,
+    0x5701,0x5701,0x5901,0x5901,0x5901,0x5901,0x5A01,0x5A01,0x5A01,0x5A01,
+    0x5A01,0x5A01,0x5A01,0x5A01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,
+    0x6108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6210,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5708,
+    0x8004,0x5204,0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,
+    0x8008,0x6008,0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,
+    0x5904,0x5208,0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,
+    0x5901,0x5901,0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,
+    0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,
+    0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,
+    0x5901,0x5901,0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,
+    0x6001,0x6001,0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,
+    0x4908,0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,
+    0x4904,0x8004,0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5410,0x5201,0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,
+    0x5001,0x5001,0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,
+    0x4904,0x4904,0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4714,
+    0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B14,
+    0x4B01,0x4B01,0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,
+    0x5408,0x5608,0x5708,0x5908,0x5B08,0x5108,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,
+    0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,
+    0x5101,0x5101,0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+    0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,
+    0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,0x5902,
+    0x6204,0x5904,0x6104,0x5904,0x6204,0x5904,0x6104,0x5904,0x6204,0x4204,
+    0x4204,0x4204,0x4208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,
+    0x4704,0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5204,0x800C,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5404,0x8004,0x6004,0x8004,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+    0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5908,0x8008,0x8004,0x6204,
+    0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,
+    0x6201,0x6201,0x6201,0x6201,0x6001,0x6001,0x6001,0x6001,0x5901,0x5901,
+    0x5901,0x5901,0x5604,0x5601,0x5601,0x5601,0x5601,0x5704,0x8004,0x5404,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x4604,0x4708,0x8004,0x5204,
+    0x5701,0x5701,0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,
+    0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,
+    0x5204,0x5704,0x5604,0x5404,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,
+    0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,
+    0x5204,0x8008,0x540A,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x5008,
+    0x8008,0x520A,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4B08,0x8008,
+    0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x4B04,0x5204,0x5201,0x5201,0x5201,
+    0x5201,0x5004,0x4B04,0x4904,0x4708,0x8004,0x5204,0x5701,0x5701,0x5701,
+    0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,
+    0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5701,0x5701,
+    0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,
+    0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,
+    0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,0x640A,0x6201,
+    0x6201,0x6001,0x6001,0x5B01,0x5B01,0x6008,0x8008,0x620A,0x6001,0x6001,
+    0x5B01,0x5B01,0x5901,0x5901,0x5B08,0x8008,0x5401,0x5401,0x5401,0x5401,
+    0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,0x5204,0x5704,0x5B04,0x6204,
+    0x6201,0x6201,0x6201,0x6201,0x6004,0x5B04,0x5904,0x5704,0x4204,0x4404,
+    0x4604,0x4704,0x4704,0x4901,0x4901,0x4901,0x4901,0x4701,0x4701,0x4901,
+    0x4901,0x4B04,0x4604,0x4704,0x4904,0x4B04,0x4B04,0x5001,0x5001,0x5001,
+    0x5001,0x4B01,0x4B01,0x5001,0x5001,0x5204,0x5204,0x5301,0x5301,0x5301,
+    0x5301,0x5101,0x5101,0x5301,0x5301,0x5408,0x8008,0x440C,0x4904,0x4704,
+    0x4604,0x4404,0x4204,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,
+    0x5101,0x5001,0x5001,0x5001,0x5001,0x4B01,0x4B01,0x4B01,0x4B01,0x5201,
+    0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,0x5001,0x5001,
+    0x5001,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4401,0x4401,0x4904,0x4701,0x4701,0x4701,0x4701,0x4601,
+    0x4601,0x4601,0x4601,0x4401,0x4401,0x4401,0x4401,0x4204,0x5201,0x5201,
+    0x5201,0x5201,0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,
+    0x5701,0x5701,0x5701,0x5701,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,
+    0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5704,0x5908,0x8008,0x6208,
+    0x8008,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,0x5204,
+    0x5704,0x5B04,0x6208,0x5608,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,
+    0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x5608,0x5708,0x8008,0x5708,
+    0x8008,0x5708,0x4706,0x4702,0x4708,0x8008,
+    0x0000
+};
+
+static int Voice2 [] = {
+    0x4708,0x8004,0x4204,0x4708,0x8004,0x4204,0x4704,0x4204,0x4704,0x4B04,
+    0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,0x8004,0x4904,0x5004,0x4904,
+    0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+    0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,
+    0x4901,0x4901,0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4210,0x4210,
+    0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,0x4008,0x3908,0x3208,0x3204,
+    0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,0x3904,0x3904,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,
+    0x4210,0x4410,0x4210,0x4410,0x4604,0x4704,0x4904,0x4704,0x4604,0x4704,
+    0x4904,0x4604,0x4B04,0x4904,0x4704,0x4904,0x4B04,0x4904,0x4804,0x4B04,
+    0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x3904,
+    0x3904,0x3904,0x3908,0x8020,0x4604,0x8004,0x3B04,0x8004,0x4704,0x8004,
+    0x4404,0x8004,0x4104,0x800C,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4204,0x8004,0x4404,0x8004,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4201,0x4108,0x8010,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,
+    0x4101,0x4101,0x4204,0x8004,0x4604,0x8004,0x3B04,0x8004,0x3704,0x8004,
+    0x3408,0x8004,0x4404,0x4704,0x4604,0x8004,0x5704,0x5701,0x5701,0x5701,
+    0x5701,0x5604,0x8004,0x4704,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,
+    0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,
+    0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,
+    0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4604,0x4404,
+    0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,0x4204,0x4104,0x3904,
+    0x3B04,0x4104,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,
+    0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4704,0x4604,0x4204,
+    0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,
+    0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,
+    0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,
+    0x4204,0x4204,0x4604,0x4404,0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,
+    0x4404,0x4204,0x4104,0x3904,0x3B04,0x4104,0x4204,0x5204,0x5204,0x5204,
+    0x5204,0x5204,0x5204,0x5204,0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,
+    0x4904,0x4704,0x4604,0x3904,0x3B04,0x4104,0x4204,0x4204,0x4404,0x4404,
+    0x4604,0x4104,0x4204,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,
+    0x4A04,0x4A04,0x4B08,0x8008,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4201,0x4201,
+    0x4201,0x4201,0x4104,0x5204,0x8004,0x5204,0x8004,0x5204,0x800C,0x4708,
+    0x8004,0x4204,0x4708,0x8004,0x4204,0x4704,0x4204,0x4704,0x4B04,0x5208,
+    0x8008,0x5008,0x8004,0x4904,0x5008,0x8004,0x4904,0x5004,0x4904,0x4604,
+    0x4904,0x4208,0x8008,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x5004,
+    0x4601,0x4601,0x4601,0x4601,0x4904,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,
+    0x4901,0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4210,0x4210,0x4210,
+    0x4208,0x8028,0x3610,0x3710,0x4008,0x4008,0x3908,0x3208,0x3204,0x8004,
+    0x4204,0x8004,0x4208,0x8028,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4710,0x4008,0x4004,0x4004,0x3908,0x3904,0x3904,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4904,
+    0x4904,0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4210,
+    0x4410,0x4210,0x4410,0x4604,0x4704,0x4904,0x4704,0x4604,0x4704,0x4904,
+    0x4604,0x4B04,0x4904,0x4704,0x4904,0x4B04,0x4904,0x4804,0x4B04,0x4904,
+    0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x3904,0x3904,
+    0x3904,0x3908,0x8020,0x4604,0x8004,0x3B04,0x8004,0x4704,0x8004,0x4404,
+    0x8004,0x4104,0x800C,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4204,0x8004,0x4404,0x8004,0x4201,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4108,0x8010,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,
+    0x4101,0x4204,0x8004,0x4604,0x8004,0x3B04,0x8004,0x3704,0x8004,0x3408,
+    0x8004,0x4404,0x4704,0x4604,0x8004,0x5704,0x5701,0x5701,0x5701,0x5701,
+    0x5604,0x8004,0x4704,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,
+    0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,
+    0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,
+    0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4604,0x4404,0x4304,
+    0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,0x4204,0x4104,0x3904,0x3B04,
+    0x4104,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,
+    0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4704,0x4604,0x4204,0x4404,
+    0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,
+    0x4404,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,
+    0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,
+    0x4204,0x4604,0x4404,0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,
+    0x4204,0x4104,0x3904,0x3B04,0x4104,0x4204,0x5204,0x5204,0x5204,0x5204,
+    0x5204,0x5204,0x5204,0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,
+    0x4704,0x4604,0x3904,0x3B04,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,
+    0x4104,0x4204,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4A04,
+    0x4A04,0x4B08,0x8008,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+    0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4201,0x4201,0x4201,
+    0x4201,0x4104,0x5204,0x8004,0x5204,0x8004,0x5204,0x800C,0x4208,0x8004,
+    0x3904,0x4208,0x8004,0x3904,0x4204,0x3904,0x4204,0x4604,0x4908,0x8008,
+    0x4908,0x8004,0x4604,0x4908,0x8004,0x4604,0x4904,0x4604,0x4304,0x4604,
+    0x3B08,0x8008,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,
+    0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,
+    0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,
+    0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,
+    0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,
+    0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3904,0x3904,
+    0x3A04,0x3A04,0x4004,0x4004,0x3904,0x3904,0x3704,0x3704,0x3604,0x3604,
+    0x3704,0x3704,0x4604,0x4604,0x4704,0x4704,0x4604,0x4604,0x4704,0x3704,
+    0x3604,0x3704,0x3908,0x8004,0x3201,0x3201,0x3201,0x3201,0x3401,0x3401,
+    0x3401,0x3401,0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,
+    0x3901,0x3901,0x3901,0x3901,0x4001,0x4001,0x4001,0x4001,0x3A04,0x8004,
+    0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,0x3901,0x3901,
+    0x3901,0x3901,0x3A01,0x3A01,0x3A01,0x3A01,0x4101,0x4101,0x4101,0x4101,
+    0x4401,0x4401,0x4401,0x4401,0x4204,0x8038,0x4B04,0x4B04,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x5004,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x4B04,
+    0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4904,0x4704,0x4204,0x3B08,0x8004,0x4204,0x4708,0x8004,0x4204,
+    0x4704,0x4204,0x4704,0x4B04,0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,
+    0x8004,0x4904,0x5004,0x4904,0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,
+    0x4401,0x4704,0x4210,0x4210,0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,
+    0x4008,0x3908,0x3908,0x3204,0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,
+    0x3904,0x3904,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,
+    0x4704,0x4704,0x4404,0x4404,0x4210,0x4410,0x4210,0x4410,0x4208,0x4408,
+    0x4208,0x4408,0x4204,0x3204,0x3204,0x3204,0x3208,0x8020,0x3B04,0x8004,
+    0x3404,0x8004,0x4004,0x8004,0x3904,0x8004,0x3604,0x800C,0x4901,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x8004,0x4904,0x8004,
+    0x4B10,0x4908,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,
+    0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5208,0x8004,0x5004,
+    0x5001,0x5001,0x5001,0x5001,0x4B04,0x8004,0x5004,0x5001,0x5001,0x5001,
+    0x5001,0x4B04,0x8004,0x4004,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+    0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,
+    0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,
+    0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4B04,0x4904,
+    0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,0x4904,0x4704,0x4604,0x4204,
+    0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4204,0x4204,0x4204,0x4204,0x4204,0x4204,0x4004,0x3B04,0x3704,
+    0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,
+    0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4904,0x4904,0x4B04,0x4B04,
+    0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+    0x4704,0x4704,0x4B04,0x4904,0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,
+    0x4904,0x4704,0x4604,0x4204,0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4904,0x5004,
+    0x5004,0x5004,0x5004,0x5004,0x4B04,0x4904,0x4204,0x4404,0x4604,0x4704,
+    0x4704,0x4904,0x4904,0x4B04,0x3604,0x3704,0x3904,0x3B04,0x3B04,0x4004,
+    0x4004,0x4004,0x4004,0x4104,0x4104,0x4208,0x8008,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8018,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8008,0x4708,
+    0x8008,0x4408,0x8008,0x4708,0x8008,0x3710,0x3710,0x3710,0x3708,0x3908,
+    0x3710,0x3710,0x3710,0x3708,0x3908,0x3704,0x3B04,0x4204,0x4704,0x4B04,
+    0x4704,0x5204,0x4B04,0x4708,0x3706,0x3702,0x3708,0x8008,0x4208,0x8004,
+    0x3904,0x4208,0x8004,0x3904,0x4204,0x3904,0x4204,0x4604,0x4908,0x8008,
+    0x4908,0x8004,0x4604,0x4908,0x8004,0x4604,0x4904,0x4604,0x4304,0x4604,
+    0x3B08,0x8008,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,
+    0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,
+    0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,
+    0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,
+    0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,
+    0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3904,0x3904,
+    0x3A04,0x3A04,0x4004,0x4004,0x3904,0x3904,0x3704,0x3704,0x3604,0x3604,
+    0x3704,0x3704,0x4604,0x4604,0x4704,0x4704,0x4604,0x4604,0x4704,0x3704,
+    0x3604,0x3704,0x3908,0x8004,0x3201,0x3201,0x3201,0x3201,0x3401,0x3401,
+    0x3401,0x3401,0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,
+    0x3901,0x3901,0x3901,0x3901,0x4001,0x4001,0x4001,0x4001,0x3A04,0x8004,
+    0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,0x3901,0x3901,
+    0x3901,0x3901,0x3A01,0x3A01,0x3A01,0x3A01,0x4101,0x4101,0x4101,0x4101,
+    0x4401,0x4401,0x4401,0x4401,0x4204,0x8038,0x4B04,0x4B04,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x5004,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x4B04,
+    0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4904,0x4704,0x4204,0x3B08,0x8004,0x4204,0x4708,0x8004,0x4204,
+    0x4704,0x4204,0x4704,0x4B04,0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,
+    0x8004,0x4904,0x5004,0x4904,0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,
+    0x4401,0x4704,0x4210,0x4210,0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,
+    0x4008,0x3908,0x3908,0x3204,0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+    0x4601,0x4601,0x4601,0x4601,0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,
+    0x3904,0x3904,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,
+    0x4704,0x4704,0x4404,0x4404,0x4210,0x4410,0x4210,0x4410,0x4208,0x4408,
+    0x4208,0x4408,0x4204,0x3204,0x3204,0x3204,0x3208,0x8020,0x3B04,0x8004,
+    0x3404,0x8004,0x4004,0x8004,0x3904,0x8004,0x3604,0x800C,0x4901,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x8004,0x4904,0x8004,
+    0x4B10,0x4908,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+    0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,
+    0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5208,0x8004,0x5004,
+    0x5001,0x5001,0x5001,0x5001,0x4B04,0x8004,0x5004,0x5001,0x5001,0x5001,
+    0x5001,0x4B04,0x8004,0x4004,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+    0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,
+    0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,
+    0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4B04,0x4904,
+    0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,0x4904,0x4704,0x4604,0x4204,
+    0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4204,0x4204,0x4204,0x4204,0x4204,0x4204,0x4004,0x3B04,0x3704,
+    0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,
+    0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4904,0x4904,0x4B04,0x4B04,
+    0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+    0x4704,0x4704,0x4B04,0x4904,0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,
+    0x4904,0x4704,0x4604,0x4204,0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,
+    0x4704,0x4704,0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4904,0x5004,
+    0x5004,0x5004,0x5004,0x5004,0x4B04,0x4904,0x4204,0x4404,0x4604,0x4704,
+    0x4704,0x4904,0x4904,0x4B04,0x3604,0x3704,0x3904,0x3B04,0x3B04,0x4004,
+    0x4004,0x4004,0x4004,0x4104,0x4104,0x4208,0x8008,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8018,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8008,0x4708,
+    0x8008,0x4408,0x8008,0x4708,0x8008,0x3710,0x3710,0x3710,0x3708,0x3908,
+    0x3710,0x3710,0x3710,0x3708,0x3908,0x3704,0x3B04,0x4204,0x4704,0x4B04,
+    0x4704,0x5204,0x4B04,0x4708,0x3706,0x3702,0x3708,0x8008,
+    0x0000
+};
+
+static int Voice3 [] = {
+    0x3708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,0x3B04,
+    0x3208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,0x3904,
+    0x3604,0x4904,0x4208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,0x3904,
+    0x3B04,0x3B04,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3B08,0x8028,
+    0x3210,0x3410,0x3008,0x3008,0x3208,0x3208,0x2B04,0x8004,0x3204,0x8004,
+    0x3708,0x8008,0x4B10,0x5010,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+    0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+    0x3410,0x3008,0x3008,0x3208,0x3208,0x3B14,0x3B02,0x3901,0x3B01,0x4004,
+    0x3904,0x4714,0x4702,0x4601,0x4701,0x4904,0x4604,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3604,0x3604,0x3704,
+    0x3704,0x3404,0x3404,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+    0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+    0x3404,0x3604,0x3404,0x3204,0x3404,0x3604,0x3204,0x3704,0x3904,0x3B04,
+    0x3904,0x3704,0x3904,0x3B04,0x3804,0x3904,0x3904,0x3904,0x3904,0x3904,
+    0x3904,0x3904,0x3904,0x3904,0x2904,0x2904,0x2904,0x2908,0x8008,0x490A,
+    0x4702,0x4602,0x4402,0x4204,0x8004,0x3304,0x8004,0x3404,0x8004,0x3204,
+    0x8004,0x3104,0x8004,0x2904,0x800C,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,
+    0x2A01,0x2A01,0x2A01,0x2B04,0x8004,0x2704,0x8004,0x2908,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+    0x3801,0x3801,0x3801,0x3801,0x3701,0x3701,0x3701,0x3701,0x3401,0x3401,
+    0x3401,0x3401,0x3204,0x8004,0x3404,0x8004,0x3604,0x8004,0x3304,0x8004,
+    0x3404,0x8004,0x3204,0x8004,0x3104,0x8004,0x2904,0x8004,0x2B04,0x8004,
+    0x3704,0x8004,0x3904,0x8004,0x2904,0x8004,0x4604,0x4604,0x4704,0x4704,
+    0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+    0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+    0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,
+    0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+    0x5401,0x5401,0x5401,0x5401,0x5204,0x5604,0x5704,0x5904,0x5701,0x5701,
+    0x5701,0x5701,0x5901,0x5901,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,
+    0x5701,0x5701,0x5604,0x5204,0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,
+    0x5204,0x5104,0x5204,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+    0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4604,0x4604,
+    0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,
+    0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+    0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+    0x5204,0x5504,0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,0x5901,0x5901,
+    0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x5204,
+    0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,0x3204,0x2904,
+    0x2B04,0x3104,0x3204,0x3204,0x3404,0x3404,0x3604,0x3104,0x3204,0x3404,
+    0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3A04,0x3A04,0x3B08,0x8008,
+    0x3710,0x3910,0x4204,0x8004,0x4204,0x8004,0x4204,0x800C,0x3708,0x8004,
+    0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,0x3B04,0x3208,0x8008,
+    0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,0x3904,0x3604,0x4904,
+    0x4208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+    0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3B08,0x8028,0x3210,0x3410,
+    0x3008,0x3008,0x3208,0x3208,0x2B04,0x8004,0x3204,0x8004,0x3708,0x8008,
+    0x4B10,0x5010,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+    0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3410,0x3008,
+    0x3008,0x3208,0x3208,0x3B14,0x3B02,0x3901,0x3B01,0x4004,0x3904,0x4714,
+    0x4702,0x4601,0x4701,0x4904,0x4604,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3404,
+    0x3404,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+    0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3404,0x3604,
+    0x3404,0x3204,0x3404,0x3604,0x3204,0x3704,0x3904,0x3B04,0x3904,0x3704,
+    0x3904,0x3B04,0x3804,0x3904,0x3904,0x3904,0x3904,0x3904,0x3904,0x3904,
+    0x3904,0x3904,0x2904,0x2904,0x2904,0x2908,0x8008,0x490A,0x4702,0x4602,
+    0x4402,0x4204,0x8004,0x3304,0x8004,0x3404,0x8004,0x3204,0x8004,0x3104,
+    0x8004,0x2904,0x800C,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,
+    0x2A01,0x2B04,0x8004,0x2704,0x8004,0x2908,0x3901,0x3901,0x3901,0x3901,
+    0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3801,0x3801,
+    0x3801,0x3801,0x3701,0x3701,0x3701,0x3701,0x3401,0x3401,0x3401,0x3401,
+    0x3204,0x8004,0x3404,0x8004,0x3604,0x8004,0x3304,0x8004,0x3404,0x8004,
+    0x3204,0x8004,0x3104,0x8004,0x2904,0x8004,0x2B04,0x8004,0x3704,0x8004,
+    0x3904,0x8004,0x2904,0x8004,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,
+    0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,
+    0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,
+    0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,
+    0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+    0x5401,0x5401,0x5204,0x5604,0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,
+    0x5901,0x5901,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,
+    0x5604,0x5204,0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,
+    0x5204,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,
+    0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+    0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+    0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+    0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+    0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5204,0x5504,
+    0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,0x5901,0x5901,0x5B01,0x5B01,
+    0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x5204,0x5604,0x5601,
+    0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,0x3204,0x2904,0x2B04,0x3104,
+    0x3204,0x3204,0x3404,0x3404,0x3604,0x3104,0x3204,0x3404,0x3604,0x3604,
+    0x3704,0x3704,0x3904,0x3904,0x3A04,0x3A04,0x3B08,0x8008,0x3710,0x3910,
+    0x4204,0x8004,0x4204,0x8004,0x4204,0x800C,0x3208,0x8004,0x2904,0x3208,
+    0x8004,0x2904,0x3204,0x2904,0x3204,0x3604,0x4908,0x8008,0x3908,0x8004,
+    0x3604,0x3908,0x8004,0x3604,0x3904,0x3604,0x3304,0x3604,0x2B08,0x8008,
+    0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,
+    0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+    0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+    0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,
+    0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4004,0x4004,
+    0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x4004,0x4004,0x4204,0x4204,
+    0x4304,0x4304,0x4004,0x4004,0x3A04,0x3A04,0x3904,0x3904,0x3A04,0x3A04,
+    0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4704,
+    0x4608,0x8004,0x2201,0x2201,0x2201,0x2201,0x2401,0x2401,0x2401,0x2401,
+    0x2601,0x2601,0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,
+    0x2901,0x2901,0x3001,0x3001,0x3001,0x3001,0x2A04,0x8004,0x2601,0x2601,
+    0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,0x2901,0x2901,
+    0x2A01,0x2A01,0x2A01,0x2A01,0x2101,0x2101,0x2101,0x2101,0x3401,0x3401,
+    0x3401,0x3401,0x3204,0x8004,0x4204,0x4404,0x4504,0x4704,0x4904,0x4A08,
+    0x4B08,0x5008,0x5108,0x5204,0x5204,0x5201,0x5201,0x5201,0x5201,0x5404,
+    0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x5204,0x4B04,0x4B04,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,0x4B04,
+    0x4904,0x4708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,
+    0x3B04,0x4208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,
+    0x3904,0x3604,0x3904,0x3208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,
+    0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x4008,
+    0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4908,0x4908,
+    0x4708,0x4708,0x4408,0x4408,0x4008,0x3908,0x4204,0x8004,0x4604,0x8004,
+    0x4704,0x800C,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+    0x4704,0x4704,0x4704,0x4408,0x4404,0x4404,0x4008,0x4004,0x4004,0x3B14,
+    0x3B01,0x3B01,0x3901,0x3B01,0x4001,0x4001,0x4001,0x4001,0x3904,0x4714,
+    0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B10,
+    0x5010,0x4B08,0x5210,0x5708,0x5610,0x5710,0x5610,0x5710,0x5608,0x5708,
+    0x5608,0x5708,0x5604,0x4204,0x4204,0x4204,0x4208,0x8008,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4001,0x4001,
+    0x3B01,0x3B01,0x3901,0x3901,0x3704,0x8004,0x4404,0x8004,0x4004,0x8004,
+    0x3904,0x8004,0x4204,0x800C,0x4B0A,0x4902,0x4702,0x4602,0x5404,0x8004,
+    0x5004,0x8004,0x3208,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4101,0x4101,0x4101,0x4101,0x4001,
+    0x4001,0x4001,0x4001,0x3901,0x3901,0x3901,0x3901,0x3704,0x8004,0x3904,
+    0x8004,0x3B04,0x8004,0x3804,0x8004,0x3904,0x8004,0x3704,0x8004,0x3604,
+    0x8004,0x3204,0x8004,0x3404,0x8004,0x3004,0x8004,0x3204,0x8004,0x3204,
+    0x8004,0x2708,0x8018,0x3208,0x8018,0x2708,0x8018,0x3208,0x8018,0x3B08,
+    0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4908,0x8008,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x4B04,0x5004,0x5204,0x5001,
+    0x5001,0x5001,0x5001,0x5201,0x5201,0x5401,0x5401,0x5204,0x5004,0x5001,
+    0x5001,0x5001,0x5001,0x4B04,0x4704,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4904,0x4704,0x4604,0x4704,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,
+    0x3B04,0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3B04,
+    0x4B04,0x5004,0x5004,0x5204,0x5204,0x4B04,0x4B04,0x4904,0x4904,0x4B04,
+    0x4B04,0x5004,0x5004,0x4904,0x4904,0x8004,0x3704,0x3B04,0x3904,0x3804,
+    0x3404,0x3604,0x3804,0x3904,0x4004,0x3904,0x3704,0x3604,0x3204,0x3404,
+    0x3604,0x3704,0x3704,0x3904,0x3B04,0x4004,0x4004,0x4004,0x4004,0x4204,
+    0x4204,0x4204,0x4204,0x3204,0x3204,0x3204,0x3204,0x3704,0x3204,0x3404,
+    0x3604,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3604,0x3704,0x3904,0x3B04,
+    0x3B04,0x4004,0x4004,0x4204,0x4204,0x4304,0x4304,0x4408,0x8008,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3008,0x8008,0x3208,
+    0x8008,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2B04,0x3204,0x3704,0x3B04,0x3704,0x4204,
+    0x3B04,0x3708,0x2706,0x2702,0x2708,0x8008,0x3208,0x8004,0x2904,0x3208,
+    0x8004,0x2904,0x3204,0x2904,0x3204,0x3604,0x4908,0x8008,0x3908,0x8004,
+    0x3604,0x3908,0x8004,0x3604,0x3904,0x3604,0x3304,0x3604,0x2B08,0x8008,
+    0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,
+    0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+    0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+    0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,
+    0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4004,0x4004,
+    0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x4004,0x4004,0x4204,0x4204,
+    0x4304,0x4304,0x4004,0x4004,0x3A04,0x3A04,0x3904,0x3904,0x3A04,0x3A04,
+    0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4704,
+    0x4608,0x8004,0x2201,0x2201,0x2201,0x2201,0x2401,0x2401,0x2401,0x2401,
+    0x2601,0x2601,0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,
+    0x2901,0x2901,0x3001,0x3001,0x3001,0x3001,0x2A04,0x8004,0x2601,0x2601,
+    0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,0x2901,0x2901,
+    0x2A01,0x2A01,0x2A01,0x2A01,0x2101,0x2101,0x2101,0x2101,0x3401,0x3401,
+    0x3401,0x3401,0x3204,0x8004,0x4204,0x4404,0x4504,0x4704,0x4904,0x4A08,
+    0x4B08,0x5008,0x5108,0x5204,0x5204,0x5201,0x5201,0x5201,0x5201,0x5404,
+    0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x5204,0x4B04,0x4B04,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,0x4B04,
+    0x4904,0x4708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,
+    0x3B04,0x4208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,
+    0x3904,0x3604,0x3904,0x3208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+    0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,
+    0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x4008,
+    0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4908,0x4908,
+    0x4708,0x4708,0x4408,0x4408,0x4008,0x3908,0x4204,0x8004,0x4604,0x8004,
+    0x4704,0x800C,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+    0x4704,0x4704,0x4704,0x4408,0x4404,0x4404,0x4008,0x4004,0x4004,0x3B14,
+    0x3B01,0x3B01,0x3901,0x3B01,0x4001,0x4001,0x4001,0x4001,0x3904,0x4714,
+    0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B10,
+    0x5010,0x4B08,0x5210,0x5708,0x5610,0x5710,0x5610,0x5710,0x5608,0x5708,
+    0x5608,0x5708,0x5604,0x4204,0x4204,0x4204,0x4208,0x8008,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4001,0x4001,
+    0x3B01,0x3B01,0x3901,0x3901,0x3704,0x8004,0x4404,0x8004,0x4004,0x8004,
+    0x3904,0x8004,0x4204,0x800C,0x4B0A,0x4902,0x4702,0x4602,0x5404,0x8004,
+    0x5004,0x8004,0x3208,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+    0x4201,0x4201,0x4201,0x4201,0x4201,0x4101,0x4101,0x4101,0x4101,0x4001,
+    0x4001,0x4001,0x4001,0x3901,0x3901,0x3901,0x3901,0x3704,0x8004,0x3904,
+    0x8004,0x3B04,0x8004,0x3804,0x8004,0x3904,0x8004,0x3704,0x8004,0x3604,
+    0x8004,0x3204,0x8004,0x3404,0x8004,0x3004,0x8004,0x3204,0x8004,0x3204,
+    0x8004,0x2708,0x8018,0x3208,0x8018,0x2708,0x8018,0x3208,0x8018,0x3B08,
+    0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4908,0x8008,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,
+    0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x4B04,0x5004,0x5204,0x5001,
+    0x5001,0x5001,0x5001,0x5201,0x5201,0x5401,0x5401,0x5204,0x5004,0x5001,
+    0x5001,0x5001,0x5001,0x4B04,0x4704,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,
+    0x4904,0x4704,0x4604,0x4704,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,
+    0x3B04,0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3B04,
+    0x4B04,0x5004,0x5004,0x5204,0x5204,0x4B04,0x4B04,0x4904,0x4904,0x4B04,
+    0x4B04,0x5004,0x5004,0x4904,0x4904,0x8004,0x3704,0x3B04,0x3904,0x3804,
+    0x3404,0x3604,0x3804,0x3904,0x4004,0x3904,0x3704,0x3604,0x3204,0x3404,
+    0x3604,0x3704,0x3704,0x3904,0x3B04,0x4004,0x4004,0x4004,0x4004,0x4204,
+    0x4204,0x4204,0x4204,0x3204,0x3204,0x3204,0x3204,0x3704,0x3204,0x3404,
+    0x3604,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3604,0x3704,0x3904,0x3B04,
+    0x3B04,0x4004,0x4004,0x4204,0x4204,0x4304,0x4304,0x4408,0x8008,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+    0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3008,0x8008,0x3208,
+    0x8008,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+    0x2704,0x2704,0x2704,0x2704,0x2B04,0x3204,0x3704,0x3B04,0x3704,0x4204,
+    0x3B04,0x3708,0x2706,0x2702,0x2708,0x8008,
+    0x0000
+};
+
+
+
+/* Screen sizes */
+#ifdef __CBM610__
+#  define MAX_X        80
+#else
+#  define MAX_X 40
+#endif
+
+
+
+#ifdef __C64__
+static unsigned long FreqTab [12] = {
+#ifndef NTSC
+    /* PAL */
+    0x008B38, 0x009381, 0x009C45, 0x00A590, 0x00AF68, 0x00B9D6,
+    0x00C4E4, 0x00D099, 0x00DCFF, 0x00EA24, 0x00F810, 0x0106D1,
+#else
+    /* NTSC */
+    0x00861E, 0x008E19, 0x00968B, 0x009F7F, 0x00A8FA, 0x00B307,
+    0x00BDAD, 0x00C8F4, 0x00D4E6, 0x00E18F, 0x00EEF9, 0x00FD2F,
+#endif
+};
+#endif
+
+#ifdef __C128__
+static unsigned long FreqTab [12] = {
+    0x00892B, 0x009153, 0x0099F7, 0x00A31E, 0x00ACD2, 0x00B718,
+    0x00C1FD, 0x00CD85, 0x00D9BD, 0x00E6B0, 0x00F467, 0x0102F0,
+};
+#endif
+
+#ifdef __CBM610__
+static unsigned long FreqTab [12] = {
+    0x004495, 0x0048AA, 0x004CFB, 0x00518F, 0x005669, 0x005B8C,
+    0x0060FE, 0x0066C3, 0x006CDE, 0x007358, 0x007A34, 0x008178,
+};
+#endif
+
+
+
+typedef struct {
+    unsigned char              DoneMask;       /* Set this if we're done */
+    unsigned char      Trigger;        /* Trigger value */
+    unsigned char      Ticks;          /* Ticks for this tone */
+    unsigned           Freq;           /* Actual frequency value */
+    int*               Data;           /* Pointer to data */
+    struct __sid_voice*        Voice;          /* Pointer to sid registers */
+} VoiceCtrl;
+
+/* Control structs for all three voices */
+static VoiceCtrl V1 = {
+    0x01, 0x11, 0, 0, Voice1, &SID.v1
+};
+static VoiceCtrl V2 = {
+    0x02, 0x41, 0, 0, Voice2, &SID.v2
+};
+static VoiceCtrl V3 = {
+    0x04, 0x11, 0, 0, Voice3, &SID.v3
+};
+
+/* Pointers to the structs for easy reference */
+static VoiceCtrl* V [3] = {
+    &V1, &V2, &V3
+};
+
+/* Variable that contains the time of the next clock tick to play a note */
+static unsigned char NextClock;
+
+/* Start- and runtime */
+static clock_t StartTime;
+
+/* Number of ticks for each tone */
+#define        TICKS_PER_TONE  4
+
+/* Done flag. Contains one bit for each voice. Will contain 0x07 if all
+ * voices have finished playing.
+ */
+static unsigned char Done;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void MakeTeeLine (unsigned char Y)
+/* Make a divider line */
+{
+    cputcxy (0, Y, CH_LTEE);
+    chline (MAX_X - 2);
+    cputc (CH_RTEE);
+}
+
+
+
+static void MakeNiceScreen (void)
+/* Make a nice screen */
+{
+    typedef struct {
+       unsigned char   X;
+       unsigned char   Y;
+       char*           Msg;
+    } TextDesc;
+    static TextDesc Text [] = {
+               {  (MAX_X / 2) - 11,  2, "Wolfgang Amadeus Mozart"      },
+        {  (MAX_X / 2) - 12,  4, "\"Eine kleine Nachtmusik\""  },
+               {  (MAX_X / 2) -  4,  5, "(KV 525)"                     },
+        {  (MAX_X / 2) - 14,  9, "Ported to the SID in 1987 by" },
+               {  (MAX_X / 2) - 10, 11, "Joachim von Bassewitz"        },
+               {  (MAX_X / 2) - 13, 12, "(joachim@von-bassewitz.de)"   },
+               {  (MAX_X / 2) -  1, 13, "and"                          },
+               {  (MAX_X / 2) - 10, 14, "Ullrich von Bassewitz"        },
+        {  (MAX_X / 2) - 13, 15, "(ullrich@von-bassewitz.de)"  },
+               {  (MAX_X / 2) -  9, 18, "C Implementation by"          },
+               {  (MAX_X / 2) - 10, 19, "Ullrich von Bassewitz"        },
+        {  (MAX_X / 2) - 11, 23, "Press any key to quit..."    },
+    };
+
+    TextDesc* T;
+    unsigned char I;
+
+    /* Clear the screen hide the cursor, set colors */
+#ifdef __CBM610__
+    textcolor (COLOR_WHITE);
+#else
+    textcolor (COLOR_GRAY3);
+#endif
+    bordercolor (COLOR_BLACK);
+    bgcolor (COLOR_BLACK);
+    clrscr ();
+    cursor (0);
+
+    /* Top line */
+    cputcxy (0, 0, CH_ULCORNER);
+    chline (MAX_X - 2);
+    cputc (CH_URCORNER);
+
+    /* Left line */
+    cvlinexy (0, 1, 23);
+
+    /* Bottom line */
+    cputc (CH_LLCORNER);
+    chline (MAX_X - 2);
+    cputc (CH_LRCORNER);
+
+    /* Right line */
+    cvlinexy (MAX_X - 1, 1, 23);
+
+    /* Several divider lines */
+    MakeTeeLine (7);
+    MakeTeeLine (22);
+
+    /* Write something into the frame */
+    for (I = 0, T = Text; I < sizeof (Text) / sizeof (Text [0]); ++I) {
+       cputsxy (T->X, T->Y, T->Msg);
+       ++T;
+    }
+}
+
+
+
+static void TimeSync (void)
+/* Sync the time for the next tone */
+{
+    static unsigned char Clock;
+
+    do {
+               Clock = clock ();
+    } while (Clock != NextClock);
+    NextClock = Clock + TICKS_PER_TONE;
+}
+
+
+
+static void DisplayTime (void)
+/* Display the running time */
+{
+    clock_t Time = (clock () - StartTime) / CLOCKS_PER_TICK;
+    unsigned Sec = Time % 60;
+    unsigned Min = Time / 60;
+
+    gotoxy (1, 0);
+    cprintf ("%02d:%02d", Min, Sec);
+}
+
+
+
+/* On the 610, the SID is in another bank (the system bank), so we cannot
+ * just write to the memory space.
+ */
+#ifdef __CBM610__
+#  define outb(addr,val)       pokebsys ((unsigned)(addr), val)
+#  define outw(addr,val)       pokewsys ((unsigned)(addr), val)
+#else
+#  define outb(addr,val)       (*(addr)) = (val)
+#  define outw(addr,val)       (*(addr)) = (val)
+#endif
+
+
+
+int main (void)
+{
+    unsigned char       I;
+    unsigned char       Tone;
+    unsigned char       Octave;
+    unsigned           Val;    
+    struct __sid_voice*        Voice;
+    VoiceCtrl*         VC;
+
+    /* Initialize the debugger */
+    DbgInit (0);
+
+    /* Make a nice screen */
+    MakeNiceScreen ();
+
+    /* Initialize the SID */
+    outw (&SID.v1.pw, 0x0800);
+    outb (&SID.v1.ad, 0x33);
+    outb (&SID.v1.sr, 0xF0);
+    outw (&SID.v2.pw, 0x0800);
+    outb (&SID.v2.ad, 0x77);
+    outb (&SID.v2.sr, 0x74);
+    outw (&SID.v3.pw, 0x0800);
+    outb (&SID.v3.ad, 0x77);
+    outb (&SID.v3.sr, 0xD2);
+    outw (&SID.flt_freq, 0xF0F0);
+    outb (&SID.flt_ctrl, 0xF2);
+    outb (&SID.amp, 0x5F);
+
+    /* Sync the clock */
+    NextClock = StartTime = clock ();
+    NextClock += TICKS_PER_TONE;
+
+    /* Play each voice until all three are done */
+    while (Done != 0x07) {
+
+       /* Display the time in the lower left corner */
+               DisplayTime ();
+
+       /* Wait for the next run */
+       TimeSync ();
+
+       /* Check for a key */
+       if (kbhit ()) {
+           if (cgetc () == 'd') {
+               /* Start the debugger */
+               BREAK ();
+           } else {
+               /* Stop playing music */
+               break;
+           }
+       }
+
+       /* Play all three voices */
+       for (I = 0; I < 3; ++I) {
+
+           /* Get a pointer to this voice */
+           VC = V [I];
+           Voice = VC->Voice;
+
+           /* Is this voice done? */
+           if (Done & VC->DoneMask) {
+               /* Voice already done */
+               continue;
+           }
+
+           /* Do we have any more ticks to play? */
+           if (VC->Ticks == 0) {
+               /* We need new data */
+               if ((Val = *VC->Data) == 0) {
+                   /* End of data. Mark the voice as done */
+                   Done |= VC->DoneMask;
+                   continue;
+               }
+               ++VC->Data;
+
+               /* Get the ticks from the data */
+                       VC->Ticks = (Val & 0x7F) - 1;
+
+               /* Check if this is a tone or a pause */
+               if (Val & 0x8000) {
+                   /* This is a pause. Remember it and shut off the SID */
+                           outb (&Voice->ctrl, VC->Trigger & 0xFE);
+               } else {
+                   /* This is a tone. Extract the attributes. */
+                   Tone = (Val >> 8) & 0x0F;
+                   Octave = ((Val >> 12) & 0x07) ^ 0x07;
+                   /* Calculate the frequency */
+                   VC->Freq = FreqTab [Tone] >> Octave;
+                   /* Set the frequency */
+                   outw (&Voice->freq, VC->Freq);
+                   /* Start the tone */
+                   outb (&Voice->ctrl, VC->Trigger);
+               }
+           } else {
+               /* Decrement the ticks. If this is the last tick of a tone,
+                * reset bit 0 of the trigger value and write it back to the
+                * SID to start the release phase.
+                */
+                       if (--(VC->Ticks) == 0) {
+                   outb (&Voice->ctrl, VC->Trigger & 0xFE);
+               }
+           }
+       }
+    }
+
+    /* Reset the SID */
+    outb (&SID.v1.ctrl, 0x00);
+    outb (&SID.v2.ctrl, 0x00);
+    outb (&SID.v3.ctrl, 0x00);
+
+    /* Clear the screen */
+    clrscr ();
+
+    /* If we have a character, remove it from the buffer */
+    if (kbhit ()) {
+               cgetc ();
+    }
+
+    /* Done */
+    return 0;
+}
+
+
+
diff --git a/samples/sieve.c b/samples/sieve.c
new file mode 100644 (file)
index 0000000..24e5601
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Calculate all primes up to a specific number.
+ */
+
+
+
+#include <stdio.h>
+#include <conio.h>
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+#define COUNT          8192            /* Up to what number? */
+#define SQRT_COUNT     91              /* Sqrt of COUNT */
+
+static unsigned char Sieve[COUNT];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int main (void)
+{
+    /* This is an example where register variables make sense */
+    register unsigned char* S;
+    register unsigned      I;
+    register unsigned      J;
+
+    /* Execute the sieve */
+    I = 2;
+    while (I < SQRT_COUNT) {
+       if (Sieve[I] == 0) {
+           /* Prime number - mark multiples */
+           S = &Sieve[J = I*2];
+                   while (J < COUNT) {
+               *S = 1;
+               S += I;
+               J += I;
+           }
+       }
+       ++I;
+    }
+
+    /* Print the result */
+    for (I = 2; I < COUNT; ++I) {
+       if (Sieve[I] == 0) {
+           printf ("%4d\n", I);
+       }
+       if (kbhit() && cgetc() == 'q') {
+           break;
+       }
+    }
+
+    return 0;
+}
+
+
+
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644 (file)
index 0000000..a8dca6f
--- /dev/null
@@ -0,0 +1 @@
+*.obj
diff --git a/src/ar65/.cvsignore b/src/ar65/.cvsignore
new file mode 100644 (file)
index 0000000..765a702
--- /dev/null
@@ -0,0 +1,3 @@
+.depend
+ar65
+
diff --git a/src/ar65/add.c b/src/ar65/add.c
new file mode 100644 (file)
index 0000000..1ca0ff1
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  add.c                                   */
+/*                                                                           */
+/*                Object file adding for the ar65 archiver                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "objfile.h"
+#include "library.h"
+#include "add.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void AddObjFiles (int argc, char* argv [])
+/* Add object files to a library */
+{
+    int I;
+
+    /* Check the argument count */
+    if (argc <= 0) {
+       Error ("No library name given");
+    }
+    if (argc <= 1) {
+       Error ("No object files to add");
+    }
+
+    /* Open the library, read the index */
+    LibOpen (argv [0], 0, 1);
+
+    /* Add the object files */
+    I = 1;
+    while (I < argc) {
+       ObjAdd (argv [I]);
+       ++I;
+    }
+
+    /* Create a new library file and close the old one */
+    LibClose ();
+
+    /* Successful end */
+    exit (EXIT_SUCCESS);
+}
+
+
+
+
diff --git a/src/ar65/add.h b/src/ar65/add.h
new file mode 100644 (file)
index 0000000..38bf868
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  add.h                                   */
+/*                                                                           */
+/*                Object file adding for the ar65 archiver                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ADD_H
+#define ADD_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void AddObjFiles (int argc, char* argv []);
+/* Add object files to a library */
+
+
+
+/* End of add.h */
+
+#endif
+
+
+
+
diff --git a/src/ar65/del.c b/src/ar65/del.c
new file mode 100644 (file)
index 0000000..a94be25
--- /dev/null
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  del.h                                   */
+/*                                                                           */
+/*               Object file deleting for the ar65 archiver                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "objdata.h"
+#include "library.h"
+#include "del.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void DelObjFiles (int argc, char* argv [])
+/* Delete modules from a library */
+{
+    int I;
+
+    /* Check the argument count */
+    if (argc <= 0) {
+       Error ("No library name given");
+    }
+    if (argc <= 1) {
+       Error ("No modules to delete");
+    }
+
+    /* Open the library, read the index */
+    LibOpen (argv [0], 1, 1);
+
+    /* Delete the modules */
+    I = 1;
+    while (I < argc) {
+       /* Delete the module from the list */
+       DelObjData (argv [I]);
+       ++I;
+    }
+
+    /* Create a new library file and close the old one */
+    LibClose ();
+
+    /* Successful end */
+    exit (EXIT_SUCCESS);
+}
+
+
+
+
diff --git a/src/ar65/del.h b/src/ar65/del.h
new file mode 100644 (file)
index 0000000..18f6c3c
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  del.h                                   */
+/*                                                                           */
+/*               Object file deleting for the ar65 archiver                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef DEL_H
+#define DEL_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void DelObjFiles (int argc, char* argv []);
+/* Delete modules from a library */
+
+
+
+/* End of del.h */              
+
+#endif
+
+
+
+
diff --git a/src/ar65/error.c b/src/ar65/error.c
new file mode 100644 (file)
index 0000000..a8b7a83
--- /dev/null
@@ -0,0 +1,106 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*                  Error handling for the ar65 archiver                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+    "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+    "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+    "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Warning: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Error: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Internal error: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
diff --git a/src/ar65/error.h b/src/ar65/error.h
new file mode 100644 (file)
index 0000000..be36010
--- /dev/null
@@ -0,0 +1,87 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*                  Error handling for the ar65 archiver                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c)                                                       \
+    if (!(c))                                                          \
+       Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c)                                                        \
+    if (!(c))                                                          \
+               Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s)                                                                \
+    Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
diff --git a/src/ar65/exports.c b/src/ar65/exports.c
new file mode 100644 (file)
index 0000000..9c1ad9d
--- /dev/null
@@ -0,0 +1,149 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                exports.c                                 */
+/*                                                                           */
+/*             Duplicate export checking for the ar65 archiver              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+#include "exports.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* A hash table entry */
+typedef struct HashEntry_ HashEntry;
+struct HashEntry_ {
+    HashEntry*                 Next;           /* Next in list */
+    unsigned           Module;         /* Module index */
+    char               Name [1];       /* Name of identifier */
+};
+
+/* Hash table */
+#define HASHTAB_SIZE   4783
+static HashEntry*      HashTab [HASHTAB_SIZE];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static HashEntry* NewHashEntry (const char* Name, unsigned Module)
+/* Create and return a new hash entry */
+{
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Get memory for the struct */
+    HashEntry* H = Xmalloc (sizeof (HashEntry) + Len);
+
+    /* Initialize the fields and return it */
+    H->Next    = 0;
+    H->Module  = Module;
+    memcpy (H->Name, Name, Len);
+    H->Name [Len] = '\0';
+    return H;
+}
+
+
+
+void ExpInsert (const char* Name, unsigned Module)
+/* Insert an exported identifier and check if it's already in the list */
+{
+    HashEntry* L;
+
+    /* Create a hash value for the given name */
+    unsigned HashVal = HashStr (Name) % HASHTAB_SIZE;
+
+    /* Create a new hash entry */
+    HashEntry* H = NewHashEntry (Name, Module);
+
+    /* Search through the list in that slot and print matching duplicates */
+    if (HashTab [HashVal] == 0) {
+       /* The slot is empty */
+       HashTab [HashVal] = H;
+       return;
+    }
+    L = HashTab [HashVal];
+    while (1) {
+       if (strcmp (L->Name, Name) == 0) {
+           /* Duplicate entry */
+           Warning ("External symbol `%s' in module `%s' is duplicated in "
+                    "module `%s'",
+                    Name, GetObjName (L->Module), GetObjName (Module));
+       }
+       if (L->Next == 0) {
+           break;
+       } else {
+           L = L->Next;
+       }
+    }
+    L->Next = H;
+}
+
+
+
+int ExpFind (const char* Name)
+/* Check for an identifier in the list. Return -1 if not found, otherwise
+ * return the number of the module, that exports the identifer.
+ */
+{
+    /* Get a pointer to the list with the symbols hash value */
+    HashEntry* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
+    while (L) {
+        /* Search through the list in that slot */
+       if (strcmp (L->Name, Name) == 0) {
+           /* Entry found */
+           return L->Module;
+       }
+       L = L->Next;
+    }
+
+    /* Not found */
+    return -1;
+}
+
+
+
diff --git a/src/ar65/exports.h b/src/ar65/exports.h
new file mode 100644 (file)
index 0000000..4ae8fc1
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                exports.h                                 */
+/*                                                                           */
+/*             Duplicate export checking for the ar65 archiver              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXPORTS_H
+#define EXPORTS_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ExpInsert (const char* Name, unsigned Module);
+/* Insert an exported identifier and check if it's already in the list */
+
+int ExpFind (const char* Name);
+/* Check for an identifier in the list. Return -1 if not found, otherwise
+ * return the number of the module, that exports the identifer.
+ */
+
+
+
+/* End of exports.h */
+
+#endif
+
+
+
diff --git a/src/ar65/extract.c b/src/ar65/extract.c
new file mode 100644 (file)
index 0000000..aba4f6b
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                extract.c                                 */
+/*                                                                           */
+/*              Object file extraction for the ar65 archiver                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objfile.h"
+#include "library.h"
+#include "extract.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ExtractObjFiles (int argc, char* argv [])
+/* Extract object files from a library */
+{
+    int I;
+
+    /* Check the argument count */
+    if (argc <= 0) {
+       Error ("No library name given");
+    }
+    if (argc <= 1) {
+       Error ("No object files to add");
+    }
+
+    /* Open the library, read the index */
+    LibOpen (argv [0], 1, 0);
+
+    /* Extract the object files */
+    I = 1;
+    while (I < argc) {
+       ObjExtract (argv [I]);
+       ++I;
+    }
+
+    /* Create a new library file and close the old one */
+    LibClose ();
+
+    /* Successful end */
+    exit (EXIT_SUCCESS);
+}
+
+
+
diff --git a/src/ar65/extract.h b/src/ar65/extract.h
new file mode 100644 (file)
index 0000000..c413fd8
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                extract.h                                 */
+/*                                                                           */
+/*              Object file extraction for the ar65 archiver                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXTRACT_H
+#define EXTRACT_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ExtractObjFiles (int argc, char* argv []);
+/* Extract object files from a library */
+
+
+
+/* End of extract.h */
+
+#endif
+
+
+
+
diff --git a/src/ar65/fileio.c b/src/ar65/fileio.c
new file mode 100644 (file)
index 0000000..696b4ff
--- /dev/null
@@ -0,0 +1,210 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                fileio.c                                  */
+/*                                                                           */
+/*                     File I/O for the ar65 archiver                       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val)
+/* Write an 8 bit value to the file */
+{
+    if (putc (Val, F) == EOF) {
+       Error ("Write error (disk full?)");
+    }
+}
+
+
+
+void Write16 (FILE* F, unsigned Val)
+/* Write a 16 bit value to the file */
+{
+    Write8 (F, (unsigned char) Val);
+    Write8 (F, (unsigned char) (Val >> 8));
+}
+
+
+
+void Write32 (FILE* F, unsigned long Val)
+/* Write a 32 bit value to the file */
+{
+    Write8 (F, (unsigned char) Val);
+    Write8 (F, (unsigned char) (Val >> 8));
+    Write8 (F, (unsigned char) (Val >> 16));
+    Write8 (F, (unsigned char) (Val >> 24));
+}
+
+
+
+void WriteStr (FILE* F, const char* S)
+/* Write a string to the file */
+{
+    unsigned Len = strlen (S);
+    if (Len > 255) {
+               Internal ("String too long");
+    }
+    Write8 (F, (unsigned char) Len);
+    WriteData (F, S, Len);
+}
+
+
+
+void WriteData (FILE* F, const void* Data, unsigned Size)
+/* Write data to the file */
+{
+    if (fwrite (Data, 1, Size, F) != Size) {
+       Error ("Write error (disk full?)");
+    }
+}
+
+
+
+unsigned Read8 (FILE* F)
+/* Read an 8 bit value from the file */
+{
+    int C = getc (F);
+    if (C == EOF) {
+       Error ("Read error (file corrupt?)");
+    }
+    return C;
+}
+
+
+
+unsigned Read16 (FILE* F)
+/* Read a 16 bit value from the file */
+{
+    unsigned Lo = Read8 (F);
+    unsigned Hi = Read8 (F);
+    return (Hi << 8) | Lo;
+}
+
+
+
+unsigned long Read32 (FILE* F)
+/* Read a 32 bit value from the file */
+{
+    unsigned long Lo = Read16 (F);
+    unsigned long Hi = Read16 (F);
+    return (Hi << 16) | Lo;
+}
+
+
+
+char* ReadStr (FILE* F)
+/* Read a string from the file (the memory will be malloc'ed) */
+{
+    /* Read the length byte */
+    unsigned Len = Read8 (F);
+
+    /* Allocate memory and read the string itself */
+    char* S = Xmalloc (Len + 1);
+    ReadData (F, S, Len);
+
+    /* Terminate the string and return it */
+    S [Len] = '\0';
+    return S;
+}
+
+
+
+void* ReadData (FILE* F, void* Data, unsigned Size)
+/* Read data from the file */
+{
+    if (fread (Data, 1, Size, F) != Size) {
+       Error ("Read error (file corrupt?)");
+    }
+    return Data;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ar65/fileio.h b/src/ar65/fileio.h
new file mode 100644 (file)
index 0000000..e38c460
--- /dev/null
@@ -0,0 +1,88 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                fileio.h                                  */
+/*                                                                           */
+/*                     File I/O for the ar65 archiver                       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FILEIO_H
+#define FILEIO_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val);
+/* Write an 8 bit value to the file */
+
+void Write16 (FILE* F, unsigned Val);
+/* Write a 16 bit value to the file */
+
+void Write32 (FILE* F, unsigned long Val);
+/* Write a 32 bit value to the file */
+
+void WriteStr (FILE* F, const char* S);
+/* Write a string to the file */
+
+void WriteData (FILE* F, const void* Data, unsigned Size);
+/* Write data to the file */
+
+unsigned Read8 (FILE* F);
+/* Read an 8 bit value from the file */
+
+unsigned Read16 (FILE* F);
+/* Read a 16 bit value from the file */
+
+unsigned long Read32 (FILE* F);
+/* Read a 32 bit value from the file */
+
+char* ReadStr (FILE* F);
+/* Read a string from the file (the memory will be malloc'ed) */
+
+void* ReadData (FILE* F, void* Data, unsigned Size);
+/* Read data from the file */
+
+
+
+/* End of fileio.h */
+
+#endif
+
+
+
diff --git a/src/ar65/global.c b/src/ar65/global.c
new file mode 100644 (file)
index 0000000..cc37aa2
--- /dev/null
@@ -0,0 +1,51 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*                 Global variables for the ar65 archiver                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+const char* ProgName               = "ar65";   /* Program name */
+
+int Verbose                        = 0;        /* Verbose operation flag */
+
+
+
diff --git a/src/ar65/global.h b/src/ar65/global.h
new file mode 100644 (file)
index 0000000..2a01fea
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*                 Global variables for the ar65 archiver                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+extern const char*     ProgName;       /* Program name */
+
+extern int             Verbose;        /* Verbose operation flag */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
diff --git a/src/ar65/library.c b/src/ar65/library.c
new file mode 100644 (file)
index 0000000..6fd3e7d
--- /dev/null
@@ -0,0 +1,470 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                library.c                                 */
+/*                                                                           */
+/*        Library data structures and helpers for the ar65 archiver         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/libdefs.h"
+#include "../common/symdefs.h"
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+#include "../common/bitops.h"
+
+#include "mem.h"
+#include "error.h"
+#include "global.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "exports.h"
+#include "library.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* File descriptor for the library file */
+FILE*                  NewLib = 0;
+static FILE*           Lib = 0;
+static const char*     LibName = 0;
+
+/* The library header */
+static LibHeader               Header = {
+    LIB_MAGIC,
+    LIB_VERSION
+};
+
+
+
+/*****************************************************************************/
+/*                      Writing file data structures                        */
+/*****************************************************************************/
+
+
+
+static void ReadHeader (void)
+/* Read the header of a library file */
+{
+    /* Seek to position zero */
+    fseek (Lib, 0, SEEK_SET);
+
+    /* Read the header fields, checking magic and version */
+    Header.Magic   = Read32 (Lib);
+    if (Header.Magic != LIB_MAGIC) {
+       Error ("`%s' is not a valid library file", LibName);
+    }
+    Header.Version = Read16 (Lib);
+    if (Header.Version != LIB_VERSION) {
+       Error ("Wrong data version in `%s'", LibName);
+    }
+    Header.Flags   = Read16 (Lib);
+    Header.IndexOffs = Read32 (Lib);
+}
+
+
+
+static void ReadIndexEntry (void)
+/* Read one entry in the index */
+{
+    /* Create a new entry and insert it into the list */
+    ObjData* O         = NewObjData ();
+
+    /* Module name/flags/MTime/Start/Size */
+    O->Name            = ReadStr (Lib);
+    O->Flags           = Read16 (Lib);
+    O->MTime    = Read32 (Lib);
+    O->Start    = Read32 (Lib);
+    O->Size     = Read32 (Lib);
+
+    /* Exports */
+    O->ExportSize = Read16 (Lib);
+    O->Exports    = Xmalloc (O->ExportSize);
+    ReadData (Lib, O->Exports, O->ExportSize);
+
+    /* Imports */
+    O->ImportSize = Read16 (Lib);
+    O->Imports    = Xmalloc (O->ImportSize);
+    ReadData (Lib, O->Imports, O->ImportSize);
+}
+
+
+
+static void ReadIndex (void)
+/* Read the index of a library file */
+{
+    unsigned Count;
+
+    /* Seek to the start of the index */
+    fseek (Lib, Header.IndexOffs, SEEK_SET);
+
+    /* Read the object file count and calculate the cross ref size */
+    Count = Read16 (Lib);
+
+    /* Read all entries in the index */
+    while (Count--) {
+       ReadIndexEntry ();
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                      Writing file data structures                        */
+/*****************************************************************************/
+
+
+
+static void WriteHeader (void)
+/* Write the header to the library file */
+{
+    /* Seek to position zero */
+    fseek (NewLib, 0, SEEK_SET);
+
+    /* Write the header fields */
+    Write32 (NewLib, Header.Magic);
+    Write16 (NewLib, Header.Version);
+    Write16 (NewLib, Header.Flags);
+    Write32 (NewLib, Header.IndexOffs);
+}
+
+
+
+static void WriteIndexEntry (ObjData* O)
+/* Write one index entry */
+{
+    /* Module name/flags/MTime/start/size */
+    WriteStr (NewLib, O->Name);
+    Write16  (NewLib, O->Flags & ~OBJ_HAVEDATA);
+    Write32  (NewLib, O->MTime);
+    Write32  (NewLib, O->Start);
+    Write32  (NewLib, O->Size);
+
+    /* Exports */
+    Write16 (NewLib, O->ExportSize);
+    WriteData (NewLib, O->Exports, O->ExportSize);
+
+    /* Imports */
+    Write16 (NewLib, O->ImportSize);
+    WriteData (NewLib, O->Imports, O->ImportSize);
+}
+
+
+
+static void WriteIndex (void)
+/* Write the index of a library file */
+{
+    ObjData* O;
+
+    /* Sync I/O in case the last operation was a read */
+    fseek (NewLib, 0, SEEK_CUR);
+
+    /* Remember the current offset in the header */
+    Header.IndexOffs = ftell (NewLib);
+
+    /* Write the object file count */
+    Write16 (NewLib, ObjCount);
+
+    /* Write the object files */
+    O = ObjRoot;
+    while (O) {
+       WriteIndexEntry (O);
+               O = O->Next;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            High level stuff                              */
+/*****************************************************************************/
+
+
+
+void LibOpen (const char* Name, int MustExist, int NeedTemp)
+/* Open an existing library and a temporary copy. If MustExist is true, the
+ * old library is expected to exist. If NeedTemp is true, a temporary library
+ * is created.
+ */
+{
+    /* Remember the name */
+    LibName = StrDup (Name);
+
+    /* Open the existing library for reading */
+    Lib = fopen (Name, "rb");
+    if (Lib == 0) {
+
+               /* File does not exist */
+               if (MustExist) {
+                   Error ("Library `%s' does not exist", Name);
+               } else {
+           Warning ("Library `%s' not found - will be created", Name);
+               }
+
+    } else {
+
+        /* We have an existing file: Read the header */
+       ReadHeader ();
+
+       /* Now read the existing index */
+               ReadIndex ();
+
+    }
+
+    if (NeedTemp) {
+       /* Create the temporary library */
+       NewLib = tmpfile ();
+       if (NewLib == 0) {
+           Error ("Cannot create temporary file: %s", strerror (errno));
+       }
+
+       /* Write a dummy header to the temp file */
+       WriteHeader ();
+    }
+}
+
+
+
+unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
+/* Copy data from F to the temp library file, return the start position in
+ * the temporary library file.
+ */
+{
+    unsigned char Buf [4096];
+
+    /* Remember the position */
+    unsigned long Pos = ftell (NewLib);
+
+    /* Copy loop */
+    while (Bytes) {
+       unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
+       ReadData (F, Buf, Count);
+       WriteData (NewLib, Buf, Count);
+       Bytes -= Count;
+    }
+
+    /* Return the start position */
+    return Pos;
+}
+
+
+
+void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
+/* Copy data from the library file into another file */
+{
+    unsigned char Buf [4096];
+
+    /* Seek to the correct position */
+    fseek (Lib, Pos, SEEK_SET);
+
+    /* Copy loop */
+    while (Bytes) {
+       unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
+       ReadData (Lib, Buf, Count);
+       WriteData (F, Buf, Count);
+       Bytes -= Count;
+    }
+}
+
+
+
+static void SkipExpr (unsigned char** Buf)
+/* Skip an expression in Buf */
+{
+    /* Get the operation and skip it */
+    unsigned char Op = **Buf;
+    ++(*Buf);
+
+    /* Filter leaf nodes */
+    switch (Op) {
+
+       case EXPR_NULL:
+           return;
+
+        case EXPR_LITERAL:
+           /* 32 bit literal value */
+           *Buf += 4;
+           return;
+
+        case EXPR_SYMBOL:
+           /* 16 bit symbol index */
+           *Buf += 2;
+           return;
+
+        case EXPR_SEGMENT:
+           /* 8 bit segment number */
+           *Buf += 1;
+           return;
+    }
+
+    /* What's left are unary and binary nodes */
+    SkipExpr (Buf);                    /* Skip left */
+    SkipExpr (Buf);            /* Skip right */
+}
+
+
+
+static void LibCheckExports (ObjData* O)
+/* Insert all exports from the given object file into the global list
+ * checking for duplicates.
+ */
+{
+    char Name [256];
+
+    /* Get a pointer to the buffer */
+    unsigned char* Exports = O->Exports;
+
+    /* First two bytes are export count */
+    unsigned Lo = *Exports++;
+    unsigned Hi = *Exports++;
+    unsigned Count = (Hi << 8) + Lo;
+
+    /* Read the exports */
+    if (Verbose > 1) {
+        printf ("Module `%s' (%u exports):\n", O->Name, Count);
+    }
+    while (Count--) {
+
+       unsigned char Len;
+
+       /* Get the export tag */
+       unsigned char Tag = *Exports++;
+
+               /* Next thing is name of symbol */
+       Len = *Exports++;
+       memcpy (Name, Exports, Len);
+       Name [Len] = '\0';
+       Exports += Len;
+
+       /* Skip value of symbol */
+       if (Tag & EXP_EXPR) {
+           /* Expression tree */
+           SkipExpr (&Exports);
+       } else {
+           /* Constant 32 bit value */
+           Exports += 4;
+       }
+
+       /* Skip the position */
+       Exports += POS_SIZE;
+
+       /* Insert the name into the hash table */
+       if (Verbose > 1) {
+               printf ("  %s\n", Name);
+       }
+       ExpInsert (Name, O->Index);
+    }
+}
+
+
+
+void LibClose (void)
+/* Write remaining data, close both files and copy the temp file to the old
+ * filename
+ */
+{
+    /* Do we have a temporary library? */
+    if (NewLib) {
+
+       unsigned I;
+       unsigned char Buf [4096];
+       size_t Count;
+
+       /* Index the object files and make an array containing the objects */
+       MakeObjPool ();
+
+        /* Walk through the object file list, inserting exports into the
+        * export list checking for duplicates. Copy any data that is still
+        * in the old library into the new one.
+        */
+       for (I = 0; I < ObjCount; ++I) {
+
+           /* Get a pointer to the object */
+           ObjData* O = ObjPool [I];
+
+           /* Check exports, make global export table */
+           LibCheckExports (O);
+
+           /* Copy data if needed */
+           if ((O->Flags & OBJ_HAVEDATA) == 0) {
+               /* Data is still in the old library */
+               fseek (Lib, O->Start, SEEK_SET);
+               O->Start = ftell (NewLib);
+               LibCopyTo (Lib, O->Size);
+               O->Flags |= OBJ_HAVEDATA;
+           }
+       }
+
+       /* Write the index */
+       WriteIndex ();
+
+       /* Write the updated header */
+       WriteHeader ();
+
+       /* Close the file */
+       if (Lib && fclose (Lib) != 0) {
+           Error ("Error closing library: %s", strerror (errno));
+       }
+
+       /* Reopen the library and truncate it */
+       Lib = fopen (LibName, "wb");
+       if (Lib == 0) {
+           Error ("Cannot open library `%s' for writing: %s",
+                  LibName, strerror (errno));
+       }
+
+       /* Copy the new library to the new one */
+       fseek (NewLib, 0, SEEK_SET);
+       while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
+           if (fwrite (Buf, 1, Count, Lib) != Count) {
+               Error ("Cannot write to `%s': %s", LibName, strerror (errno));
+           }
+       }
+    }
+
+    /* Close both files */
+    if (Lib && fclose (Lib) != 0) {
+       Error ("Problem closing `%s': %s", LibName, strerror (errno));
+    }
+    if (NewLib && fclose (NewLib) != 0) {
+       Error ("Problem closing temporary library file: %s", strerror (errno));
+    }
+}
+
+
+
diff --git a/src/ar65/library.h b/src/ar65/library.h
new file mode 100644 (file)
index 0000000..bd4b6ed
--- /dev/null
@@ -0,0 +1,88 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                library.h                                 */
+/*                                                                           */
+/*        Library data structures and helpers for the ar65 archiver         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LIBRARY_H
+#define LIBRARY_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* File descriptor for the new library file */
+extern FILE*   NewLib;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void LibOpen (const char* Name, int MustExist, int NeedTemp);
+/* Open an existing library and a temporary copy. If MustExist is true, the
+ * old library is expected to exist. If NeedTemp is true, a temporary library
+ * is created.
+ */
+
+unsigned long LibCopyTo (FILE* F, unsigned long Bytes);
+/* Copy data from F to the temp library file, return the start position in
+ * the temporary library file.
+ */
+
+void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F);
+/* Copy data from the library file into another file */
+
+void LibClose (void);  
+/* Write remaining data, close both files and copy the temp file to the old
+ * filename
+ */
+
+
+
+/* End of library.h */
+
+#endif
+
+
+
diff --git a/src/ar65/list.c b/src/ar65/list.c
new file mode 100644 (file)
index 0000000..c54f65e
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 list.c                                   */
+/*                                                                           */
+/*                  Module listing for the ar65 archiver                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "objdata.h"
+#include "library.h"
+#include "list.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ListObjFiles (int argc, char* argv [])
+/* List modules in a library */
+{
+    ObjData* O;
+
+    /* Check the argument count */
+    if (argc <= 0) {
+       Error ("No library name given");
+    }
+    if (argc > 2) {
+       Error ("Too many arguments");
+    }
+
+    /* Open the library, read the index */
+    LibOpen (argv [0], 1, 0);
+
+    /* List the modules */
+    O = ObjRoot;
+    while (O) {
+       printf ("%s\n", O->Name);
+       O = O->Next;
+    }
+
+    /* Create a new library file and close the old one */
+    LibClose ();
+
+    /* Successful end */
+    exit (EXIT_SUCCESS);
+}
+
+
+
diff --git a/src/ar65/list.h b/src/ar65/list.h
new file mode 100644 (file)
index 0000000..09ac508
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 list.h                                   */
+/*                                                                           */
+/*                  Module listing for the ar65 archiver                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LIST_H
+#define LIST_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ListObjFiles (int argc, char* argv []);
+/* List modules in a library */
+
+
+
+/* End of list.h */
+
+#endif
+
+
+
+
diff --git a/src/ar65/main.c b/src/ar65/main.c
new file mode 100644 (file)
index 0000000..1201901
--- /dev/null
@@ -0,0 +1,140 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                 main.c                                   */
+/*                                                                          */
+/*                   Main program for the ar65 archiver                     */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "add.h"
+#include "del.h"
+#include "list.h"
+#include "extract.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+    fprintf (stderr,
+            "Usage: %s <operation> lib file|module ...\n"
+            "Operation is one of:\n"
+            "\ta\tAdd modules\n"
+            "\td\tDelete modules\n"
+            "\tl\tList library contents\n"
+            "\tx\tExtract modules\n"
+            "\tV\tPrint the archiver version\n",
+            ProgName);
+    exit (EXIT_FAILURE);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+    int I;
+
+    /* We must have a file name */
+    if (argc < 2) {
+       Usage ();
+    }
+
+    /* Check the parameters */
+    I = 1;
+    while (I < argc) {
+
+       /* Get the argument */
+       const char* Arg = argv [I];
+
+       /* Check for an option */
+       if (strlen (Arg) != 1) {
+           Usage ();
+       }
+       switch (Arg [0]) {
+
+           case 'a':
+               AddObjFiles (argc - I - 1, &argv [I+1]);
+               break;
+
+           case 'd':
+               DelObjFiles (argc - I - 1, &argv [I+1]);
+               break;
+
+           case 'l':
+               ListObjFiles (argc - I - 1, &argv [I+1]);
+               break;
+
+           case 'v':
+               ++Verbose;
+               break;
+
+           case 'x':
+               ExtractObjFiles (argc - I - 1, &argv [I+1]);
+               break;
+
+           case 'V':
+               fprintf (stderr,
+                        "ar65 V%u.%u.%u - (C) Copyright 1998-1999 Ullrich von Bassewitz\n",
+                        VER_MAJOR, VER_MINOR, VER_PATCH);
+               break;
+
+           default:
+               fprintf (stderr, "Unknown option: %s\n", Arg);
+               Usage ();
+
+       }
+
+       /* Next argument */
+       ++I;
+    }
+
+    /* Return an apropriate exit code */
+    return EXIT_SUCCESS;
+}
+
+
+
diff --git a/src/ar65/make/gcc.mak b/src/ar65/make/gcc.mak
new file mode 100644 (file)
index 0000000..fae3bd3
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# gcc Makefile for ar65
+#
+
+CFLAGS         = -g -O2 -Wall
+CC     = gcc
+LDFLAGS        =
+
+OBJS =         add.o           \
+       del.o           \
+       error.o         \
+       exports.o       \
+       extract.o       \
+       fileio.o        \
+       global.o        \
+       library.o       \
+       list.o          \
+       main.o          \
+       mem.o           \
+       objdata.o       \
+       objfile.o
+
+LIBS = ../common/common.a
+
+
+EXECS = ar65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ar65:   $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+       rm -f *~ core
+
+zap:   clean
+       rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
+
diff --git a/src/ar65/make/watcom.mak b/src/ar65/make/watcom.mak
new file mode 100644 (file)
index 0000000..7be93c9
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# ar65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = add.obj         \
+       del.obj         \
+       error.obj       \
+       exports.obj     \
+       extract.obj     \
+       fileio.obj      \
+       global.obj      \
+       library.obj     \
+       list.obj        \
+       main.obj        \
+       mem.obj         \
+       objdata.obj     \
+       objfile.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:           ar65
+
+ar65:          ar65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ar65.exe:      $(OBJS) $(LIBS)
+       $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE add.obj
+FILE del.obj
+FILE error.obj
+FILE exports.obj
+FILE extract.obj
+FILE fileio.obj
+FILE global.obj
+FILE library.obj
+FILE list.obj
+FILE main.obj
+FILE mem.obj
+FILE objdata.obj
+FILE objfile.obj
+LIBRARY ..\common\common.lib
+|
+
+
+clean:
+       @if exist *.obj del *.obj
+       @if exist ar65.exe del ar65.exe
+
+strip:
+               @-wstrip ar65.exe
+
diff --git a/src/ar65/mem.c b/src/ar65/mem.c
new file mode 100644 (file)
index 0000000..7d5d175
--- /dev/null
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                  mem.c                                   */
+/*                                                                          */
+/*                 Memory allocation for the ar65 archiver                  */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+    void* p;
+
+    p = malloc (size);
+    if (p == 0 && size != 0) {
+       Error ("Out of memory");
+    }
+
+    /* Return a pointer to the block */
+    return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+    free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+    unsigned len;
+
+    len = strlen (s) + 1;
+    return memcpy (Xmalloc (len), s, len);
+}
+
+
+
diff --git a/src/ar65/mem.h b/src/ar65/mem.h
new file mode 100644 (file)
index 0000000..a896131
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.h                                   */
+/*                                                                           */
+/*                 Memory allocation for the ar65 archiver                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
diff --git a/src/ar65/objdata.c b/src/ar65/objdata.c
new file mode 100644 (file)
index 0000000..0fd32d3
--- /dev/null
@@ -0,0 +1,207 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objdata.c                                 */
+/*                                                                           */
+/*             Handling object file data for the ar65 archiver              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Object data list management */
+unsigned       ObjCount = 0;   /* Count of object files in the list */
+ObjData*       ObjRoot  = 0;   /* List of object files */
+ObjData*       ObjLast  = 0;   /* Last entry in list */
+ObjData**              ObjPool  = 0;   /* Object files as array */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void)
+/* Allocate a new structure on the heap, insert it into the list, return it */
+{
+    /* Allocate memory */
+    ObjData* O = Xmalloc (sizeof (ObjData));
+
+    /* Initialize the data */
+    O->Next       = 0;
+    O->Name      = 0;
+    O->Index     = ~0;
+    O->Flags             = 0;
+    O->MTime     = 0;
+    O->Start     = 0;
+    O->Size      = 0;
+    O->ImportSize = 0;
+    O->Imports    = 0;
+    O->ExportSize = 0;
+    O->Exports    = 0;
+
+    /* Link it into the list */
+    if (ObjLast) {
+       ObjLast->Next = O;
+       ObjLast       = O;
+    } else {
+       /* First entry */
+       ObjRoot = ObjLast = O;
+    }
+
+    /* One object file more now */
+    ++ObjCount;
+
+    /* Return the new entry */
+    return O;
+}
+
+
+
+void FreeObjData (ObjData* O)
+/* Free a complete struct */
+{
+    Xfree (O->Name);
+    Xfree (O->Imports);
+    Xfree (O->Exports);
+    Xfree (O);
+}
+
+
+
+ObjData* FindObjData (const char* Module)
+/* Search for the module with the given name and return it. Return NULL if the
+ * module is not in the list.
+ */
+{
+    /* Hmm. Maybe we should hash the module names? */
+    ObjData* O = ObjRoot;
+    while (O) {
+       if (strcmp (O->Name, Module) == 0) {
+           return O;
+       }
+       O = O->Next;
+    }
+    return 0;
+}
+
+
+
+void DelObjData (const char* Module)
+/* Delete the object module from the list */
+{
+    ObjData* O = ObjRoot;
+    ObjData* Last = 0;
+    while (O) {
+       if (strcmp (O->Name, Module) == 0) {
+           /* Found the module, remove it from the list */
+           if (Last == 0) {
+               /* This was the first entry in the list */
+               ObjRoot = O->Next;
+           } else {
+               Last->Next = O->Next;
+           }
+           if (ObjLast == O) {
+               /* O was the last object in the list */
+               ObjLast = Last;
+           }
+           --ObjCount;
+
+           /* Free the entry */
+           FreeObjData (O);
+
+           /* Done */
+           return;
+       }
+       Last = O;
+       O = O->Next;
+    }
+
+    /* Not found! */
+    Warning ("Module `%s' not found in library", Module);
+}
+
+
+
+void MakeObjPool (void)
+/* Allocate memory, index the entries and make the ObjPool valid */
+{
+    ObjData* O;
+    unsigned Index;
+
+    /* Allocate memory for the pool */
+    ObjPool = Xmalloc (ObjCount * sizeof (ObjData*));
+
+    /* Setup the pointers and index the objects */
+    Index = 0;
+    O = ObjRoot;
+    while (O) {
+
+       /* Safety */
+       CHECK (Index < ObjCount);
+
+       /* Set the Index */
+       O->Index = Index;
+
+       /* Set the pool pointer */
+       ObjPool [Index] = O;
+
+       /* Next object */
+       ++Index;
+       O = O->Next;
+    }
+}
+
+
+
+const char* GetObjName (unsigned Index)
+/* Get the name of a module by index */
+{
+    PRECONDITION (ObjPool != 0 && Index < ObjCount && ObjPool [Index] != 0);
+    return ObjPool [Index]->Name;
+}
+
+
+
+
+
diff --git a/src/ar65/objdata.h b/src/ar65/objdata.h
new file mode 100644 (file)
index 0000000..66acb76
--- /dev/null
@@ -0,0 +1,111 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objdata.h                                 */
+/*                                                                           */
+/*             Handling object file data for the ar65 archiver              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDATA_H
+#define OBJDATA_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Values for the Flags field */
+#define        OBJ_HAVEDATA    0x0001          /* The object data is in the tmp file */
+#define OBJ_MARKED     0x0002          /* Generic marker bit */
+
+
+/* Internal structure holding object file data */
+typedef struct ObjData_ ObjData;
+struct ObjData_ {
+    ObjData*           Next;           /* Linked list of all objects */
+    char*              Name;           /* Module name */
+    unsigned           Index;          /* Module index */
+    unsigned           Flags;
+    unsigned long      MTime;          /* Modifiation time of object file */
+    unsigned long      Start;          /* Start offset of data in library */
+    unsigned long      Size;           /* Size of data in library */
+    unsigned long              ImportSize;     /* Size of imports */
+    void*              Imports;        /* Imports as raw data */
+    unsigned long      ExportSize;     /* Size of exports */
+    void*              Exports;        /* Exports as raw data */
+};
+
+
+
+/* Object data list management */
+extern unsigned                ObjCount;       /* Count of files in the list */
+extern ObjData*                ObjRoot;        /* List of object files */
+extern ObjData*                ObjLast;        /* Last entry in list */
+extern ObjData**       ObjPool;        /* Object files as array */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void);
+/* Allocate a new structure on the heap, insert it into the list, return it */
+
+void FreeObjData (ObjData* O);
+/* Free a complete struct */
+
+ObjData* FindObjData (const char* Module);
+/* Search for the module with the given name and return it. Return NULL if the
+ * module is not in the list.
+ */
+
+void DelObjData (const char* Module);
+/* Delete the object module from the list */
+
+void MakeObjPool (void);
+/* Allocate memory, index the entries and make the ObjPool valid */
+
+const char* GetObjName (unsigned Index);
+/* Get the name of a module by index */
+
+
+
+/* End of objdata.h */
+
+#endif
+
+
+
diff --git a/src/ar65/objfile.c b/src/ar65/objfile.c
new file mode 100644 (file)
index 0000000..c485c6e
--- /dev/null
@@ -0,0 +1,288 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                objfile.c                                 */
+/*                                                                          */
+/*               Object file handling for the ar65 archiver                 */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#ifdef __WATCOMC__
+/* Watcom has the file in the wrong directory */
+#  include <sys/utime.h>
+#else
+#  include <sys/types.h>               /* FreeBSD needs this */
+#  include <utime.h>
+#endif
+#include <time.h>
+#include <sys/stat.h>
+
+#include "error.h"
+#include "mem.h"
+#include "objdata.h"
+#include "fileio.h"
+#include "library.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static const char* GetModule (const char* Name)
+/* Get a module name from the file name */
+{
+    /* Make a module name from the file name */
+    const char* Module = Name + strlen (Name);
+    while (Module > Name) {
+       --Module;
+       if (*Module == '/' || *Module == '\\') {
+           ++Module;
+           break;
+       }
+    }
+    if (*Module == 0) {
+       Error ("Cannot make module name from `%s'", Name);
+    }
+    return Module;
+}
+
+
+
+void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
+/* Read the header of the object file checking the signature */
+{
+    H->Magic     = Read32 (Obj);
+    if (H->Magic != OBJ_MAGIC) {
+       Error ("`%s' is not an object file", Name);
+    }
+    H->Version   = Read16 (Obj);
+    if (H->Version != OBJ_VERSION) {
+       Error ("Object file `%s' has wrong version", Name);
+    }
+    H->Flags     = Read16 (Obj);
+    H->OptionOffs = Read32 (Obj);
+    H->OptionSize = Read32 (Obj);
+    H->FileOffs   = Read32 (Obj);
+    H->FileSize   = Read32 (Obj);
+    H->SegOffs   = Read32 (Obj);
+    H->SegSize   = Read32 (Obj);
+    H->ImportOffs = Read32 (Obj);
+    H->ImportSize = Read32 (Obj);
+    H->ExportOffs = Read32 (Obj);
+    H->ExportSize = Read32 (Obj);
+    H->DbgSymOffs = Read32 (Obj);
+    H->DbgSymSize = Read32 (Obj);
+}
+
+
+
+void ObjWriteHeader (FILE* Obj, ObjHeader* H)
+/* Write the header of the object file */
+{
+    Write32 (Obj, H->Magic);
+    Write16 (Obj, H->Version);
+    Write16 (Obj, H->Flags);
+    Write32 (Obj, H->OptionOffs);
+    Write32 (Obj, H->OptionSize);
+    Write32 (Obj, H->FileOffs);
+    Write32 (Obj, H->FileSize);
+    Write32 (Obj, H->SegOffs);
+    Write32 (Obj, H->SegSize);
+    Write32 (Obj, H->ImportOffs);
+    Write32 (Obj, H->ImportSize);
+    Write32 (Obj, H->ExportOffs);
+    Write32 (Obj, H->ExportSize);
+    Write32 (Obj, H->DbgSymOffs);
+    Write32 (Obj, H->DbgSymSize);
+}
+
+
+
+void ObjAdd (const char* Name)
+/* Add an object file to the library */
+{
+    struct stat StatBuf;
+    const char* Module;
+    ObjHeader H;
+    ObjData* O;
+
+    /* Open the object file */
+    FILE* Obj = fopen (Name, "rb");
+    if (Obj == 0) {
+       Error ("Could not open `%s': %s", Name, strerror (errno));
+    }
+
+    /* Get the modification time of the object file */
+    if (fstat (fileno (Obj), &StatBuf) != 0) {
+       Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
+    }
+
+    /* Read and check the header */
+    ObjReadHeader (Obj, &H, Name);
+
+    /* Make a module name from the file name */
+    Module = GetModule (Name);
+
+    /* Check if we already have a module with this name */
+    O = FindObjData (Module);
+    if (O == 0) {
+       /* Not found, create a new entry */
+       O = NewObjData ();
+    } else {
+       /* Found - check the file modification times of the internal copy
+        * and the external one.
+        */
+       if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
+           Warning ("Replacing module `%s' by older version", O->Name);
+       }
+    }
+
+    /* Initialize the object module data structure */
+    O->Name      = StrDup (Module);
+    O->Flags     = OBJ_HAVEDATA;
+    O->MTime     = StatBuf.st_mtime;
+    O->ImportSize = H.ImportSize;
+    O->Imports   = Xmalloc (O->ImportSize);
+    O->ExportSize = H.ExportSize;
+    O->Exports   = Xmalloc (O->ExportSize);
+
+    /* Read imports and exports */
+    fseek (Obj, H.ImportOffs, SEEK_SET);
+    ReadData (Obj, O->Imports, O->ImportSize);
+    fseek (Obj, H.ExportOffs, SEEK_SET);
+    ReadData (Obj, O->Exports, O->ExportSize);
+
+    /* Skip the object file header */
+    O->Start = ftell (NewLib);
+    fseek (NewLib, OBJ_HDR_SIZE, SEEK_CUR);
+
+    /* Copy the remaining sections */
+    fseek (Obj, H.DbgSymOffs, SEEK_SET);
+    H.DbgSymOffs = LibCopyTo (Obj, H.DbgSymSize) - O->Start;
+    fseek (Obj, H.OptionOffs, SEEK_SET);
+    H.OptionOffs = LibCopyTo (Obj, H.OptionSize) - O->Start;
+    fseek (Obj, H.SegOffs, SEEK_SET);
+    H.SegOffs = LibCopyTo (Obj, H.SegSize) - O->Start;
+    fseek (Obj, H.FileOffs, SEEK_SET);
+    H.FileOffs = LibCopyTo (Obj, H.FileSize) - O->Start;
+
+    /* Calculate the amount of data written */
+    O->Size = ftell (NewLib) - O->Start;
+
+    /* Clear the remaining header fields */
+    H.ImportOffs = H.ImportSize = 0;
+    H.ExportOffs = H.ExportSize = 0;
+
+    /* Seek back and write the updated header */
+    fseek (NewLib, O->Start, SEEK_SET);
+    ObjWriteHeader (NewLib, &H);
+
+    /* Now seek again to end of file */
+    fseek (NewLib, 0, SEEK_END);
+
+    /* Done, close the file (we read it only, so no error check) */
+    fclose (Obj);
+}
+
+
+
+void ObjExtract (const char* Name)
+/* Extract a module from the library */
+{
+    unsigned long ImportStart;
+    unsigned long ExportStart;
+    struct utimbuf U;
+    ObjHeader H;
+    FILE* Obj;
+
+
+    /* Make a module name from the file name */
+    const char* Module = GetModule (Name);
+
+    /* Try to find the module in the library */
+    ObjData* O = FindObjData (Module);
+
+    /* Bail out if the module does not exist */
+    if (O == 0) {
+       Error ("Module `%s' not found in library", Module);
+    }
+
+    /* Open the output file */
+    Obj = fopen (Name, "w+b");
+    if (Obj == 0) {
+       Error ("Cannot open target file `%s': %s", Name, strerror (errno));
+    }
+
+    /* Copy the first four segments including the header to the new file */
+    LibCopyFrom (O->Start, O->Size, Obj);
+
+    /* Write imports and exports */
+    ImportStart = ftell (Obj);
+    WriteData (Obj, O->Imports, O->ImportSize);
+    ExportStart = ftell (Obj);
+    WriteData (Obj, O->Exports, O->ExportSize);
+
+    /* Seek back and read the header */
+    fseek (Obj, 0, SEEK_SET);
+    ObjReadHeader (Obj, &H, Name);
+
+    /* Update the header fields */
+    H.ImportOffs = ImportStart;
+    H.ImportSize = O->ImportSize;
+    H.ExportOffs = ExportStart;
+    H.ExportSize = O->ExportSize;
+
+    /* Write the changed header */
+    fseek (Obj, 0, SEEK_SET);
+    ObjWriteHeader (Obj, &H);
+
+    /* Close the file */
+    if (fclose (Obj) != 0) {
+       Error ("Problem closing object file `%s': %s", Name, strerror (errno));
+    }
+
+    /* Set access and modification time */
+    U.actime = O->MTime;
+    U.modtime = O->MTime;
+    if (utime (Name, &U) != 0) {
+       Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
+    }
+}
+
+
+
+
+
+
diff --git a/src/ar65/objfile.h b/src/ar65/objfile.h
new file mode 100644 (file)
index 0000000..50b05f9
--- /dev/null
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objfile.h                                 */
+/*                                                                           */
+/*               Object file handling for the ar65 archiver                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include <stdio.h>
+
+#include "../common/objdefs.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name);
+/* Read the header of the object file checking the signature */
+
+void ObjWriteHeader (FILE* Obj, ObjHeader* H);
+/* Write the header of the object file */
+
+void ObjAdd (const char* Name);
+/* Add an object file to the library */
+
+void ObjExtract (const char* Name);
+/* Extract a module from the library */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
diff --git a/src/ca65/.cvsignore b/src/ca65/.cvsignore
new file mode 100644 (file)
index 0000000..d745ea8
--- /dev/null
@@ -0,0 +1,2 @@
+.depend
+ca65
diff --git a/src/ca65/condasm.c b/src/ca65/condasm.c
new file mode 100644 (file)
index 0000000..831802c
--- /dev/null
@@ -0,0 +1,418 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                condasm.c                                 */
+/*                                                                           */
+/*                  Conditional assembly support for ca65                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "expr.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "condasm.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Maximum count of nested .ifs */
+#define MAX_IFS                32
+
+/* Set of bitmapped flags for the if descriptor */
+enum {
+    ifNone     = 0x0000,               /* No flag */
+    ifCond     = 0x0001,               /* IF condition was true */
+    ifElse     = 0x0002,               /* We had a .ELSE branch */
+    ifNeedTerm = 0x0004                /* Need .ENDIF termination */
+};
+
+
+
+/*****************************************************************************/
+/*                              struct IfDesc                               */
+/*****************************************************************************/
+
+
+
+/* One .IF descriptor */
+typedef struct IfDesc_ IfDesc;
+struct IfDesc_ {
+    unsigned           Flags;          /* Bitmapped flags, see above */
+    FilePos            Pos;            /* File position of the .IF */
+    const char* Name;          /* Name of the directive */
+};
+
+/* The .IF stack */
+static IfDesc IfStack [MAX_IFS];
+static unsigned IfCount = 0;
+
+
+
+static IfDesc* AllocIf (const char* Directive, int NeedTerm)
+/* Alloc a new element from the .IF stack */
+{
+    IfDesc* ID;
+
+    /* Check for stack overflow */
+    if (IfCount >= MAX_IFS) {
+               Error (ERR_IF_NESTING);
+    }
+
+    /* Alloc one element */
+    ID = &IfStack [IfCount++];
+
+    /* Initialize elements */
+    ID->Flags = NeedTerm? ifNeedTerm : ifNone;
+    ID->Pos   = CurPos;
+    ID->Name  = Directive;
+
+    /* Return the result */
+    return ID;
+}
+
+
+
+static IfDesc* GetCurrentIf (void)
+/* Return the current .IF descriptor */
+{
+    if (IfCount == 0) {
+               return 0;
+    } else {
+        return &IfStack [IfCount-1];
+    }
+}
+
+
+
+static void FreeIf (void)
+/* Free all .IF descriptors until we reach one with the NeedTerm bit set */
+{
+    int Done = 0;
+    do {
+               IfDesc* D = GetCurrentIf();
+               if (D == 0) {
+                   Error (ERR_UNEXPECTED, ".ENDIF");
+               } else {
+                   Done = (D->Flags & ifNeedTerm) != 0;
+            --IfCount;
+               }
+    } while (!Done);
+}
+
+
+
+static int GetCurrentIfCond (void)
+/* Return the current condition based on all conditions on the stack */
+{
+    unsigned Count;
+    for (Count = 0; Count < IfCount; ++Count) {
+               if ((IfStack[Count].Flags & ifCond) == 0) {
+                   return 0;
+               }
+    }
+    return 1;
+}
+
+
+
+static void SetIfCond (IfDesc* ID, int C)
+/* Set the .IF condition */
+{
+    if (C) {
+               ID->Flags |= ifCond;
+    } else {
+               ID->Flags &= ~ifCond;
+    }
+}
+
+
+
+static void InvertIfCond (IfDesc* ID)
+/* Invert the current condition */
+{
+    ID->Flags ^= ifCond;
+}
+
+
+
+static int GetElse (const IfDesc* ID)
+/* Return true if we had a .ELSE */
+{
+    return (ID->Flags & ifElse) != 0;
+}
+
+
+
+static void SetElse (IfDesc* ID, int E)
+/* Set the .ELSE flag */
+{
+    if (E) {
+       ID->Flags |= ifElse;
+    } else {
+       ID->Flags &= ~ifElse;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void DoConditionals (void)
+/* Catch all for conditional directives */
+{
+    IfDesc* D;
+
+    int IfCond = GetCurrentIfCond ();
+    do {
+
+       switch (Tok) {
+
+           case TOK_ELSE:
+                       D = GetCurrentIf ();
+               if (D == 0) {
+                   Error (ERR_UNEXPECTED, ".ELSE");
+                       } else if (GetElse(D)) {
+                   /* We already had a .ELSE ! */
+                   Error (ERR_DUPLICATE_ELSE);
+                       } else {
+                   /* Allow an .ELSE */
+                   InvertIfCond (D);
+                   SetElse (D, 1);
+                   D->Pos = CurPos;
+                   D->Name = ".ELSE";
+                   IfCond = GetCurrentIfCond ();
+               }
+               NextTok ();
+                       break;
+
+                   case TOK_ELSEIF:
+               D = GetCurrentIf ();
+               if (D == 0) {
+                   Error (ERR_UNEXPECTED, ".ELSEIF");
+               } else if (GetElse(D)) {
+                   /* We already had a .ELSE */
+                   Error (ERR_DUPLICATE_ELSE);
+               } else {
+                   /* Handle as if there was an .ELSE first */
+                   InvertIfCond (D);
+                   SetElse (D, 1);
+
+                   /* Allocate and prepare a new descriptor */
+                           D = AllocIf (".ELSEIF", 0);
+                   NextTok ();
+
+                   /* Ignore the new condition if we are inside a false .ELSE
+                    * branch. This way we won't get any errors about undefined
+                    * symbols or similar...
+                    */
+                   if (IfCond == 0) {
+                       SetIfCond (D, ConstExpression ());
+                   }
+
+                   /* Get the new overall condition */
+                   IfCond = GetCurrentIfCond ();
+               }
+               break;
+
+           case TOK_ENDIF:
+               /* We're done with this .IF.. - remove the descriptor(s) */
+               FreeIf ();
+
+               /* Be sure not to read the next token until the .IF stack
+                * has been cleanup up, since we may be at end of file.
+                */
+               NextTok ();
+
+               /* Get the new overall condition */
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IF:
+               D = AllocIf (".IF", 1);
+               NextTok ();
+               if (IfCond) {
+                   SetIfCond (D, ConstExpression ());
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFBLANK:
+               D = AllocIf (".IFBLANK", 1);
+               NextTok ();
+               if (IfCond) {
+                   SetIfCond (D, Tok == TOK_SEP);
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFCONST:
+               D = AllocIf (".IFCONST", 1);
+               NextTok ();
+               if (IfCond) {
+                   ExprNode* Expr = Expression();
+                   SetIfCond (D, IsConstExpr (Expr));
+                   FreeExpr (Expr);
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFDEF:
+               D = AllocIf (".IFDEF", 1);
+               NextTok ();
+               if (IfCond) {
+                   if (Tok != TOK_IDENT) {
+                       ErrorSkip (ERR_IDENT_EXPECTED);
+                   } else {
+                       SetIfCond (D, SymIsDef (SVal));
+                       NextTok ();
+                   }
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFNBLANK:
+               D = AllocIf (".IFNBLANK", 1);
+               NextTok ();
+               if (IfCond) {
+                   SetIfCond (D, Tok != TOK_SEP);
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFNCONST:
+               D = AllocIf (".IFNCONST", 1);
+               NextTok ();
+               if (IfCond) {
+                   ExprNode* Expr = Expression();
+                   SetIfCond (D, !IsConstExpr (Expr));
+                   FreeExpr (Expr);
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFNDEF:
+               D = AllocIf (".IFNDEF", 1);
+               NextTok ();
+               if (IfCond) {
+                   if (Tok != TOK_IDENT) {
+                       ErrorSkip (ERR_IDENT_EXPECTED);
+                   } else {
+                       SetIfCond (D, !SymIsDef (SVal));
+                       NextTok ();
+                   }
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFNREF:
+               D = AllocIf (".IFNREF", 1);
+               NextTok ();
+               if (IfCond) {
+                   if (Tok != TOK_IDENT) {
+                       ErrorSkip (ERR_IDENT_EXPECTED);
+                   } else {
+                       SetIfCond (D, !SymIsRef (SVal));
+                       NextTok ();
+                   }
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           case TOK_IFP02:
+               break;
+
+           case TOK_IFP816:
+               break;
+
+           case TOK_IFPC02:
+               break;
+
+           case TOK_IFREF:
+               D = AllocIf (".IFREF", 1);
+               NextTok ();
+               if (IfCond) {
+                   if (Tok != TOK_IDENT) {
+                       ErrorSkip (ERR_IDENT_EXPECTED);
+                   } else {
+                       SetIfCond (D, SymIsRef (SVal));
+                       NextTok ();
+                   }
+               }
+               IfCond = GetCurrentIfCond ();
+               break;
+
+           default:
+               // Skip tokens
+               NextTok ();
+
+       }
+
+    } while (IfCond == 0 && Tok != TOK_EOF);
+}
+
+
+
+void CheckOpenIfs (void)
+/* Called from the scanner before closing an input file. Will check for any
+ * open .ifs in this file.
+ */
+{
+    while (1) {
+       /* Get the current file number and check if the topmost entry on the
+        * .IF stack was inserted with this file number
+        */
+       IfDesc* D = GetCurrentIf ();
+       if (D == 0) {
+           /* There are no open .IFs */
+           break;
+       }
+         
+       if (D->Pos.Name != CurPos.Name) {
+           /* The .if is from another file, bail out */
+           break;
+       }
+
+               /* Start of .if is in the file we're about to leave */
+       PError (&D->Pos, ERR_OPEN_IF);
+       FreeIf ();
+    }
+}
+
+
+
diff --git a/src/ca65/condasm.h b/src/ca65/condasm.h
new file mode 100644 (file)
index 0000000..3994b39
--- /dev/null
@@ -0,0 +1,62 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                condasm.h                                 */
+/*                                                                           */
+/*                  Conditional assembly support for ca65                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef CONDASM_H
+#define CONDASM_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void DoConditionals (void);
+/* Catch all for conditional directives */
+
+void CheckOpenIfs (void);
+/* Called from the scanner before closing an input file. Will check for any
+ * open .ifs in this file.
+ */
+
+
+
+/* End of condasm.h */
+
+#endif
+
+
+
diff --git a/src/ca65/ea.c b/src/ca65/ea.c
new file mode 100644 (file)
index 0000000..8bc8e81
--- /dev/null
@@ -0,0 +1,198 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  ea.c                                    */
+/*                                                                           */
+/*          Effective address parsing for the ca65 macroassembler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "expr.h"
+#include "instr.h"
+#include "scanner.h"
+#include "ea.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank)
+/* Parse an effective address, return the possible modes in AddrMode, and the
+ * expression involved (if any) in Expr.
+ */
+{
+    /* Clear the expressions */
+    *Bank = *Expr = 0;
+
+
+    if (Tok == TOK_SEP) {
+
+       *AddrMode = AM_IMPLICIT;
+
+    } else if (Tok == TOK_HASH) {
+
+       /* #val */
+       NextTok ();
+       *Expr = Expression ();
+       *AddrMode = AM_IMM;
+
+    } else if (Tok == TOK_A) {
+
+       NextTok ();
+       *AddrMode = AM_ACCU;
+
+    } else if (Tok == TOK_LBRACK) {
+
+       /* [dir] or [dir],y */
+       NextTok ();
+       *Expr = Expression ();
+       Consume (TOK_RBRACK, ERR_RBRACK_EXPECTED);
+       if (Tok == TOK_COMMA) {
+           /* [dir],y */
+           NextTok ();
+           Consume (TOK_Y, ERR_Y_EXPECTED);
+           *AddrMode = AM_DIR_IND_LONG_Y;
+       } else {
+           /* [dir] */
+           *AddrMode = AM_DIR_IND_LONG;
+       }
+
+    } else if (Tok == TOK_LPAREN) {
+
+       /* One of the indirect modes */
+       NextTok ();
+       *Expr = Expression ();
+
+       if (Tok == TOK_COMMA) {
+
+           /* (expr,X) or (rel,S),y */
+           NextTok ();
+           if (Tok == TOK_X) {
+               /* (adr,x) */
+               NextTok ();
+                       *AddrMode = AM_ABS_X_IND | AM_DIR_X_IND;
+               ConsumeRParen ();
+           } else if (Tok == TOK_S) {
+               /* (rel,s),y */
+               NextTok ();
+               *AddrMode = AM_STACK_REL_IND_Y;
+               ConsumeRParen ();
+               ConsumeComma ();
+               Consume (TOK_Y, ERR_Y_EXPECTED);
+           } else {
+               Error (ERR_SYNTAX);
+           }
+
+               } else {
+
+           /* (adr) or (adr),y */
+           ConsumeRParen ();
+           if (Tok == TOK_COMMA) {
+               /* (adr),y */
+               NextTok ();
+               Consume (TOK_Y, ERR_Y_EXPECTED);
+               *AddrMode = AM_DIR_IND_Y;
+           } else {
+               /* (adr) */
+               *AddrMode = AM_ABS_IND | AM_DIR_IND;
+           }
+       }
+
+    } else {
+
+       /* Remaining stuff:
+        *
+        * adr
+        * bank.adr
+        * adr,x
+        * bank.adr,x
+        * adr,y
+        * adr,s
+        */
+               *Expr = Expression ();
+
+               if (Tok == TOK_DOT) {
+
+                   /* Expr was a bank specification: bank.adr or bank.adr,x */
+                   *Bank = *Expr;
+                   NextTok ();
+                   *Expr = Expression ();
+                   if (Tok == TOK_COMMA) {
+                       /* bank.adr,x */
+                       NextTok ();
+                       Consume (TOK_X, ERR_X_EXPECTED);
+                       *AddrMode = AM_ABS_LONG_X;
+                   } else {
+                       /* bank.adr */
+                       *AddrMode = AM_ABS_LONG;
+                   }
+
+       } else {
+
+           if (Tok == TOK_COMMA) {
+
+               NextTok ();
+               switch (Tok) {
+
+                   case TOK_X:
+                               *AddrMode = AM_ABS_X | AM_DIR_X;
+                       NextTok ();
+                       break;
+
+                   case TOK_Y:
+                       *AddrMode = AM_ABS_Y | AM_DIR_Y;
+                       NextTok ();
+                       break;
+
+                   case TOK_S:
+                       *AddrMode = AM_STACK_REL;
+                       NextTok ();
+                       break;
+
+                   default:
+                       Error (ERR_SYNTAX);
+
+               }
+
+           } else {
+
+               *AddrMode = AM_ABS | AM_DIR;
+
+           }
+       }
+    }
+}
+
+
+
diff --git a/src/ca65/ea.h b/src/ca65/ea.h
new file mode 100644 (file)
index 0000000..8d3c88a
--- /dev/null
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  ea.h                                    */
+/*                                                                           */
+/*          Effective address parsing for the ca65 macroassembler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EA_H
+#define EA_H
+
+
+
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank);
+/* Parse an effective address, return the possible modes in AddrMode, and the
+ * expression involved (if any) in Expr.
+ */
+
+
+
+/* End of ea.h */
+
+#endif
+
+
+
diff --git a/src/ca65/error.c b/src/ca65/error.c
new file mode 100644 (file)
index 0000000..5dea2d6
--- /dev/null
@@ -0,0 +1,291 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 error.c                                  */
+/*                                                                           */
+/*               Error handling for the ca65 macroassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "scanner.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Warning level */
+unsigned WarnLevel         = 1;
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+    "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+    "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+    "%s, file `%s', line %u\n";
+
+
+/* Statistics */
+unsigned ErrorCount    = 0;
+unsigned WarningCount  = 0;
+
+
+
+/*****************************************************************************/
+/*                                Warnings                                  */
+/*****************************************************************************/
+
+
+
+void WarningMsg (const FilePos* Pos, unsigned WarnNum, va_list ap)
+/* Print warning message. */
+{
+    static const struct {
+       unsigned char   Level;
+       const char*     Msg;
+    } Warnings [WARN_COUNT-1] = {
+       {   1,  "Mask error"                                    },
+               {   2,  "Symbol `%s' is defined but never used"         },
+        {   2,  "Symbol `%s' is imported but never used"       },
+       {   1,  "Cannot track processor status byte"            },
+    };
+
+    if (Warnings [WarnNum-1].Level <= WarnLevel) {
+       fprintf (stderr, "%s(%lu): Warning #%u: ",
+                GetFileName (Pos->Name), Pos->Line, WarnNum);
+       vfprintf (stderr, Warnings [WarnNum-1].Msg, ap);
+       fprintf (stderr, "\n");
+       ++WarningCount;
+    }
+}
+
+
+
+void Warning (unsigned WarnNum, ...)
+/* Print warning message. */
+{
+    va_list ap;
+    va_start (ap, WarnNum);
+    WarningMsg (&CurPos, WarnNum, ap);
+    va_end (ap);
+}
+
+
+
+void PWarning (const FilePos* Pos, unsigned WarnNum, ...)
+/* Print warning message giving an explicit file and position. */
+{
+    va_list ap;
+    va_start (ap, WarnNum);
+    WarningMsg (Pos, WarnNum, ap);
+    va_end (ap);
+}
+
+
+
+/*****************************************************************************/
+/*                                 Errors                                   */
+/*****************************************************************************/
+
+
+
+void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap)
+/* Print an error message */
+{
+    static const char* Msgs [ERR_COUNT-1] = {
+       "Command/operation not implemented",
+       "Cannot open include file `%s': %s",
+       "Include nesting too deep",
+        "Invalid input character: %02X",
+       "Hex digit expected",
+       "Digit expected",
+       "`0' or `1' expected",
+       "Numerical overflow",
+        "Control statement expected",
+       "Too many characters",
+       "`:' expected",
+               "`(' expected",
+       "`)' expected",
+       "`]' expected",
+       "`,' expected",
+        "Boolean switch value expected (on/off/+/-)",
+       "`Y' expected",
+       "`X' expected",
+       "Integer constant expected",
+       "String constant expected",
+       "Character constant expected",
+       "Constant expression expected",
+       "Identifier expected",
+       "`.endmacro' expected",
+       "Option key expected",
+       "Command is only valid in 65816 mode",
+       "User error: %s",
+       "String constant too long",
+       "Newline in string constant",
+       "Illegal character constant",
+       "Illegal addressing mode",
+       "Illegal character to start local symbols",
+       "Illegal use of local symbol",
+       "Illegal segment name: `%s'",
+       "Illegal segment attribute",
+       "Illegal macro package name",
+       "Illegal emulation feature",
+       "Syntax error",
+       "Symbol `%s' is already defined",
+       "Undefined symbol `%s'",
+       "Symbol `%s' is marked as import",
+        "Symbol `%s' is marked as export",
+       "Exported symbol `%s' is undefined",
+       "Exported values must be constant",
+       ".IF nesting too deep",
+       "Unexpected end of line",
+       "Unexpected `%s'",
+       "Division by zero",
+       "Modulo operation with zero",
+        "Range error",
+       "Too many macro parameters",
+       "Macro parameter expected",
+       "Circular reference in symbol definition",
+               "Symbol redeclaration mismatch",
+        "Alignment value must be a power of 2",
+       "Duplicate `.ELSE'",
+               "Conditional assembly branch was never closed",
+       "Lexical level was not terminated correctly",
+       "Segment attribute mismatch",
+       "CPU not supported",
+       "Counter underflow",
+       "Undefined label",
+    };
+
+    fprintf (stderr, "%s(%lu): Error #%u: ",
+            GetFileName (Pos->Name), Pos->Line, ErrNum);
+    vfprintf (stderr, Msgs [ErrNum-1], ap);
+    fprintf (stderr, "\n");
+    ++ErrorCount;
+}
+
+
+
+void Error (unsigned ErrNum, ...)
+/* Print an error message */
+{
+    va_list ap;
+    va_start (ap, ErrNum);
+    ErrorMsg (&CurPos, ErrNum, ap);
+    va_end (ap);
+}
+
+
+
+void PError (const FilePos* Pos, unsigned ErrNum, ...)
+/* Print an error message giving an explicit file and position. */
+{
+    va_list ap;
+    va_start (ap, ErrNum);
+    ErrorMsg (Pos, ErrNum, ap);
+    va_end (ap);
+}
+
+
+
+void ErrorSkip (unsigned ErrNum, ...)
+/* Print an error message and skip the rest of the line */
+{
+    va_list ap;
+    va_start (ap, ErrNum);
+    ErrorMsg (&CurPos, ErrNum, ap);
+    va_end (ap);
+
+    SkipUntilSep ();
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void Fatal (unsigned FatNum, ...)
+/* Print a message about a fatal error and die */
+{
+    static const char* Msgs [FAT_COUNT-1] = {
+       "Maximum number of input files reached",
+       "Out of memory",
+       "Too many segments",
+       "String too long",
+       "Cannot open input file `%s': %s",
+       "Cannot stat input file `%s': %s",
+       "Cannot open output file `%s': %s",
+       "Cannot write to output file `%s': %s",
+       "Cannot open listing file: %s",
+       "Cannot write to listing file: %s",
+       "Cannot read from listing file: %s",
+       "Macro nesting too deep",
+       "Too many symbols",
+    };
+    va_list ap;
+
+    va_start (ap, FatNum);
+    fprintf (stderr, "Fatal #%u: ", FatNum);
+    vfprintf (stderr, Msgs [FatNum-1], ap);
+    fprintf (stderr, "\n");
+    va_end (ap);
+
+    /* And die... */
+    exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print a message about an internal compiler error and die. */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Internal assembler error\n");
+    vfprintf (stderr, Format, ap);
+    va_end (ap);
+    fprintf (stderr, "\n");
+
+    exit (EXIT_FAILURE);
+}
+
+
+
diff --git a/src/ca65/error.h b/src/ca65/error.h
new file mode 100644 (file)
index 0000000..7dba969
--- /dev/null
@@ -0,0 +1,210 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 error.h                                  */
+/*                                                                           */
+/*               Error handling for the ca65 macroassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Warning numbers */
+enum Warnings {
+    WARN_NONE,                         /* No warning */
+    WARN_MASK_ERROR,
+    WARN_SYM_NOT_REFERENCED,
+    WARN_IMPORT_NOT_REFERENCED,
+    WARN_CANNOT_TRACK_STATUS,
+    WARN_COUNT                         /* Warning count */
+};
+
+/* Error numbers */
+enum Errors {
+    ERR_NONE,                                  /* No error */
+    ERR_NOT_IMPLEMENTED,               /* Command/operation not implemented */
+    ERR_CANNOT_OPEN_INCLUDE,
+    ERR_INCLUDE_NESTING,
+    ERR_INVALID_CHAR,
+    ERR_HEX_DIGIT_EXPECTED,
+    ERR_DIGIT_EXPECTED,
+    ERR_01_EXPECTED,
+    ERR_NUM_OVERFLOW,
+    ERR_PSEUDO_EXPECTED,
+    ERR_TOO_MANY_CHARS,
+    ERR_COLON_EXPECTED,
+    ERR_LPAREN_EXPECTED,
+    ERR_RPAREN_EXPECTED,
+    ERR_RBRACK_EXPECTED,
+    ERR_COMMA_EXPECTED,
+    ERR_ONOFF_EXPECTED,
+    ERR_Y_EXPECTED,
+    ERR_X_EXPECTED,
+    ERR_INTCON_EXPECTED,
+    ERR_STRCON_EXPECTED,
+    ERR_CHARCON_EXPECTED,
+    ERR_CONSTEXPR_EXPECTED,
+    ERR_IDENT_EXPECTED,
+    ERR_ENDMACRO_EXPECTED,
+    ERR_OPTION_KEY_EXPECTED,
+    ERR_816_MODE_ONLY,
+    ERR_USER,
+    ERR_STRING_TOO_LONG,
+    ERR_NEWLINE_IN_STRING,
+    ERR_ILLEGAL_CHARCON,
+    ERR_ILLEGAL_ADDR_MODE,
+    ERR_ILLEGAL_LOCALSTART,
+    ERR_ILLEGAL_LOCAL_USE,
+    ERR_ILLEGAL_SEGMENT,
+    ERR_ILLEGAL_SEG_ATTR,
+    ERR_ILLEGAL_MACPACK,
+    ERR_ILLEGAL_FEATURE,
+    ERR_SYNTAX,
+    ERR_SYM_ALREADY_DEFINED,
+    ERR_SYM_UNDEFINED,
+    ERR_SYM_ALREADY_IMPORT,
+    ERR_SYM_ALREADY_EXPORT,
+    ERR_EXPORT_UNDEFINED,
+    ERR_EXPORT_MUST_BE_CONST,
+    ERR_IF_NESTING,
+    ERR_UNEXPECTED_EOL,
+    ERR_UNEXPECTED,
+    ERR_DIV_BY_ZERO,
+    ERR_MOD_BY_ZERO,
+    ERR_RANGE,
+    ERR_TOO_MANY_PARAMS,
+    ERR_MACRO_PARAM_EXPECTED,
+    ERR_CIRCULAR_REFERENCE,
+    ERR_SYM_REDECL_MISMATCH,
+    ERR_ALIGN,
+    ERR_DUPLICATE_ELSE,
+    ERR_OPEN_IF,
+    ERR_OPEN_PROC,
+    ERR_SEG_ATTR_MISMATCH,
+    ERR_CPU_NOT_SUPPORTED,
+    ERR_COUNTER_UNDERFLOW,
+    ERR_UNDEFINED_LABEL,
+    ERR_COUNT                                  /* Error count */
+};
+
+/* Fatal errors */
+enum Fatals {
+    FAT_NONE,
+    FAT_MAX_INPUT_FILES,
+    FAT_OUT_OF_MEMORY,
+    FAT_TOO_MANY_SEGMENTS,
+    FAT_STRING_TOO_LONG,
+    FAT_CANNOT_OPEN_INPUT,
+    FAT_CANNOT_STAT_INPUT,
+    FAT_CANNOT_OPEN_OUTPUT,
+    FAT_CANNOT_WRITE_OUTPUT,
+    FAT_CANNOT_OPEN_LISTING,
+    FAT_CANNOT_WRITE_LISTING,
+    FAT_CANNOT_READ_LISTING,
+    FAT_MACRO_NESTING,
+    FAT_TOO_MANY_SYMBOLS,
+    FAT_COUNT                          /* Fatal error count */
+};
+
+
+
+/* Warning levels */
+extern unsigned                WarnLevel;
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+/* Statistics */
+extern unsigned ErrorCount;
+extern unsigned WarningCount;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...);
+/* Print warning message. */
+
+void PWarning (const FilePos* Pos, unsigned WarnNum, ...);
+/* Print warning message giving an explicit file and position. */
+
+void Error (unsigned ErrNum, ...);
+/* Print an error message */
+
+void PError (const FilePos* Pos, unsigned ErrNum, ...);
+/* Print an error message giving an explicit file and position. */
+
+void ErrorSkip (unsigned ErrNum, ...);
+/* Print an error message and skip the rest of the line */
+
+void Fatal (unsigned FatNum, ...);
+/* Print a message about a fatal error and die */
+
+void Internal (const char* Format, ...);
+/* Print a message about an internal compiler error and die. */
+
+#define CHECK(c)                                                               \
+    if (!(c))                                                          \
+       Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c)                                                        \
+    if (!(c))                                                          \
+               Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s)                                                                \
+    Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
+
diff --git a/src/ca65/expr.c b/src/ca65/expr.c
new file mode 100644 (file)
index 0000000..6131e39
--- /dev/null
@@ -0,0 +1,1566 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 expr.c                                   */
+/*                                                                           */
+/*            Expression evaluation for the ca65 macroassembler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "../common/exprdefs.h"
+
+#include "error.h"
+#include "global.h"
+#include "instr.h"
+#include "mem.h"
+#include "objcode.h"
+#include "objfile.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "toknode.h"
+#include "ulabel.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Since all expressions are first packed into expression trees, and each
+ * expression tree node is allocated on the heap, we add some type of special
+ * purpose memory allocation here: Instead of freeing the nodes, we save some
+ * number of freed nodes for later and remember them in a single linked list
+ * using the Left link.
+ */
+#define        MAX_FREE_NODES  64
+static ExprNode*       FreeExprNodes = 0;
+static unsigned                FreeNodeCount = 0;
+
+
+
+/*****************************************************************************/
+/*                                 Helpers                                  */
+/*****************************************************************************/
+
+
+
+static ExprNode* NewExprNode (void)
+/* Create a new expression node */
+{
+    ExprNode* N;
+
+    /* Do we have some nodes in the list already? */
+    if (FreeExprNodes) {
+       /* Use first node from list */
+       N = FreeExprNodes;
+       FreeExprNodes = N->Left;
+    } else {
+       /* Allocate fresh memory */
+        N = Xmalloc (sizeof (ExprNode));
+    }
+    N->Op = EXPR_NULL;
+    N->Left = N->Right = 0;
+    N->Obj = 0;
+
+    return N;
+}
+
+
+
+static void FreeExprNode (ExprNode* E)
+/* Free a node */
+{
+    if (E) {
+       if (FreeNodeCount < MAX_FREE_NODES) {
+           /* Remember this node for later */
+           E->Left = FreeExprNodes;
+           FreeExprNodes = E;
+       } else {
+           /* Free the memory */
+           Xfree (E);
+       }
+    }
+}
+
+
+
+/*****************************************************************************/
+/*             Dump an expression tree on stdout for debugging              */
+/*****************************************************************************/
+
+
+
+static void InternalDumpExpr (ExprNode* Expr)
+/* Dump an expression in UPN */
+{
+    if (Expr == 0) {
+       return;
+    }
+    InternalDumpExpr (Expr->Left);
+    InternalDumpExpr (Expr->Right);
+
+    switch (Expr->Op) {
+
+       case EXPR_LITERAL:
+       case EXPR_ULABEL:
+           printf (" $%04lX", Expr->V.Val & 0xFFFF);
+           break;
+
+       case EXPR_SYMBOL:
+                   printf (" %s", GetSymName (Expr->V.Sym));
+           break;
+
+       case EXPR_SEGMENT:
+           printf (" SEG");
+           break;
+
+               case EXPR_PLUS:
+           printf (" +");
+           break;
+
+               case EXPR_MINUS:
+           printf (" -");
+           break;
+
+               case EXPR_MUL:
+           printf (" *");
+           break;
+
+               case EXPR_DIV:
+           printf (" /");
+           break;
+
+               case EXPR_MOD:
+           printf (" %%");
+           break;
+
+       case EXPR_OR:
+           printf (" OR");
+           break;
+
+       case EXPR_XOR:
+           printf (" XOR");
+           break;
+
+       case EXPR_AND:
+           printf (" AND");
+           break;
+
+       case EXPR_SHL:
+           printf (" SHL");
+           break;
+
+       case EXPR_SHR:
+           printf (" SHR");
+           break;
+
+               case EXPR_EQ:
+           printf (" =");
+           break;
+
+               case EXPR_NE:
+           printf ("<>");
+           break;
+
+               case EXPR_LT:
+           printf (" <");
+           break;
+
+               case EXPR_GT:
+           printf (" >");
+           break;
+
+               case EXPR_UNARY_MINUS:
+           printf (" NEG");
+           break;
+
+               case EXPR_NOT:
+           printf (" ~");
+           break;
+
+               case EXPR_LOBYTE:
+           printf (" LO");
+           break;
+
+               case EXPR_HIBYTE:
+           printf (" HI");
+           break;
+
+               case EXPR_SWAP:
+           printf (" SWAP");
+           break;
+
+       case EXPR_BAND:
+           printf (" BOOL_AND");
+           break;
+
+       case EXPR_BOR:
+           printf (" BOOL_OR");
+           break;
+
+       case EXPR_BXOR:
+           printf (" BOOL_XOR");
+           break;
+
+       case EXPR_BNOT:
+           printf (" BOOL_NOT");
+           break;
+
+        default:
+                   Internal ("Unknown Op type: %u", Expr->Op);
+
+    }
+}
+
+
+
+void DumpExpr (ExprNode* Expr)
+/* Dump an expression tree to stdout */
+{
+    InternalDumpExpr (Expr);
+    printf ("\n");
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static ExprNode* Expr0 (void);
+
+
+
+int IsByteRange (long Val)
+/* Return true if this is a byte value */
+{
+    return (Val & ~0xFFL) == 0;
+}
+
+
+
+int IsWordRange (long Val)
+/* Return true if this is a word value */
+{
+    return (Val & ~0xFFFF) == 0;
+}
+
+
+
+static int FuncBlank (void)
+/* Handle the .BLANK builtin function */
+{
+    /* Assume no tokens if the closing brace follows (this is not correct in
+     * all cases, since the token may be the closing brace, but this will
+     * give a syntax error anyway and may not be handled by .BLANK.
+     */
+    if (Tok == TOK_RPAREN) {
+       /* No tokens */
+       return 1;
+    } else {
+       /* Skip any tokens */
+       int Braces = 0;
+       while (Tok != TOK_SEP && Tok != TOK_EOF) {
+           if (Tok == TOK_LPAREN) {
+               ++Braces;
+           } else if (Tok == TOK_RPAREN) {
+               if (Braces == 0) {
+                   /* Done */
+                   break;
+               } else {
+                   --Braces;
+               }
+           }
+           NextTok ();
+       }
+       return 0;
+    }
+}
+
+
+
+static int FuncConst (void)
+/* Handle the .CONST builtin function */
+{
+    /* Read an expression */
+    ExprNode* Expr = Expression ();
+
+    /* Check the constness of the expression */
+    int Result = IsConstExpr (Expr);
+
+    /* Free the expression */
+    FreeExpr (Expr);
+
+    /* Done */
+    return Result;
+}
+
+
+
+static int FuncDefined (void)
+/* Handle the .DEFINED builtin function */
+{
+    int Result = 0;
+
+    if (Tok != TOK_IDENT) {
+       Error (ERR_IDENT_EXPECTED);
+       if (Tok != TOK_RPAREN) {
+           NextTok ();
+       }
+    } else {
+       Result = SymIsDef (SVal);
+       NextTok ();
+    }
+
+    /* Done */
+    return Result;
+}
+
+
+
+static int DoMatch (enum TC EqualityLevel)
+/* Handle the .MATCH and .XMATCH builtin functions */
+{
+    int Result;
+    TokNode* Root = 0;
+    TokNode* Last = 0;
+    TokNode* Node = 0;
+
+    /* A list of tokens follows. Read this list and remember it building a
+     * single linked list of tokens including attributes. The list is
+     * terminated by a comma.
+     */
+    while (Tok != TOK_COMMA) {
+
+       /* We may not end-of-line of end-of-file here */
+       if (Tok == TOK_SEP || Tok == TOK_EOF) {
+           Error (ERR_UNEXPECTED_EOL);
+           return 0;
+       }
+
+       /* Get a node with this token */
+       Node = NewTokNode ();
+
+       /* Insert the node into the list */
+       if (Last == 0) {
+                   Root = Node;
+       } else {
+           Last->Next = Node;
+       }
+       Last = Node;
+
+       /* Skip the token */
+       NextTok ();
+    }
+
+    /* Skip the comma */
+    NextTok ();
+
+    /* Read the second list which is terminated by the right parenthesis and
+     * compare each token against the one in the first list.
+     */
+    Result = 1;
+    Node = Root;
+    while (Tok != TOK_RPAREN) {
+
+       /* We may not end-of-line of end-of-file here */
+       if (Tok == TOK_SEP || Tok == TOK_EOF) {
+           Error (ERR_UNEXPECTED_EOL);
+           return 0;
+       }
+
+       /* Compare the tokens if the result is not already known */
+       if (Result != 0) {
+           if (Node == 0) {
+               /* The second list is larger than the first one */
+               Result = 0;
+           } else if (TokCmp (Node) < EqualityLevel) {
+               /* Tokens do not match */
+               Result = 0;
+           }
+       }
+
+       /* Next token in first list */
+       if (Node) {
+           Node = Node->Next;
+       }
+
+               /* Next token in current list */
+       NextTok ();
+    }
+
+    /* Check if there are remaining tokens in the first list */
+    if (Node != 0) {
+       Result = 0;
+    }
+
+    /* Free the token list */
+    while (Root) {
+       Node = Root;
+       Root = Root->Next;
+       FreeTokNode (Node);
+    }
+
+    /* Done, return the result */
+    return Result;
+}
+
+
+
+static int FuncMatch (void)
+/* Handle the .MATCH function */
+{
+    return DoMatch (tcSameToken);
+}
+
+
+
+static int FuncReferenced (void)
+/* Handle the .REFERENCED builtin function */
+{
+    int Result = 0;
+
+    if (Tok != TOK_IDENT) {
+       Error (ERR_IDENT_EXPECTED);
+       if (Tok != TOK_RPAREN) {
+           NextTok ();
+       }
+    } else {
+       Result = SymIsRef (SVal);
+       NextTok ();
+    }
+
+    /* Done */
+    return Result;
+}
+
+
+
+static int FuncXMatch (void)
+/* Handle the .XMATCH function */
+{
+    return DoMatch (tcIdentical);
+}
+
+
+
+static ExprNode* Function (int (*F) (void))
+/* Handle builtin functions */
+{
+    long Result;
+
+    /* Skip the keyword */
+    NextTok ();
+
+    /* Expression must be enclosed in braces */
+    if (Tok != TOK_LPAREN) {
+       Error (ERR_LPAREN_EXPECTED);
+       SkipUntilSep ();
+       return LiteralExpr (0);
+    }
+    NextTok ();
+
+    /* Call the function itself */
+    Result = (F () != 0);
+
+    /* Closing brace must follow */
+    ConsumeRParen ();
+
+    /* Return an expression node with the boolean code */
+    return LiteralExpr (Result);
+}
+
+
+
+static ExprNode* Factor (void)
+{
+    ExprNode* N;
+    SymEntry* S;
+
+    switch (Tok) {
+
+       case TOK_INTCON:
+       case TOK_CHARCON:
+           N = LiteralExpr (IVal);
+                   NextTok ();
+           break;
+
+        case TOK_NAMESPACE:
+           NextTok ();
+           if (Tok != TOK_IDENT) {
+               Error (ERR_IDENT_EXPECTED);
+               N = LiteralExpr (0);    /* Dummy */
+           } else {
+               S = SymRefGlobal (SVal);
+               if (SymIsConst (S)) {
+                   /* Use the literal value instead */
+                   N = LiteralExpr (GetSymVal (S));
+               } else {
+                   /* Create symbol node */
+                   N = NewExprNode ();
+                   N->Op    = EXPR_SYMBOL;
+                   N->V.Sym = S;
+               }
+               NextTok ();
+           }
+           break;
+
+        case TOK_IDENT:
+           S = SymRef (SVal);
+           if (SymIsConst (S)) {
+               /* Use the literal value instead */
+               N = LiteralExpr (GetSymVal (S));
+           } else {
+               /* Create symbol node */
+               N = NewExprNode ();
+               N->Op    = EXPR_SYMBOL;
+               N->V.Sym = S;
+           }
+           NextTok ();
+           break;
+
+       case TOK_ULABEL:
+           N = ULabRef (IVal);
+           NextTok ();
+           break;
+
+       case TOK_MINUS:
+           NextTok ();
+           N = NewExprNode ();
+                   N->Left = Factor ();
+                   N->Op   = EXPR_UNARY_MINUS;
+           break;
+
+       case TOK_NOT:
+           NextTok ();
+           N = NewExprNode ();
+           N->Left = Factor ();
+           N->Op   = EXPR_NOT;
+           break;
+
+       case TOK_STAR:
+       case TOK_PC:
+           NextTok ();
+                   N = CurrentPC ();
+           break;
+
+       case TOK_LT:
+           NextTok ();
+           N = NewExprNode ();
+           N->Left = Factor ();
+           N->Op   = EXPR_LOBYTE;
+           break;
+
+       case TOK_GT:
+           NextTok ();
+           N = NewExprNode ();
+           N->Left = Factor ();
+           N->Op   = EXPR_HIBYTE;
+           break;
+
+       case TOK_LPAREN:
+           NextTok ();
+           N = Expr0 ();
+                   ConsumeRParen ();
+           break;
+
+        case TOK_BLANK:
+           N = Function (FuncBlank);
+           break;
+
+       case TOK_CONST:
+           N = Function (FuncConst);
+           break;
+
+       case TOK_CPU:
+           N = LiteralExpr (GetCPU());
+           NextTok ();
+           break;
+
+        case TOK_DEFINED:
+           N = Function (FuncDefined);
+           break;
+
+       case TOK_MATCH:
+           N = Function (FuncMatch);
+           break;
+
+        case TOK_REFERENCED:
+           N = Function (FuncReferenced);
+           break;
+
+       case TOK_XMATCH:
+           N = Function (FuncXMatch);
+           break;
+
+       default:
+           N = LiteralExpr (0);        /* Dummy */
+           Error (ERR_SYNTAX);
+           NextTok ();
+           break;
+    }
+    return N;
+}
+
+
+
+static ExprNode* Term (void)
+{
+    ExprNode* Root;
+
+    /* Read left hand side */
+    Root = Factor ();
+
+    /* Handle multiplicative operations */
+    while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
+          Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
+          Tok == TOK_SHR) {
+
+       /* Create a new node and insert the left expression */
+       ExprNode* Left = Root;
+       Root = NewExprNode ();
+       Root->Left = Left;
+
+       /* Determine the operator token */
+       switch (Tok) {
+                   case TOK_MUL:       Root->Op = EXPR_MUL;    break;
+           case TOK_DIV:       Root->Op = EXPR_DIV;    break;
+           case TOK_MOD:       Root->Op = EXPR_MOD;    break;
+                   case TOK_AND:       Root->Op = EXPR_AND;    break;
+                   case TOK_XOR:       Root->Op = EXPR_XOR;    break;
+                   case TOK_SHL:       Root->Op = EXPR_SHL;    break;
+                   case TOK_SHR:       Root->Op = EXPR_SHR;    break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the right hand side */
+       Root->Right = Factor ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* SimpleExpr (void)
+{
+    ExprNode* Root;
+
+    /* Read left hand side */
+    Root = Term ();
+
+    /* Handle additive operations */
+    while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
+
+       /* Create a new node and insert the left expression */
+       ExprNode* Left = Root;
+       Root = NewExprNode ();
+       Root->Left = Left;
+
+       /* Determine the operator token */
+       switch (Tok) {
+                   case TOK_PLUS:      Root->Op = EXPR_PLUS;   break;
+           case TOK_MINUS:     Root->Op = EXPR_MINUS;  break;
+           case TOK_OR:        Root->Op = EXPR_OR;     break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the right hand side */
+       Root->Right = Term ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* BoolExpr (void)
+/* Evaluate a boolean expression */
+{
+    /* Read left hand side */
+    ExprNode* Root = SimpleExpr ();
+
+    /* Handle booleans */
+    while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
+          Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
+
+       /* Create a new node and insert the left expression */
+       ExprNode* Left = Root;
+       Root = NewExprNode ();
+       Root->Left = Left;
+
+       /* Determine the operator token */
+       switch (Tok) {
+           case TOK_EQ:        Root->Op = EXPR_EQ;     break;
+           case TOK_NE:        Root->Op = EXPR_NE;     break;
+           case TOK_LT:        Root->Op = EXPR_LT;     break;
+           case TOK_GT:        Root->Op = EXPR_GT;     break;
+           case TOK_LE:        Root->Op = EXPR_LE;     break;
+           case TOK_GE:        Root->Op = EXPR_GE;     break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the right hand side */
+       Root->Right = SimpleExpr ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* Expr2 (void)
+/* Boolean operators: AND and XOR */
+{
+    /* Read left hand side */
+    ExprNode* Root = BoolExpr ();
+
+    /* Handle booleans */
+    while (Tok == TOK_BAND || Tok == TOK_BXOR) {
+
+       /* Create a new node and insert the left expression */
+       ExprNode* Left = Root;
+       Root = NewExprNode ();
+       Root->Left = Left;
+
+       /* Determine the operator token */
+       switch (Tok) {
+           case TOK_BAND:      Root->Op = EXPR_BAND;   break;
+           case TOK_BXOR:      Root->Op = EXPR_BXOR;   break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the right hand side */
+       Root->Right = BoolExpr ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* Expr1 (void)
+/* Boolean operators: OR */
+{
+    /* Read left hand side */
+    ExprNode* Root = Expr2 ();
+
+    /* Handle booleans */
+    while (Tok == TOK_BOR) {
+
+       /* Create a new node and insert the left expression */
+       ExprNode* Left = Root;
+       Root = NewExprNode ();
+       Root->Left = Left;
+
+       /* Determine the operator token */
+       switch (Tok) {
+           case TOK_BOR:       Root->Op = EXPR_BOR;    break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the right hand side */
+       Root->Right = Expr2 ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* Expr0 (void)
+/* Boolean operators: NOT */
+{
+    ExprNode* Root;
+
+    /* Handle booleans */
+    if (Tok == TOK_BNOT) {
+
+               /* Create a new node */
+       Root = NewExprNode ();
+
+       /* Determine the operator token */
+       switch (Tok) {
+           case TOK_BNOT:      Root->Op = EXPR_BNOT;   break;
+           default:            Internal ("Invalid token");
+       }
+       NextTok ();
+
+       /* Parse the left hand side, allow more BNOTs */
+       Root->Left = Expr0 ();
+
+    } else {
+
+       /* Read left hand side */
+       Root = Expr1 ();
+
+    }
+
+    /* Return the expression tree we've created */
+    return Root;
+}
+
+
+
+static ExprNode* SimplifyExpr (ExprNode* Root)
+/* Try to simplify the given expression tree */
+{
+    if (Root) {
+       SimplifyExpr (Root->Left);
+       SimplifyExpr (Root->Right);
+       if (IsConstExpr (Root)) {
+           /* The complete expression is constant */
+           Root->V.Val = GetExprVal (Root);
+           Root->Op = EXPR_LITERAL;
+           FreeExpr (Root->Left);
+           FreeExpr (Root->Right);
+           Root->Left = Root->Right = 0;
+               }
+    }
+    return Root;
+}
+
+
+
+ExprNode* Expression (void)
+/* Evaluate an expression, build the expression tree on the heap and return
+ * a pointer to the root of the tree.
+ */
+{
+    return SimplifyExpr (Expr0 ());
+}
+
+
+
+long ConstExpression (void)
+/* Parse an expression. Check if the expression is const, and print an error
+ * message if not. Return the value of the expression, or a dummy, if it is
+ * not constant.
+ */
+{
+    /* Read the expression, and call finalize (exception here, since we
+     * expect a const).
+     */
+    ExprNode* Expr = FinalizeExpr (Expression ());
+
+    /* Return the value */
+    if (IsConstExpr (Expr)) {
+       return GetExprVal (Expr);
+    } else {
+       Error (ERR_CONSTEXPR_EXPECTED);
+       return 0;
+    }
+}
+
+
+
+ExprNode* LiteralExpr (long Val)
+/* Return an expression tree that encodes the given literal value */
+{
+    ExprNode* Expr = NewExprNode ();
+    Expr->Op = EXPR_LITERAL;
+    Expr->V.Val = Val;
+    return Expr;
+}
+
+
+
+ExprNode* CurrentPC (void)
+/* Return the current program counter as expression */
+{
+    ExprNode* Left;
+    ExprNode* Root;
+
+    if (RelocMode) {
+       /* Create SegmentBase + Offset */
+       Left = NewExprNode ();
+       Left->Op = EXPR_SEGMENT;
+       Left->V.SegNum = GetSegNum ();
+
+       Root = NewExprNode ();
+       Root->Left  = Left;
+       Root->Right = LiteralExpr (GetPC ());
+       Root->Op = EXPR_PLUS;
+    } else {
+       /* Absolute mode, just return PC value */
+       Root = LiteralExpr (GetPC ());
+    }
+
+    return Root;
+}
+
+
+
+ExprNode* SwapExpr (ExprNode* Expr)
+/* Return an extended expression with lo and hi bytes swapped */
+{
+    ExprNode* N = NewExprNode ();
+    N->Op = EXPR_SWAP;
+    N->Left = Expr;
+    return N;
+}
+
+
+
+ExprNode* BranchExpr (unsigned Offs)
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
+ */
+{
+    ExprNode* N;
+    ExprNode* Root;
+    ExprNode* Left;
+
+    /* Create *+Offs */
+    if (RelocMode) {
+       Left = NewExprNode ();
+       Left->Op = EXPR_SEGMENT;
+       Left->V.SegNum = GetSegNum ();
+
+       N = NewExprNode ();
+       N->Left  = Left;
+       N->Right = LiteralExpr (GetPC () + Offs);
+       N->Op = EXPR_PLUS;
+    } else {
+       N = LiteralExpr (GetPC () + Offs);
+    }
+
+    /* Create the root node */
+    Root = NewExprNode ();
+    Root->Left = Expression ();
+    Root->Right = N;
+    Root->Op = EXPR_MINUS;
+
+    /* Return the result */
+    return SimplifyExpr (Root);
+}
+
+
+
+ExprNode* ULabelExpr (unsigned Num)
+/* Return an expression for an unnamed label with the given index */
+{
+    /* Get an expression node */
+    ExprNode* Node = NewExprNode ();
+
+    /* Set the values */
+    Node->Op   = EXPR_ULABEL;
+    Node->V.Val        = Num;
+
+    /* Return the new node */
+    return Node;
+}
+
+
+
+void FreeExpr (ExprNode* Root)
+/* Free the expression, Root is pointing to. */
+{
+    if (Root) {
+       FreeExpr (Root->Left);
+       FreeExpr (Root->Right);
+       FreeExprNode (Root);
+    }
+}
+
+
+
+ExprNode* ForceWordExpr (ExprNode* Expr)
+/* Force the given expression into a word and return the result. */
+{
+    /* And the expression by $FFFF to force it into word size */
+    ExprNode* Root = NewExprNode ();
+    Root->Left  = Expr;
+    Root->Op    = EXPR_AND;
+    Root->Right        = LiteralExpr (0xFFFF);
+
+    /* Return the result */
+    return Root;
+}
+
+
+
+int IsConstExpr (ExprNode* Root)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+{
+    int Const;
+    SymEntry* Sym;
+
+    if (EXPR_IS_LEAF (Root->Op)) {
+       switch (Root->Op) {
+
+           case EXPR_LITERAL:
+               return 1;
+
+           case EXPR_SYMBOL:
+               Sym = Root->V.Sym;
+               if (SymHasUserMark (Sym)) {
+                   if (Verbose) {
+                       DumpExpr (Root);
+                   }
+                   PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
+                   Const = 0;
+               } else {
+                   SymMarkUser (Sym);
+                   Const = SymIsConst (Sym);
+                   SymUnmarkUser (Sym);
+               }
+               return Const;
+
+           default:
+               return 0;
+
+       }
+    } else if (EXPR_IS_UNARY (Root->Op)) {
+
+       return IsConstExpr (Root->Left);
+
+    } else {
+
+       /* We must handle shortcut boolean expressions here */
+       switch (Root->Op) {
+
+           case EXPR_BAND:
+               if (IsConstExpr (Root->Left)) {
+                   /* lhs is const, if it is zero, don't eval right */
+                   if (GetExprVal (Root->Left) == 0) {
+                       return 1;
+                   } else {
+                       return IsConstExpr (Root->Right);
+                   }
+               } else {
+                   /* lhs not const --> tree not const */
+                   return 0;
+               }
+               break;
+
+           case EXPR_BOR:
+               if (IsConstExpr (Root->Left)) {
+                   /* lhs is const, if it is not zero, don't eval right */
+                   if (GetExprVal (Root->Left) != 0) {
+                       return 1;
+                   } else {
+                       return IsConstExpr (Root->Right);
+                   }
+               } else {
+                   /* lhs not const --> tree not const */
+                   return 0;
+               }
+               break;
+
+           default:
+               /* All others are handled normal */
+               return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
+       }
+    }
+}
+
+
+
+static void CheckByteExpr (const ExprNode* N, int* IsByte)
+/* Internal routine that is recursively called to check if there is a zeropage
+ * symbol in the expression tree.
+ */
+{
+    if (N) {
+       switch (N->Op & EXPR_TYPEMASK) {
+
+           case EXPR_LEAFNODE:
+               switch (N->Op) {
+
+                   case EXPR_SYMBOL:
+                       if (SymIsZP (N->V.Sym)) {
+                           *IsByte = 1;
+                       }
+                       break;
+
+                   case EXPR_SEGMENT:
+                       if (GetSegType (N->V.SegNum) == SEGTYPE_ZP) {
+                           *IsByte = 1;
+                       }
+                       break;
+
+               }
+               break;
+
+           case EXPR_UNARYNODE:
+               CheckByteExpr (N->Left, IsByte);
+               break;
+
+           case EXPR_BINARYNODE:
+               CheckByteExpr (N->Left, IsByte);
+               CheckByteExpr (N->Right, IsByte);
+               break;
+
+           default:
+               Internal ("Unknown expression op: %02X", N->Op);
+       }
+    }
+}
+
+
+
+int IsByteExpr (ExprNode* Root)
+/* Return true if this is a byte expression */
+{
+    int IsByte;
+
+    if (IsConstExpr (Root)) {
+       if (Root->Op != EXPR_LITERAL) {
+           SimplifyExpr (Root);
+       }
+               return IsByteRange (GetExprVal (Root));
+    } else if (Root->Op == EXPR_LOBYTE || Root->Op == EXPR_HIBYTE) {
+       /* Symbol forced to have byte range */
+               IsByte = 1;
+    } else {
+       /* We have undefined symbols in the expression. Assume that the
+        * expression is a byte expression if there is at least one symbol
+        * declared as zeropage in it. Being wrong here is not a very big
+        * problem since the linker knows about all symbols and detects
+        * error like mixing absolute and zeropage labels.
+        */
+       IsByte = 0;
+       CheckByteExpr (Root, &IsByte);
+    }
+    return IsByte;
+}
+
+
+
+long GetExprVal (ExprNode* Expr)
+/* Get the value of a constant expression */
+{
+    long Right, Left;
+
+    switch (Expr->Op) {
+
+               case EXPR_LITERAL:
+           return Expr->V.Val;
+
+               case EXPR_SYMBOL:
+           return GetSymVal (Expr->V.Sym);
+
+               case EXPR_PLUS:
+           return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
+
+               case EXPR_MINUS:
+           return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
+
+               case EXPR_MUL:
+           return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
+
+               case EXPR_DIV:
+           Left  = GetExprVal (Expr->Left);
+           Right = GetExprVal (Expr->Right);
+           if (Right == 0) {
+               Error (ERR_DIV_BY_ZERO);
+               return 0;
+           }
+           return Left / Right;
+
+               case EXPR_MOD:
+           Left  = GetExprVal (Expr->Left);
+           Right = GetExprVal (Expr->Right);
+           if (Right == 0) {
+               Error (ERR_MOD_BY_ZERO);
+               return 0;
+           }
+           return Left % Right;
+
+               case EXPR_OR:
+                   return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
+
+               case EXPR_XOR:
+                   return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
+
+               case EXPR_AND:
+                   return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
+
+               case EXPR_SHL:
+                   return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
+
+               case EXPR_SHR:
+                   return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
+
+               case EXPR_EQ:
+                   return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
+
+               case EXPR_NE:
+                   return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
+
+               case EXPR_LT:
+           return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
+
+               case EXPR_GT:
+           return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
+
+               case EXPR_LE:
+           return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
+
+               case EXPR_GE:
+           return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
+
+               case EXPR_UNARY_MINUS:
+           return -GetExprVal (Expr->Left);
+
+               case EXPR_NOT:
+           return ~GetExprVal (Expr->Left);
+
+               case EXPR_LOBYTE:
+           return GetExprVal (Expr->Left) & 0xFF;
+
+               case EXPR_HIBYTE:
+           return (GetExprVal (Expr->Left) >> 8) & 0xFF;
+
+        case EXPR_SWAP:
+           Left = GetExprVal (Expr->Left);
+           return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
+
+       case EXPR_BAND:
+           return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
+
+       case EXPR_BOR:
+           return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
+
+       case EXPR_BXOR:
+           return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+
+       case EXPR_BNOT:
+                   return !GetExprVal (Expr->Left);
+
+       case EXPR_ULABEL:
+           Internal ("GetExprVal called for EXPR_ULABEL");
+           /* NOTREACHED */
+           return 0;
+
+        default:
+           Internal ("Unknown Op type: %u", Expr->Op);
+           /* NOTREACHED */
+           return 0;
+    }
+}
+
+
+
+static ExprNode* RemoveSyms (ExprNode* Expr, int MustClone)
+/* Remove resolved symbols from the tree by cloning symbol expressions */
+{
+    /* Accept NULL pointers */
+    if (Expr == 0) {
+       return 0;
+    }
+
+    /* Special node handling */
+    switch (Expr->Op) {
+
+       case EXPR_SYMBOL:
+           if (SymHasExpr (Expr->V.Sym)) {
+               /* The symbol has an expression tree */
+               SymEntry* Sym = Expr->V.Sym;
+               if (SymHasUserMark (Sym)) {
+                   /* Circular definition */
+                   if (Verbose) {
+                       DumpExpr (Expr);
+                   }
+                   PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
+                   return LiteralExpr (0);             /* Return a dummy value */
+               }
+               SymMarkUser (Sym);
+               Expr = RemoveSyms (GetSymExpr (Sym), 1);
+               SymUnmarkUser (Sym);
+               return Expr;
+           } else if (SymIsConst (Expr->V.Sym)) {
+               /* The symbol is a constant */
+               return LiteralExpr (GetSymVal (Expr->V.Sym));
+           }
+           break;
+
+       case EXPR_ULABEL:
+           if (ULabCanResolve ()) {
+               ExprNode* NewExpr = ULabResolve (Expr->V.Val);
+               FreeExpr (Expr);
+               Expr = NewExpr;
+           }
+           break;
+
+    }
+
+    /* Clone the current node if needed */
+    if (MustClone) {
+
+       /* Create a new node */
+               ExprNode* Clone = NewExprNode ();
+
+       /* Clone the operation */
+       Clone->Op = Expr->Op;
+
+       /* Clone the attribute if needed */
+       switch (Expr->Op) {
+
+           case EXPR_LITERAL:
+           case EXPR_ULABEL:
+               Clone->V.Val = Expr->V.Val;
+               break;
+
+           case EXPR_SYMBOL:
+               Clone->V.Sym = Expr->V.Sym;
+               break;
+
+           case EXPR_SEGMENT:
+               Clone->V.SegNum = Expr->V.SegNum;
+               break;
+
+       }
+
+       /* Clone the tree nodes */
+               Clone->Left = RemoveSyms (Expr->Left, MustClone);
+       Clone->Right = RemoveSyms (Expr->Right, MustClone);
+
+       /* Done */
+       return Clone;
+
+    } else {
+
+       /* Nothing to clone */
+       Expr->Left = RemoveSyms (Expr->Left, MustClone);
+       Expr->Right = RemoveSyms (Expr->Right, MustClone);
+
+       /* Done */
+       return Expr;
+
+    }
+}
+
+
+
+static ExprNode* ConstExtract (ExprNode* Expr, long* Val, int Sign)
+/* Extract and evaluate all constant factors in an subtree that has only
+ * additions and subtractions.
+ */
+{
+    if (Expr->Op == EXPR_LITERAL) {
+       if (Sign < 0) {
+           *Val -= Expr->V.Val;
+       } else {
+           *Val += Expr->V.Val;
+       }
+               FreeExprNode (Expr);
+       return 0;
+    }
+
+    if (Expr->Op == EXPR_PLUS || Expr->Op == EXPR_MINUS) {
+       ExprNode* Left;
+       ExprNode* Right;
+       Left = ConstExtract (Expr->Left, Val, Sign);
+       if (Expr->Op == EXPR_MINUS) {
+           Sign = -Sign;
+       }
+       Right = ConstExtract (Expr->Right, Val, Sign);
+       if (Left == 0 && Right == 0) {
+           FreeExprNode (Expr);
+           return 0;
+       } else if (Left == 0) {
+           FreeExprNode (Expr);
+           return Right;
+       } else if (Right == 0) {
+           FreeExprNode (Expr);
+           return Left;
+       } else {
+           /* Check for SEG - SEG which is now possible */
+           if (Left->Op == EXPR_SEGMENT && Right->Op == EXPR_SEGMENT &&
+               Left->V.SegNum == Right->V.SegNum) {
+               /* SEG - SEG, remove it completely */
+               FreeExprNode (Left);
+               FreeExprNode (Right);
+               FreeExprNode (Expr);
+               return 0;
+           } else {
+               Expr->Left  = Left;
+               Expr->Right = Right;
+               return Expr;
+           }
+       }
+    }
+
+    /* Some other sort of node, finalize the terms */
+    if (Expr->Left) {
+       Expr->Left = FinalizeExpr (Expr->Left);
+    }
+    if (Expr->Right) {
+       Expr->Right = FinalizeExpr (Expr->Right);
+    }
+
+    return Expr;
+}
+
+
+
+ExprNode* FinalizeExpr (ExprNode* Expr)
+/* Resolve any symbols by cloning the symbol expression tree instead of the
+ * symbol reference, then try to simplify the expression as much as possible.
+ * This function must only be called if all symbols are resolved (no undefined
+ * symbol errors).
+ */
+{
+    long Val = 0;
+    ExprNode* N;
+
+    Expr = RemoveSyms (Expr, 0);
+    Expr = ConstExtract (Expr, &Val, 1);
+    if (Expr == 0) {
+       /* Reduced to a literal value */
+       Expr = LiteralExpr (Val);
+    } else if (Val) {
+       /* Extracted a value */
+       N = NewExprNode ();
+       N->Op = EXPR_PLUS;
+       N->Left = Expr;
+       N->Right = LiteralExpr (Val);
+       Expr = N;
+    }
+    return Expr;
+}
+
+
+
+ExprNode* CloneExpr (ExprNode* Expr)
+/* Clone the given expression tree. The function will simply clone symbol
+ * nodes, it will not resolve them.
+ */
+{
+    ExprNode* Clone;
+
+    /* Accept NULL pointers */
+    if (Expr == 0) {
+        return 0;
+    }
+
+    /* Get a new node */
+    Clone = NewExprNode ();
+
+    /* Clone the operation */
+    Clone->Op = Expr->Op;
+
+    /* Clone the attribute if needed */
+    switch (Expr->Op) {
+
+       case EXPR_LITERAL:
+       case EXPR_ULABEL:
+           Clone->V.Val = Expr->V.Val;
+           break;
+
+       case EXPR_SYMBOL:
+           Clone->V.Sym = Expr->V.Sym;
+           break;
+
+       case EXPR_SEGMENT:
+           Clone->V.SegNum = Expr->V.SegNum;
+           break;
+
+    }
+
+    /* Clone the tree nodes */
+    Clone->Left = CloneExpr (Expr->Left);
+    Clone->Right = CloneExpr (Expr->Right);
+
+    /* Done */
+    return Clone;
+}
+
+
+
+void WriteExpr (ExprNode* Expr)
+/* Write the given expression to the object file */
+{
+    /* Null expressions are encoded by a type byte of zero */
+    if (Expr == 0) {
+       ObjWrite8 (0);
+       return;
+    }
+
+    /* Write the expression code */
+    ObjWrite8 (Expr->Op);
+
+    /* If the is a leafnode, write the expression attribute, otherwise
+     * write the expression operands.
+     */
+    switch (Expr->Op) {
+
+        case EXPR_LITERAL:
+           ObjWrite32 (Expr->V.Val);
+           break;
+
+        case EXPR_SYMBOL:
+           /* Maybe we should use a code here? */
+           CHECK (SymIsImport (Expr->V.Sym));  /* Safety */
+           ObjWrite16 (GetSymIndex (Expr->V.Sym));
+           break;
+
+        case EXPR_SEGMENT:
+           ObjWrite8 (Expr->V.SegNum);
+           break;
+
+       case EXPR_ULABEL:
+           Internal ("WriteExpr: Cannot write EXPR_ULABEL nodes");
+           break;
+
+        default:
+           /* Not a leaf node */
+           WriteExpr (Expr->Left);
+           WriteExpr (Expr->Right);
+           break;
+
+    }
+}
+
+
+
diff --git a/src/ca65/expr.h b/src/ca65/expr.h
new file mode 100644 (file)
index 0000000..e80d313
--- /dev/null
@@ -0,0 +1,127 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 expr.h                                   */
+/*                                                                           */
+/*            Expression evaluation for the ca65 macroassembler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "../common/exprdefs.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ExprNode* Expression (void);
+/* Evaluate an expression, build the expression tree on the heap and return
+ * a pointer to the root of the tree.
+ */
+
+long ConstExpression (void);
+/* Parse an expression. Check if the expression is const, and print an error
+ * message if not. Return the value of the expression, or a dummy, if it is
+ * not constant.
+ */
+
+void FreeExpr (ExprNode* Root);
+/* Free the expression tree, Root is pointing to. */
+
+ExprNode* LiteralExpr (long Val);
+/* Return an expression tree that encodes the given literal value */
+
+ExprNode* CurrentPC (void);
+/* Return the current program counter as expression */
+
+ExprNode* SwapExpr (ExprNode* Expr);
+/* Return an extended expression with lo and hi bytes swapped */
+
+ExprNode* BranchExpr (unsigned Offs);
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
+ */
+
+ExprNode* ULabelExpr (unsigned Num);
+/* Return an expression for an unnamed label with the given index */
+
+ExprNode* ForceWordExpr (ExprNode* Expr);
+/* Force the given expression into a word and return the result. */
+
+int IsConstExpr (ExprNode* Root);
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+
+int IsByteExpr (ExprNode* Root);
+/* Return true if this is a byte expression */
+
+long GetExprVal (ExprNode* Expr);
+/* Get the value of a constant expression */
+
+int IsByteRange (long Val);
+/* Return true if this is a byte value */
+
+int IsWordRange (long Val);
+/* Return true if this is a word value */
+
+void DumpExpr (ExprNode* Expr);
+/* Dump an expression tree to stdout */
+
+ExprNode* FinalizeExpr (ExprNode* Expr);
+/* Resolve any symbols by cloning the symbol expression tree instead of the
+ * symbol reference, then try to simplify the expression as much as possible.
+ * This function must only be called if all symbols are resolved (no undefined
+ * symbol errors).
+ */
+
+ExprNode* CloneExpr (ExprNode* Expr);
+/* Clone the given expression tree. The function will simply clone symbol
+ * nodes, it will not resolve them.
+ */
+
+void WriteExpr (ExprNode* Expr);
+/* Write the given expression to the object file */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
diff --git a/src/ca65/fname.c b/src/ca65/fname.c
new file mode 100644 (file)
index 0000000..e764d52
--- /dev/null
@@ -0,0 +1,74 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 fname.c                                  */
+/*                                                                           */
+/*                      File name handling utilities                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "fname.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+char* MakeFilename (const char* Origin, const char* Ext)
+/* Make a new file name from Origin and Ext. If Origin has an extension, it
+ * is removed and Ext is appended. If Origin has no extension, Ext is simply
+ * appended. The result is placed in a malloc'ed buffer and returned.
+ * The function may be used to create "foo.o" from "foo.s".
+ */
+{
+    /* Construct the name */
+    char* Result;
+    const char* P = strrchr (Origin, '.');
+    if (P == 0) {
+       /* No dot, add the extension */
+       Result = Xmalloc (strlen (Origin) + strlen (Ext) + 1);
+       strcpy (Result, Origin);
+       strcat (Result, Ext);
+    } else {
+       Result = Xmalloc (P - Origin + strlen (Ext) + 1);
+       memcpy (Result, Origin, P - Origin);
+       strcpy (Result + (P - Origin), Ext);
+    }
+    return Result;
+}
+
+
+
+
diff --git a/src/ca65/fname.h b/src/ca65/fname.h
new file mode 100644 (file)
index 0000000..671bf80
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 fname.h                                  */
+/*                                                                           */
+/*                      File name handling utilities                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FNAME_H
+#define FNAME_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+char* MakeFilename (const char* Origin, const char* Ext);
+/* Make a new file name from Origin and Ext. If Origin has an extension, it
+ * is removed and Ext is appended. If Origin has no extension, Ext is simply
+ * appended. The result is placed in a malloc'ed buffer and returned.
+ * The function may be used to create "foo.o" from "foo.s".
+ */
+
+
+
+/* End of fname.h */
+
+#endif
+
+
+
diff --git a/src/ca65/fragment.c b/src/ca65/fragment.c
new file mode 100644 (file)
index 0000000..2d269be
--- /dev/null
@@ -0,0 +1,51 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               fragment.c                                 */
+/*                                                                           */
+/*               Data fragments for the ca65 crossassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "fragment.h"
+
+
+
+/*****************************************************************************/
+/*                             struct Fragment                              */
+/*****************************************************************************/
+
+
+
+/* List of all fragments */
+Fragment* FragList = 0;
+Fragment* FragLast = 0;
+
+
+
diff --git a/src/ca65/fragment.h b/src/ca65/fragment.h
new file mode 100644 (file)
index 0000000..e2ef065
--- /dev/null
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               fragment.h                                 */
+/*                                                                           */
+/*               Data fragments for the ca65 crossassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FRAGMENT_H
+#define FRAGMENT_H
+
+
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/*                             struct Fragment                              */
+/*****************************************************************************/
+
+
+
+typedef struct Fragment_ Fragment;
+struct Fragment_ {
+    Fragment*          List;           /* List of all fragments */
+    Fragment*                  Next;           /* Fragment list in one segment */
+    Fragment*          LineList;       /* List of fragments for one src line */
+    FilePos                    Pos;            /* File position for this fragment */
+    unsigned short     Len;            /* Length for this fragment */
+    unsigned char      Type;           /* Fragment type */
+    union {
+               unsigned char   Data [4];       /* Literal values */
+               ExprNode*       Expr;           /* Expression */
+    } V;
+};
+
+
+
+/* List of all fragments */
+extern Fragment* FragList;
+extern Fragment* FragLast;
+
+
+
+/* End of fragment.h */
+#endif
+
+
+
diff --git a/src/ca65/global.c b/src/ca65/global.c
new file mode 100644 (file)
index 0000000..24fb34f
--- /dev/null
@@ -0,0 +1,76 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*              Global variables for the ca65 macroassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+const char* ProgName                 = "ca65"; /* Program name */
+
+/* File names */
+const char* InFile                   = 0;      /* Name of input file */
+const char* OutFile                  = 0;      /* Name of output file */
+const char* ListFile                 = 0;      /* Name of listing file */
+
+/* Default extensions */
+const char ObjExt[]                  = ".o";   /* Default object extension */
+const char ListExt[]                 = ".lst"; /* Default listing extension */
+
+char LocalStart                      = '@';    /* This char starts local symbols */
+
+unsigned char IgnoreCase      = 0;     /* Ignore case on identifiers? */
+unsigned char AutoImport      = 0;     /* Mark unresolveds as import */
+unsigned char Verbose         = 0;      /* Verbose operation flag */
+unsigned char SmartMode              = 0;      /* Smart mode */
+unsigned char DbgSyms        = 0;      /* Add debug symbols */
+unsigned char Listing                = 0;      /* Create listing file */
+unsigned char LineCont       = 0;      /* Allow line continuation */
+
+/* Emulation features */
+unsigned char DollarIsPC      = 0;      /* Allow the $ symbol as current PC */
+unsigned char NoColonLabels   = 0;             /* Allow labels without a colon */
+unsigned char LooseStringTerm = 0;     /* Allow ' as string terminator */
+unsigned char AtInIdents      = 0;     /* Allow '@' in identifiers */
+unsigned char DollarInIdents  = 0;     /* Allow '$' in identifiers */
+                                                                         
+
+
+
diff --git a/src/ca65/global.h b/src/ca65/global.h
new file mode 100644 (file)
index 0000000..4bd7f9a
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*              Global variables for the ca65 macroassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+extern const char*     ProgName;       /* Program name */
+
+/* File names */
+extern const char*     InFile;         /* Name of input file */
+extern const char*     OutFile;        /* Name of output file */
+extern const char*     ListFile;       /* Name of listing file */
+
+/* Default extensions */
+extern const char              ObjExt[];       /* Default object extension */
+extern const char      ListExt[];      /* Default listing extension */
+
+extern char            LocalStart;     /* This char starts local symbols */
+
+extern unsigned char   IgnoreCase;     /* Ignore case on identifiers? */
+extern unsigned char   AutoImport;     /* Mark unresolveds as import */
+extern unsigned char   Verbose;        /* Verbose operation flag */
+extern unsigned char   SmartMode;      /* Smart mode */
+extern unsigned char           DbgSyms;        /* Add debug symbols */
+extern unsigned char   Listing;        /* Create listing file */
+extern unsigned char   LineCont;       /* Allow line continuation */
+
+/* Emulation features */
+extern unsigned char           DollarIsPC;     /* Allow the $ symbol as current PC */
+extern unsigned char   NoColonLabels;  /* Allow labels without a colon */
+extern unsigned char   LooseStringTerm;/* Allow ' as string terminator */
+extern unsigned char    AtInIdents;    /* Allow '@' in identifiers */
+extern unsigned char   DollarInIdents; /* Allow '$' in identifiers */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
diff --git a/src/ca65/instr.c b/src/ca65/instr.c
new file mode 100644 (file)
index 0000000..50c7492
--- /dev/null
@@ -0,0 +1,748 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 instr.c                                  */
+/*                                                                           */
+/*            Instruction encoding for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "../common/bitops.h"
+
+#include "ea.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "objcode.h"
+#include "scanner.h"
+#include "instr.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Forwards for handler functions */
+static void PutPCRel8 (const InsDesc* Ins);
+static void PutPCRel16 (const InsDesc* Ins);
+static void PutBlockMove (const InsDesc* Ins);
+static void PutREP (const InsDesc* Ins);
+static void PutSEP (const InsDesc* Ins);
+static void PutAll (const InsDesc* Ins);
+
+
+
+/* Instruction table for the 6502 */
+#define INS_COUNT_6502                 56
+static const struct {
+    unsigned Count;
+    InsDesc  Ins[INS_COUNT_6502];
+} InsTab6502 = {
+    INS_COUNT_6502,
+    {
+       { "ADC", 0x080A26C, 0x60, 0, PutAll },
+       { "AND", 0x080A26C, 0x20, 0, PutAll },
+       { "ASL", 0x000006e, 0x02, 1, PutAll },
+       { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+       { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+       { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+       { "BIT", 0x000000C, 0x00, 2, PutAll },
+       { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+       { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+       { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+       { "BRK", 0x0000001, 0x00, 0, PutAll },
+       { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+       { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+       { "CLC", 0x0000001, 0x18, 0, PutAll },
+       { "CLD", 0x0000001, 0xd8, 0, PutAll },
+       { "CLI", 0x0000001, 0x58, 0, PutAll },
+       { "CLV", 0x0000001, 0xb8, 0, PutAll },
+       { "CMP", 0x080A26C, 0xc0, 0, PutAll },
+       { "CPX", 0x080000C, 0xe0, 1, PutAll },
+       { "CPY", 0x080000C, 0xc0, 1, PutAll },
+       { "DEC", 0x000006C, 0x00, 3, PutAll },
+       { "DEX", 0x0000001, 0xca, 0, PutAll },
+       { "DEY", 0x0000001, 0x88, 0, PutAll },
+       { "EOR", 0x080A26C, 0x40, 0, PutAll },
+       { "INC", 0x000006c, 0x00, 4, PutAll },
+       { "INX", 0x0000001, 0xe8, 0, PutAll },
+       { "INY", 0x0000001, 0xc8, 0, PutAll },
+       { "JMP", 0x0000808, 0x4c, 6, PutAll },
+       { "JSR", 0x0000008, 0x20, 7, PutAll },
+       { "LDA", 0x080A26C, 0xa0, 0, PutAll },
+       { "LDX", 0x080030C, 0xa2, 1, PutAll },
+       { "LDY", 0x080006C, 0xa0, 1, PutAll },
+       { "LSR", 0x000006F, 0x42, 1, PutAll },
+       { "NOP", 0x0000001, 0xea, 0, PutAll },
+       { "ORA", 0x080A26C, 0x00, 0, PutAll },
+       { "PHA", 0x0000001, 0x48, 0, PutAll },
+       { "PHP", 0x0000001, 0x08, 0, PutAll },
+       { "PLA", 0x0000001, 0x68, 0, PutAll },
+       { "PLP", 0x0000001, 0x28, 0, PutAll },
+       { "ROL", 0x000006F, 0x22, 1, PutAll },
+       { "ROR", 0x000006F, 0x62, 1, PutAll },
+       { "RTI", 0x0000001, 0x40, 0, PutAll },
+       { "RTS", 0x0000001, 0x60, 0, PutAll },
+       { "SBC", 0x080A26C, 0xe0, 0, PutAll },
+       { "SEC", 0x0000001, 0x38, 0, PutAll },
+       { "SED", 0x0000001, 0xf8, 0, PutAll },
+       { "SEI", 0x0000001, 0x78, 0, PutAll },
+       { "STA", 0x000A26C, 0x80, 0, PutAll },
+       { "STX", 0x000010c, 0x82, 1, PutAll },
+       { "STY", 0x000002c, 0x80, 1, PutAll },
+       { "TAX", 0x0000001, 0xaa, 0, PutAll },
+       { "TAY", 0x0000001, 0xa8, 0, PutAll },
+       { "TSX", 0x0000001, 0xba, 0, PutAll },
+       { "TXA", 0x0000001, 0x8a, 0, PutAll },
+       { "TXS", 0x0000001, 0x9a, 0, PutAll },
+       { "TYA", 0x0000001, 0x98, 0, PutAll }
+    }
+};
+
+/* Instruction table for the 65SC02 */
+#define INS_COUNT_65SC02       66
+static const struct {
+    unsigned Count;
+    InsDesc  Ins[INS_COUNT_65SC02];
+} InsTab65SC02 = {
+    INS_COUNT_65SC02,
+    {
+       { "ADC", 0x080A66C, 0x60, 0, PutAll },
+       { "AND", 0x080A66C, 0x20, 0, PutAll },
+       { "ASL", 0x000006e, 0x02, 1, PutAll },
+       { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+       { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+       { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+       { "BIT", 0x080006C, 0x00, 2, PutAll },
+       { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+       { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+       { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+       { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
+       { "BRK", 0x0000001, 0x00, 0, PutAll },
+       { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+       { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+       { "CLC", 0x0000001, 0x18, 0, PutAll },
+       { "CLD", 0x0000001, 0xd8, 0, PutAll },
+       { "CLI", 0x0000001, 0x58, 0, PutAll },
+       { "CLV", 0x0000001, 0xb8, 0, PutAll },
+       { "CMP", 0x080A66C, 0xc0, 0, PutAll },
+       { "CPX", 0x080000C, 0xe0, 1, PutAll },
+       { "CPY", 0x080000C, 0xc0, 1, PutAll },
+       { "DEA", 0x0000001, 0x00, 3, PutAll },   /* == DEC */
+       { "DEC", 0x000006F, 0x00, 3, PutAll },
+       { "DEX", 0x0000001, 0xca, 0, PutAll },
+       { "DEY", 0x0000001, 0x88, 0, PutAll },
+       { "EOR", 0x080A66C, 0x40, 0, PutAll },
+       { "INA", 0x0000001, 0x00, 4, PutAll },   /* == INC */
+       { "INC", 0x000006f, 0x00, 4, PutAll },
+       { "INX", 0x0000001, 0xe8, 0, PutAll },
+       { "INY", 0x0000001, 0xc8, 0, PutAll },
+       { "JMP", 0x0010808, 0x4c, 6, PutAll },
+       { "JSR", 0x0000008, 0x20, 7, PutAll },
+       { "LDA", 0x080A66C, 0xa0, 0, PutAll },
+       { "LDX", 0x080030C, 0xa2, 1, PutAll },
+       { "LDY", 0x080006C, 0xa0, 1, PutAll },
+       { "LSR", 0x000006F, 0x42, 1, PutAll },
+       { "NOP", 0x0000001, 0xea, 0, PutAll },
+       { "ORA", 0x080A66C, 0x00, 0, PutAll },
+       { "PHA", 0x0000001, 0x48, 0, PutAll },
+       { "PHP", 0x0000001, 0x08, 0, PutAll },
+       { "PHX", 0x0000001, 0xda, 0, PutAll },
+       { "PHY", 0x0000001, 0x5a, 0, PutAll },
+       { "PLA", 0x0000001, 0x68, 0, PutAll },
+       { "PLP", 0x0000001, 0x28, 0, PutAll },
+       { "PLX", 0x0000001, 0xfa, 0, PutAll },
+       { "PLY", 0x0000001, 0x7a, 0, PutAll },
+       { "ROL", 0x000006F, 0x22, 1, PutAll },
+       { "ROR", 0x000006F, 0x62, 1, PutAll },
+       { "RTI", 0x0000001, 0x40, 0, PutAll },
+       { "RTS", 0x0000001, 0x60, 0, PutAll },
+       { "SBC", 0x080A66C, 0xe0, 0, PutAll },
+       { "SEC", 0x0000001, 0x38, 0, PutAll },
+       { "SED", 0x0000001, 0xf8, 0, PutAll },
+       { "SEI", 0x0000001, 0x78, 0, PutAll },
+       { "STA", 0x000A66C, 0x80, 0, PutAll },
+       { "STX", 0x000010c, 0x82, 1, PutAll },
+       { "STY", 0x000002c, 0x80, 1, PutAll },
+       { "STZ", 0x000006c, 0x04, 5, PutAll },
+       { "TAX", 0x0000001, 0xaa, 0, PutAll },
+       { "TAY", 0x0000001, 0xa8, 0, PutAll },
+       { "TRB", 0x000000c, 0x10, 1, PutAll },
+       { "TSB", 0x000000c, 0x00, 1, PutAll },
+       { "TSX", 0x0000001, 0xba, 0, PutAll },
+       { "TXA", 0x0000001, 0x8a, 0, PutAll },
+       { "TXS", 0x0000001, 0x9a, 0, PutAll },
+       { "TYA", 0x0000001, 0x98, 0, PutAll }
+    }
+};
+
+/* Instruction table for the 65816 */
+#define INS_COUNT_65816        101
+static const struct {
+    unsigned Count;
+    InsDesc  Ins[INS_COUNT_65816];
+} InsTab65816 = {
+    INS_COUNT_65816,
+    {
+       { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
+       { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
+       { "ASL", 0x000006e, 0x02, 1, PutAll },
+       { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+       { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+       { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+       { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 },   /* == BCS */
+       { "BIT", 0x0a0006c, 0x00, 2, PutAll },
+       { "BLT", 0x0020000, 0x90, 0, PutPCRel8 },   /* == BCC */
+       { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+       { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+       { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+       { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
+       { "BRK", 0x0000001, 0x00, 0, PutAll },
+       { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
+       { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+       { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+       { "CLC", 0x0000001, 0x18, 0, PutAll },
+       { "CLD", 0x0000001, 0xd8, 0, PutAll },
+       { "CLI", 0x0000001, 0x58, 0, PutAll },
+       { "CLV", 0x0000001, 0xb8, 0, PutAll },
+       { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
+       { "COP", 0x0000004, 0x02, 6, PutAll },
+       { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll },   /* == CMP */
+       { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
+       { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
+       { "DEA", 0x0000001, 0x00, 3, PutAll },   /* == DEC */
+       { "DEC", 0x000006F, 0x00, 3, PutAll },
+       { "DEX", 0x0000001, 0xca, 0, PutAll },
+       { "DEY", 0x0000001, 0x88, 0, PutAll },
+       { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
+       { "INA", 0x0000001, 0x00, 4, PutAll },   /* == INC */
+       { "INC", 0x000006F, 0x00, 4, PutAll },
+       { "INX", 0x0000001, 0xe8, 0, PutAll },
+       { "INY", 0x0000001, 0xc8, 0, PutAll },
+       { "JML", 0x0000810, 0x5c, 1, PutAll },
+       { "JMP", 0x0010818, 0x4c, 6, PutAll },
+       { "JSL", 0x0000010, 0x20, 7, PutAll },
+       { "JSR", 0x0010018, 0x20, 7, PutAll },
+       { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
+       { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
+       { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
+       { "LSR", 0x000006F, 0x42, 1, PutAll },
+       { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
+       { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
+       { "NOP", 0x0000001, 0xea, 0, PutAll },
+       { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
+       { "PEA", 0x0000008, 0xf4, 6, PutAll },
+       { "PEI", 0x0800000, 0xd4, 0, PutAll },
+       { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
+       { "PHA", 0x0000001, 0x48, 0, PutAll },
+       { "PHB", 0x0000001, 0x8b, 0, PutAll },
+       { "PHD", 0x0000001, 0x0b, 0, PutAll },
+       { "PHK", 0x0000001, 0x4b, 0, PutAll },
+       { "PHP", 0x0000001, 0x08, 0, PutAll },
+       { "PHX", 0x0000001, 0xda, 0, PutAll },
+       { "PHY", 0x0000001, 0x5a, 0, PutAll },
+       { "PLA", 0x0000001, 0x68, 0, PutAll },
+       { "PLB", 0x0000001, 0xab, 0, PutAll },
+       { "PLD", 0x0000001, 0x2b, 0, PutAll },
+       { "PLP", 0x0000001, 0x28, 0, PutAll },
+       { "PLX", 0x0000001, 0xfa, 0, PutAll },
+       { "PLY", 0x0000001, 0x7a, 0, PutAll },
+       { "REP", 0x0800000, 0xc2, 1, PutREP },
+       { "ROL", 0x000006F, 0x22, 1, PutAll },
+       { "ROR", 0x000006F, 0x62, 1, PutAll },
+       { "RTI", 0x0000001, 0x40, 0, PutAll },
+       { "RTL", 0x0000001, 0x6b, 0, PutAll },
+       { "RTS", 0x0000001, 0x60, 0, PutAll },
+       { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
+       { "SEC", 0x0000001, 0x38, 0, PutAll },
+       { "SED", 0x0000001, 0xf8, 0, PutAll },
+       { "SEI", 0x0000001, 0x78, 0, PutAll },
+       { "SEP", 0x0800000, 0xe2, 1, PutSEP },
+       { "STA", 0x018f6fc, 0x80, 0, PutAll },
+       { "STP", 0x0000001, 0xdb, 0, PutAll },
+       { "STX", 0x000010c, 0x82, 1, PutAll },
+       { "STY", 0x000002c, 0x80, 1, PutAll },
+       { "STZ", 0x000006c, 0x04, 5, PutAll },
+       { "SWA", 0x0000001, 0xeb, 0, PutAll },   /* == XBA */
+       { "TAD", 0x0000001, 0x5b, 0, PutAll },   /* == TCD */
+       { "TAS", 0x0000001, 0x1b, 0, PutAll },   /* == TCS */
+       { "TAX", 0x0000001, 0xaa, 0, PutAll },
+       { "TAY", 0x0000001, 0xa8, 0, PutAll },
+       { "TCD", 0x0000001, 0x5b, 0, PutAll },
+       { "TCS", 0x0000001, 0x1b, 0, PutAll },
+       { "TDA", 0x0000001, 0x7b, 0, PutAll },   /* == TDC */
+       { "TDC", 0x0000001, 0x7b, 0, PutAll },
+       { "TRB", 0x000000c, 0x10, 1, PutAll },
+       { "TSA", 0x0000001, 0x3b, 0, PutAll },   /* == TSC */
+       { "TSB", 0x000000c, 0x00, 1, PutAll },
+       { "TSC", 0x0000001, 0x3b, 0, PutAll },
+       { "TSX", 0x0000001, 0xba, 0, PutAll },
+       { "TXA", 0x0000001, 0x8a, 0, PutAll },
+       { "TXS", 0x0000001, 0x9a, 0, PutAll },
+       { "TXY", 0x0000001, 0x9b, 0, PutAll },
+       { "TYA", 0x0000001, 0x98, 0, PutAll },
+       { "TYX", 0x0000001, 0xbb, 0, PutAll },
+       { "WAI", 0x0000001, 0xcb, 0, PutAll },
+       { "XBA", 0x0000001, 0xeb, 0, PutAll },
+       { "XCE", 0x0000001, 0xfb, 0, PutAll }
+    }
+};
+
+#ifdef SUNPLUS
+/* Table for the SUNPLUS CPU */
+#include "sunplus.inc"
+#endif
+
+
+
+/* The current CPU and an array with instruction tables */
+static enum CPUType CPU = CPU_6502;
+static const InsTable* InsTabs[CPU_COUNT] = {
+    (const InsTable*) &InsTab6502,
+    (const InsTable*) &InsTab65SC02,
+    (const InsTable*) &InsTab65816,
+#ifdef SUNPLUS
+    (const InsTable*) &InsTabSunPlus,
+#else
+    NULL,
+#endif
+};
+const InsTable* InsTab = (const InsTable*) &InsTab6502;
+
+/* Table to build the effective opcode from a base opcode and an addressing
+ * mode.
+ */
+unsigned char EATab [9][AMI_COUNT] = {
+    {   /* Table 0 */
+       0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
+       0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
+       0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
+       0x00
+    },
+    {   /* Table 1 */
+       0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
+       0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 2 */
+       0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 3 */
+       0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 4 */
+       0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 5 */
+       0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 6 */
+       0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+       0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 7 */
+       0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00
+    },
+    {   /* Table 8 */
+               0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
+       0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+               0x00
+    },
+};
+
+/* Table that encodes the additional bytes for each instruction */
+unsigned char ExtBytes [AMI_COUNT] = {
+    0,         /* Implicit */
+    0,         /* Accu */
+    1,         /* Direct */
+    2,         /* Absolute */
+    3,                 /* Absolute long */
+    1,         /* Direct,X */
+    2,         /* Absolute,X */
+    3,         /* Absolute long,X */
+    1,         /* Direct,Y */
+    2,         /* Absolute,Y */
+    1,         /* (Direct) */
+    2,         /* (Absolute) */
+    1,         /* [Direct] */
+    1,         /* (Direct),Y */
+    1,         /* [Direct],Y */
+    1,         /* (Direct,X) */
+    2,         /* (Absolute,X) */
+    1,         /* Relative short */
+    2,         /* Relative long */
+    1,         /* r,s */
+    1,         /* (r,s),y */
+    1,         /* Immidiate accu */
+    1,         /* Immidiate index */
+    1,         /* Immidiate byte */
+    2          /* Blockmove */
+};
+
+
+
+/*****************************************************************************/
+/*                            Handler functions                             */
+/*****************************************************************************/
+
+
+
+static long PutImmed8 (const InsDesc* Ins)
+/* Parse and emit an immediate 8 bit instruction. Return the value of the
+ * operand if it's available and const.
+ */
+{
+    ExprNode* Expr;
+    ExprNode* Bank;
+    unsigned long AddrMode;
+    unsigned char OpCode;
+    long Val = -1;
+
+    /* Get the addressing mode used */
+    GetEA (&AddrMode, &Expr, &Bank);
+
+    /* From the possible addressing modes, remove the ones that are invalid
+     * for this instruction or CPU.
+     */
+    AddrMode &= Ins->AddrMode;
+
+    /* If we have possible zero page addressing modes, and the expression
+     * involved (if any) is not in byte range, remove the zero page addressing
+     * modes.
+     */
+    if (Expr && (AddrMode & AM_ZP) && !IsByteExpr (Expr)) {
+       AddrMode &= ~AM_ZP;
+    }
+
+    /* Check if we have any adressing modes left */
+    if (AddrMode == 0) {
+       Error (ERR_ILLEGAL_ADDR_MODE);
+       return -1;
+    }
+    AddrMode = BitFind (AddrMode);
+
+    /* Build the opcode */
+    OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
+
+    /* If we have an expression and it's const, get it's value */
+    if (Expr && IsConstExpr (Expr)) {
+       Val = GetExprVal (Expr);
+    }
+
+    /* Check how many extension bytes are needed and output the instruction */
+    switch (ExtBytes [AddrMode]) {
+
+       case 1:
+           Emit1 (OpCode, Expr);
+           break;
+
+       default:
+           Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
+    }
+
+    /* Return the expression value */
+    return Val;
+}
+
+
+
+static void PutPCRel8 (const InsDesc* Ins)
+/* Handle branches with a 8 bit distance */
+{
+    EmitPCRel (Ins->BaseCode, BranchExpr (2), 1);
+}
+
+
+
+static void PutPCRel16 (const InsDesc* Ins)
+/* Handle branches with an 16 bit distance and PER */
+{
+    EmitPCRel (Ins->BaseCode, BranchExpr (3), 2);
+}
+
+
+
+static void PutBlockMove (const InsDesc* Ins)
+/* Handle the blockmove instructions */
+{
+    Emit0 (Ins->BaseCode);
+    EmitByte (Expression ());
+    ConsumeComma ();
+    EmitByte (Expression ());
+}
+
+
+
+static void PutREP (const InsDesc* Ins)
+/* Emit a REP instruction, track register sizes */
+{
+    /* Use the generic handler */
+    long Val = PutImmed8 (Ins);
+
+    /* We track the status only for the 816 CPU and in smart mode */
+    if (CPU == CPU_65816 && SmartMode) {
+
+       /* Check the range for Val. */
+       if (Val < 0) {
+           /* We had an error */
+           Warning (WARN_CANNOT_TRACK_STATUS);
+       } else {
+           if (Val & 0x10) {
+               /* Index registers to 16 bit */
+               ExtBytes [AMI_IMM_INDEX] = 2;
+           }
+           if (Val & 0x20) {
+               /* Accu to 16 bit */
+               ExtBytes [AMI_IMM_ACCU] = 2;
+           }
+       }
+    }
+}
+
+
+
+static void PutSEP (const InsDesc* Ins)
+/* Emit a SEP instruction, track register sizes */
+{
+    /* Use the generic handler */
+    long Val = PutImmed8 (Ins);
+
+    /* We track the status only for the 816 CPU and in smart mode */
+    if (CPU == CPU_65816 && SmartMode) {
+
+       /* Check the range for Val. */
+       if (Val < 0) {
+           /* We had an error */
+           Warning (WARN_CANNOT_TRACK_STATUS);
+       } else {
+           if (Val & 0x10) {
+               /* Index registers to 8 bit */
+               ExtBytes [AMI_IMM_INDEX] = 1;
+           }
+           if (Val & 0x20) {
+               /* Accu to 8 bit */
+               ExtBytes [AMI_IMM_ACCU] = 1;
+           }
+       }
+    }
+}
+
+
+
+static void PutAll (const InsDesc* Ins)
+/* Handle all other instructions */
+{
+    ExprNode* Expr;
+    ExprNode* Bank;
+    unsigned long AddrModeSet;
+    unsigned char OpCode;
+    unsigned AddrMode;
+    unsigned long AddrModeBit;
+
+    /* Get the addressing mode used */
+    GetEA (&AddrModeSet, &Expr, &Bank);
+
+    /* From the possible addressing modes, remove the ones that are invalid
+     * for this instruction or CPU.
+     */
+    AddrModeSet &= Ins->AddrMode;
+
+    /* If we have possible zero page addressing modes, and the expression
+     * involved (if any) is not in byte range, remove the zero page addressing
+     * modes.
+     */
+    if (Expr && (AddrModeSet & AM_ZP) && !IsByteExpr (Expr)) {
+       AddrModeSet &= ~AM_ZP;
+    }
+
+    /* Check if we have any adressing modes left */
+    if (AddrModeSet == 0) {
+       Error (ERR_ILLEGAL_ADDR_MODE);
+       return;
+    }
+    AddrMode = BitFind (AddrModeSet);
+
+    /* Build the opcode */
+    OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
+
+    /* Check how many extension bytes are needed and output the instruction */
+    switch (ExtBytes [AddrMode]) {
+
+        case 0:
+           Emit0 (OpCode);
+           break;
+
+       case 1:
+           Emit1 (OpCode, Expr);
+           break;
+
+       case 2:
+           AddrModeBit = (1L << AddrMode);
+           if (CPU == CPU_65816 && (AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
+               /* This is a 16 bit mode that uses an address. If in 65816,
+                * mode, force this address into 16 bit range to allow
+                * addressing inside a 64K segment.
+                */
+               Emit2 (OpCode, ForceWordExpr (Expr));
+           } else {
+               Emit2 (OpCode, Expr);
+           }
+           break;
+
+       case 3:
+           if (Bank) {
+               /* Separate bank given */
+               Emit3b (OpCode, Expr, Bank);
+           } else {
+               /* One far argument */
+               Emit3 (OpCode, Expr);
+           }
+           break;
+
+       default:
+           Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static int CmpName (const void* Key, const void* Instr)
+/* Compare function for bsearch */
+{
+    return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
+}
+
+
+
+void SetCPU (enum CPUType NewCPU)
+/* Set a new CPU */
+{
+    /* Make sure the parameter is correct */
+    CHECK (NewCPU < CPU_COUNT);
+
+    /* Check if we have support for the new CPU, if so, use it */
+    if (InsTabs[NewCPU]) {
+       CPU = NewCPU;
+       InsTab = InsTabs[CPU];
+    } else {
+       Error (ERR_CPU_NOT_SUPPORTED);
+    }
+}
+
+
+
+enum CPUType GetCPU (void)
+/* Return the current CPU */
+{
+    return CPU;
+}
+
+
+
+int FindInstruction (const char* Ident)
+/* Check if Ident is a valid mnemonic. If so, return the index in the
+ * instruction table. If not, return -1.
+ */
+{
+    const InsDesc* I;
+    char Key [sizeof (I->Mnemonic)];
+
+    /* Accept only strings with the right length */
+    if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
+               /* Wrong length */
+               return -1;
+    }
+
+    /* Make a copy, and uppercase that copy */
+    Key [0] = toupper (Ident [0]);
+    Key [1] = toupper (Ident [1]);
+    Key [2] = toupper (Ident [2]);
+    Key [3] = '\0';
+
+    /* Search for the key */
+    I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
+    if (I == 0) {
+               /* Not found */
+               return -1;
+    } else {
+               /* Found, return the entry */
+               return I - InsTab->Ins;
+    }
+}
+
+
+
+void HandleInstruction (unsigned Index)
+/* Handle the mnemonic with the given index */
+{
+    /* Safety check */
+    PRECONDITION (Index < InsTab->Count);
+
+    /* Skip the mnemonic token */
+    NextTok ();
+
+    /* Call the handler */
+    InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
+}
+
+
+
diff --git a/src/ca65/instr.h b/src/ca65/instr.h
new file mode 100644 (file)
index 0000000..7d30dd4
--- /dev/null
@@ -0,0 +1,156 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 instr.h                                  */
+/*                                                                           */
+/*            Instruction encoding for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef INSTR_H
+#define INSTR_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Supported CPUs */
+enum CPUType {
+    CPU_6502,
+    CPU_65C02,
+    CPU_65816,
+    CPU_SUNPLUS,       /* Not in the freeware version - sorry */
+    CPU_COUNT          /* Count of different CPUs */
+};
+
+/* Constants for the addressing mode. If an opcode is available in zero page
+ * and absolut adressing mode, both bits are set. When checking for valid
+ * modes, the zeropage bit is checked first. Similar, the implicit bit is set
+ * on accu adressing modes, so the 'A' for accu adressing is not needed (but
+ * may be specified).
+ * When assembling for the 6502 or 65C02, all addressing modes that are not
+ * available on these CPUs are removed before doing any checks.
+ */
+#define AM_IMPLICIT                    0x00000003UL
+#define AM_ACCU                        0x00000002UL
+#define AM_DIR                 0x00000004UL
+#define AM_ABS                 0x00000008UL
+#define AM_ABS_LONG            0x00000010UL
+#define AM_DIR_X               0x00000020UL
+#define AM_ABS_X               0x00000040UL
+#define AM_ABS_LONG_X          0x00000080UL
+#define AM_DIR_Y                       0x00000100UL
+#define AM_ABS_Y               0x00000200UL
+#define AM_DIR_IND             0x00000400UL
+#define AM_ABS_IND                     0x00000800UL
+#define AM_DIR_IND_LONG        0x00001000UL
+#define AM_DIR_IND_Y           0x00002000UL
+#define AM_DIR_IND_LONG_Y      0x00004000UL
+#define AM_DIR_X_IND           0x00008000UL
+#define AM_ABS_X_IND           0x00010000UL
+#define AM_REL                 0x00020000UL
+#define AM_REL_LONG                    0x00040000UL
+#define AM_STACK_REL           0x00080000UL
+#define AM_STACK_REL_IND_Y     0x00100000UL
+#define AM_IMM                 0x00E00000UL
+#define AM_BLOCKMOVE                   0x01000000UL
+
+/* Bitmask for all ZP operations that have correspondent ABS ops */
+#define AM_ZP  (AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+
+/* Bit numbers and count */
+#define AMI_IMM_ACCU           21
+#define AMI_IMM_INDEX          22
+#define AMI_COUNT              25
+
+
+
+/* Description for one instruction */
+typedef struct InsDesc_ InsDesc;
+struct InsDesc_ {
+    char               Mnemonic [4];
+    unsigned long              AddrMode;               /* Valid adressing modes */
+    unsigned char      BaseCode;               /* Base opcode */
+    unsigned char      ExtCode;                /* Number of ext code table */
+    void                       (*Emit) (const InsDesc*);/* Handler function */
+};
+
+/* An instruction table */
+typedef struct InsTable_ InsTable;
+struct InsTable_ {
+    unsigned           Count;                  /* Number of intstructions */
+    InsDesc                    Ins[1];                 /* Varying length */
+};
+
+/* The instruction table for the currently active CPU */
+extern const InsTable* InsTab;
+
+/* Table to build the effective opcode from a base opcode and an addressing
+ * mode.
+ */
+extern unsigned char EATab [9][AMI_COUNT];
+
+/* Table that encodes the additional bytes for each instruction */
+extern unsigned char ExtBytes [AMI_COUNT];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void SetCPU (enum CPUType NewCPU);
+/* Set a new CPU */
+
+enum CPUType GetCPU (void);
+/* Return the current CPU */
+
+int FindInstruction (const char* Ident);
+/* Check if Ident is a valid mnemonic. If so, return the index in the
+ * instruction table. If not, return -1.
+ */
+
+void HandleInstruction (unsigned Index);
+/* Handle the mnemonic with the given index */
+
+
+
+/* End of instr.h */
+
+#endif
+
+
+
+
diff --git a/src/ca65/listing.c b/src/ca65/listing.c
new file mode 100644 (file)
index 0000000..8177c6e
--- /dev/null
@@ -0,0 +1,437 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                listing.c                                 */
+/*                                                                           */
+/*               Listing support for the ca65 crossassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/segdefs.h"
+#include "../common/version.h"
+
+#include "error.h"
+#include "fname.h"
+#include "global.h"
+#include "mem.h"
+#include "objcode.h"
+#include "listing.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Single linked list of lines */
+ListLine*              LineList = 0;           /* List of listing lines */
+ListLine*              LineCur  = 0;           /* Current listing line */
+ListLine*       LineLast = 0;          /* Last (current) listing line */
+
+/* Page and other formatting */
+int                    PageLength = -1;        /* Length of a listing page */
+static unsigned        PageNumber = 1;         /* Current listing page number */
+static unsigned PageLines  = 0;                /* Current line on page */
+static unsigned ListBytes  = 12;       /* Number of bytes to list for one line */
+
+/* Switch the listing on/off */
+static int             ListingEnabled = 1;     /* Enabled if > 0 */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void NewListingLine (const char* Line, unsigned char File, unsigned char Depth)
+/* Create a new ListLine struct and insert it */
+{
+    /* Store only if listing is enabled */
+    if (Listing) {
+
+       ListLine* L;
+
+       /* Get the length of the line */
+       unsigned Len = strlen (Line);
+
+       /* Ignore trailing newlines */
+       while (Len > 0 && Line[Len-1] == '\n') {
+           --Len;
+       }
+
+       /* Allocate memory */
+       L = Xmalloc (sizeof (ListLine) + Len);
+
+       /* Initialize the fields. */
+       L->Next         = 0;
+       L->FragList     = 0;
+       L->FragLast     = 0;
+       L->PC           = GetPC ();
+       L->Reloc        = RelocMode;
+       L->File         = File;
+       L->Depth        = Depth;
+       L->Output       = (ListingEnabled > 0);
+       L->ListBytes    = (unsigned char) ListBytes;
+       memcpy (L->Line, Line, Len);
+       L->Line [Len] = '\0';
+
+       /* Insert the line into the list of lines */
+       if (LineList == 0) {
+           LineList = L;
+       } else {
+           LineLast->Next = L;
+       }
+       LineLast = L;
+    }
+}
+
+
+
+void EnableListing (void)
+/* Enable output of lines to the listing */
+{
+    if (Listing) {
+       /* If we're about to enable the listing, do this for the current line
+        * also, so we will see the source line that did this.
+        */
+       if (ListingEnabled++ == 0) {
+           LineCur->Output = 1;
+       }
+    }
+}
+
+
+
+void DisableListing (void)
+/* Disable output of lines to the listing */
+{
+    if (Listing) {
+       if (ListingEnabled == 0) {
+           /* Cannot switch the listing off once more */
+           Error (ERR_COUNTER_UNDERFLOW);
+       } else {
+           --ListingEnabled;
+       }
+    }
+}
+
+
+
+void SetListBytes (int Bytes)
+/* Set the maximum number of bytes listed for one line */
+{
+    if (Bytes < 0) {
+       Bytes = 0;      /* Encode "unlimited" as zero */
+    }
+    ListBytes = Bytes;
+}
+
+
+
+void InitListingLine (void)
+/* Initialize the current listing line */
+{
+    if (Listing) {
+       /* Make the last loaded line the current line */
+       LineCur = LineLast;
+
+       /* Set the values for this line */
+       CHECK (LineCur != 0);
+       LineCur->PC         = GetPC ();
+       LineCur->Reloc      = RelocMode;
+       LineCur->Output     = (ListingEnabled > 0);
+               LineCur->ListBytes  = (unsigned char) ListBytes;
+    }
+}
+
+
+
+static char* AddHex (char* S, unsigned Val)
+/* Add a hex byte in ASCII to the given string and return the new pointer */
+{
+    static const char HexTab [16] = {
+               '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+    };
+
+    *S++ = HexTab [(Val >> 4) & 0x0F];
+    *S++ = HexTab [Val & 0x0F];
+
+    return S;
+}
+
+
+
+static void PrintPageHeader (FILE* F, const ListLine* L)
+/* Print the header for a new page. It is assumed that the given line is the
+ * last line of the previous page.
+ */
+{
+    /* Print the header on the new page */
+    fprintf (F, 
+            "ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n"
+            "Main file   : %s\n"
+            "Current file: %s\n"
+            "\n",
+            VER_MAJOR, VER_MINOR, VER_PATCH,
+            InFile,
+            GetFileName (L->File));
+
+    /* Count pages, reset lines */
+    ++PageNumber;
+    PageLines = 4;
+}
+
+
+
+static void PrintLine (FILE* F, const char* Header, const char* Line, const ListLine* L)
+/* Print one line to the listing file, adding a newline and counting lines */
+{
+    /* Print the given line */
+    fprintf (F, "%s%s\n", Header, Line);
+
+    /* Increment the current line */
+    ++PageLines;
+
+    /* Switch to a new page if needed. Do not switch, if the current line is
+     * the last one, to avoid pages that consist of just the header.
+     */
+    if (PageLength > 0 && PageLines >= PageLength && L->Next != 0) {
+       /* Do a formfeed */
+               putc ('\f', F);
+       /* Print the header on the new page */
+       PrintPageHeader (F, L);
+    }
+}
+
+
+
+static char* AddMult (char* S, char C, unsigned Count)
+/* Add multiple instances of character C to S, return updated S. */
+{
+    memset (S, C, Count);
+    return S + Count;
+}
+
+
+
+static char* MakeLineHeader (char* H, const ListLine* L)
+/* Prepare the line header */
+{
+    char Mode;
+    char Depth;
+
+    /* Setup the PC mode */
+    Mode = (L->Reloc)? 'r' : ' ';
+
+    /* Set up the include depth */
+    Depth = (L->Depth < 10)? L->Depth + '0' : '+';
+
+    /* Format the line */
+    sprintf (H, "%06lX%c %c", L->PC, Mode, Depth);
+    memset (H+9, ' ', LINE_HEADER_LEN-9);
+
+    /* Return the buffer */
+    return H;
+}
+
+
+
+void CreateListing (void)
+/* Create the listing */
+{
+    FILE* F;
+    Fragment* Frag;
+    ListLine* L;
+    char HeaderBuf [LINE_HEADER_LEN+1];
+
+    /* Create the name of the listing file if needed */
+    if (ListFile == 0) {
+       ListFile = MakeFilename (InFile, ListExt);
+    }
+
+    /* Open the real listing file */
+    F = fopen (ListFile, "w");
+    if (F == 0) {
+       Fatal (FAT_CANNOT_OPEN_LISTING, strerror (errno));
+    }
+
+    /* Reset variables, print the header for the first page */
+    PageNumber = 0;
+    PrintPageHeader (F, LineList);
+
+    /* Terminate the header buffer. The last byte will never get overwritten */
+    HeaderBuf [LINE_HEADER_LEN] = '\0';
+
+    /* Walk through all listing lines */
+    L = LineList;
+    while (L) {
+
+       char* Buf;
+       char* B;
+       unsigned Count;
+       unsigned I;
+       char* Line;
+
+       /* If we should not output this line, go to the next */
+       if (L->Output == 0) {
+           L = L->Next;
+           continue;
+       }
+
+       /* If we don't have a fragment list for this line, things are easy */
+       if (L->FragList == 0) {
+           PrintLine (F, MakeLineHeader (HeaderBuf, L), L->Line, L);
+           L = L->Next;
+           continue;
+       }
+
+       /* Count the number of bytes in the complete fragment list */
+       Count = 0;
+       Frag = L->FragList;
+       while (Frag) {
+           Count += Frag->Len;
+           Frag = Frag->LineList;
+       }
+
+       /* Allocate memory for the given number of bytes */
+       Buf = Xmalloc (Count*2+1);
+
+       /* Copy an ASCII representation of the bytes into the buffer */
+       B = Buf;
+       Frag = L->FragList;
+       while (Frag) {
+
+           /* Write data depending on the type */
+           switch (Frag->Type) {
+
+               case FRAG_LITERAL:
+                   for (I = 0; I < Frag->Len; ++I) {
+                       B = AddHex (B, Frag->V.Data[I]);
+                   }
+                   break;
+
+               case FRAG_EXPR:
+               case FRAG_SEXPR:
+                   B = AddMult (B, 'r', Frag->Len*2);
+                   break;
+
+               case FRAG_FILL:
+                   B = AddMult (B, 'x', Frag->Len*2);
+                   break;
+
+               default:
+                   Internal ("Invalid fragment type: %u", Frag->Type);
+
+           }
+
+           /* Next fragment */
+           Frag = Frag->LineList;
+
+       }
+
+       /* Limit the number of bytes actually printed */
+       if (L->ListBytes != 0) {
+           /* Not unlimited */
+           if (Count > L->ListBytes) {
+               Count = L->ListBytes;
+           }
+       }
+
+       /* Output the data. The format of a listing line is:
+        *
+                *      PPPPPPm I  11 22 33 44
+        *
+        * where
+        *
+        *      PPPPPP  is the PC
+        *      m       is the mode ('r' or empty)
+        *      I       is the include level
+        *      11 ..   are code or data bytes
+        */
+       Line = L->Line;
+               B    = Buf;
+       while (Count) {
+
+           unsigned    Chunk;
+           char*       P;
+
+           /* Prepare the line header */
+                   MakeLineHeader (HeaderBuf, L);
+
+           /* Get the number of bytes for the next line */
+           Chunk = Count;
+           if (Chunk > 4) {
+               Chunk = 4;
+           }
+           Count -= Chunk;
+
+           /* Increment the program counter. Since we don't need the PC stored
+            * in the LineList object for anything else, just increment this
+            * variable.
+            */
+           L->PC += Chunk;
+
+           /* Copy the bytes into the line */
+                   P = HeaderBuf + 11;
+                   for (I = 0; I < Chunk; ++I) {
+               *P++ = *B++;
+               *P++ = *B++;
+               *P++ = ' ';
+           }
+
+           /* Output this line */
+           PrintLine (F, HeaderBuf, Line, L);
+
+           /* Don't output a line twice */
+           Line = "";
+
+       }
+
+       /* Delete the temporary buffer */
+       Xfree (Buf);
+
+       /* Next line */
+       L = L->Next;
+
+    }
+
+    /* Close the listing file */
+    (void) fclose (F);
+}
+
+
+
diff --git a/src/ca65/listing.h b/src/ca65/listing.h
new file mode 100644 (file)
index 0000000..51b3e80
--- /dev/null
@@ -0,0 +1,116 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                listing.h                                 */
+/*                                                                           */
+/*               Listing support for the ca65 crossassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LISTING_H
+#define LISTING_H
+
+
+
+#include "fragment.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Length of the header of a listing line */
+#define LINE_HEADER_LEN                24
+
+/* One listing line as it is stored in memory */
+typedef struct ListLine_ ListLine;
+struct ListLine_ {
+    ListLine*          Next;           /* Pointer to next line */
+    Fragment*          FragList;       /* List of fragments for this line */
+    Fragment*          FragLast;       /* Last entry in fragment list */
+    unsigned long      PC;             /* Program counter for this line */
+    unsigned char      Reloc;          /* Relocatable mode? */
+    unsigned char      File;           /* From which file is the line? */
+    unsigned char      Depth;          /* Include depth */
+    unsigned char      Output;         /* Should we output this line? */
+    unsigned char      ListBytes;      /* How many bytes at max? */
+    char               Line[1];        /* Line with dynamic length */
+};
+
+/* Single linked list of lines */
+extern ListLine*       LineList;       /* List of listing lines */
+extern ListLine*       LineCur;        /* Current listing line */
+extern ListLine*               LineLast;       /* Last listing line */
+
+/* Page formatting */
+#define MIN_PAGE_LEN   32
+#define MAX_PAGE_LEN   127
+extern int             PageLength;     /* Length of a listing page */
+
+/* Byte for one listing line */
+#define MIN_LIST_BYTES 4
+#define MAX_LIST_BYTES 255
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void NewListingLine (const char* Line, unsigned char File, unsigned char Depth);
+/* Create a new ListLine struct */
+
+void EnableListing (void);
+/* Enable output of lines to the listing */
+
+void DisableListing (void);
+/* Disable output of lines to the listing */
+
+void SetListBytes (int Bytes);
+/* Set the maximum number of bytes listed for one line */
+
+void InitListingLine (void);
+/* Initialize the current listing line */
+
+void CreateListing (void);
+/* Create the listing */
+
+
+
+/* End of listing.h */
+
+#endif
+
+
+
diff --git a/src/ca65/macpack.c b/src/ca65/macpack.c
new file mode 100644 (file)
index 0000000..b730b11
--- /dev/null
@@ -0,0 +1,154 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                macpack.c                                 */
+/*                                                                           */
+/*          Predefined macro packages for the ca65 macroassembler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "scanner.h"
+#include "macpack.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Predefined packages */
+static const char MacGeneric [] =      /* Generic macros */
+    ".macro  add     Arg\n"
+    "        clc\n"
+    "        adc     Arg\n"
+    ".endmacro\n\n"
+    ".macro  sub     Arg\n"
+    "        sec\n"
+    "        sbc     Arg\n"
+    ".endmacro\n\n";
+
+
+
+static const char MacLongBranch [] =   /* Long branch macros */
+    ".macro  jeq     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        beq     Target\n"
+    "        .else\n"
+    "        bne     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jne     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bne     Target\n"
+    "        .else\n"
+    "        beq     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jmi     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bmi     Target\n"
+    "        .else\n"
+    "        bpl     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jpl     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bpl     Target\n"
+    "        .else\n"
+    "        bmi     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jcs     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bcs     Target\n"
+    "        .else\n"
+    "        bcc     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jcc     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bcc     Target\n"
+    "        .else\n"
+    "        bcs     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jvs     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bvs     Target\n"
+    "        .else\n"
+    "        bvc     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n"
+    ".macro  jvc     Target\n"
+    "        .if     .def(Target) .and ((*+2)-(Target) <= 127)\n"
+    "        bvc     Target\n"
+    "        .else\n"
+    "        bvs     *+5\n"
+    "        jmp     Target\n"
+    "        .endif\n"
+    ".endmacro\n\n";
+
+
+
+/* Table with pointers to the different packages */
+static const char* MacPackages [] = {
+    MacGeneric,
+    MacLongBranch,
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void InsertMacPack (unsigned Id)
+/* Insert the macro package with the given id in the input stream */
+{
+    /* Check the parameter */
+    CHECK (Id < sizeof (MacPackages) / sizeof (MacPackages [0]));
+
+    /* Insert the package */
+    NewInputData (MacPackages [Id], 0);
+}
+
+
+
diff --git a/src/ca65/macpack.h b/src/ca65/macpack.h
new file mode 100644 (file)
index 0000000..e292922
--- /dev/null
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                macpack.h                                 */
+/*                                                                           */
+/*          Predefined macro packages for the ca65 macroassembler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MACPACK_H
+#define MACPACK_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Constants for the predefined packages */
+#define MAC_GENERIC            0
+#define        MAC_LONGBRANCH          1
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void InsertMacPack (unsigned Id);
+/* Insert the macro package with the given id in the input stream */
+
+
+
+/* End of macpack.h */
+
+#endif
+
+
+
diff --git a/src/ca65/macro.c b/src/ca65/macro.c
new file mode 100644 (file)
index 0000000..73d8a00
--- /dev/null
@@ -0,0 +1,769 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 macro.c                                  */
+/*                                                                           */
+/*                   Macros for the ca65 macroassembler                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "scanner.h"
+#include "toknode.h"
+#include "pseudo.h"
+#include "macro.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Struct that describes an identifer (macro param, local list) */
+typedef struct IdDesc_ IdDesc;
+struct IdDesc_ {
+    IdDesc*        Next;       /* Linked list */
+    char                   Id [1];     /* Identifier, dynamically allocated */
+};
+
+
+
+/* Struct that describes a macro definition */
+typedef struct Macro_ Macro;
+struct Macro_ {
+    Macro*                 Next;       /* Next macro with same hash */
+    Macro*         List;       /* List of all macros */
+    unsigned       LocalCount; /* Count of local symbols */
+    IdDesc*        Locals;     /* List of local symbols */
+    unsigned       ParamCount; /* Parameter count of macro */
+    IdDesc*                Params;     /* Identifiers of macro parameters */
+    unsigned       TokCount;   /* Number of tokens for this macro */
+    TokNode*       TokRoot;    /* Root of token list */
+    TokNode*       TokLast;    /* Pointer to last token in list */
+    unsigned char   Style;     /* Macro style */
+    char                   Name [1];   /* Macro name, dynamically allocated */
+};
+
+/* Macro hash table */
+#define HASHTAB_SIZE           117
+static Macro*          MacroTab [HASHTAB_SIZE];
+
+/* Global macro data */
+static Macro*          MacroRoot = 0;  /* List of all macros */
+
+/* Structs that holds data for a macro expansion */
+typedef struct MacExp_ MacExp;
+struct MacExp_ {
+    MacExp*    Next;           /* Pointer to next expansion */
+    Macro*     M;              /* Which macro do we expand? */
+    TokNode*           Exp;            /* Pointer to current token */
+    TokNode*   Final;          /* Pointer to final token */
+    unsigned    LocalStart;    /* Start of counter for local symbol names */
+    unsigned   ParamCount;     /* Number of actual parameters */
+    TokNode**  Params;         /* List of actual parameters */
+    TokNode*   ParamExp;       /* Node for expanding parameters */
+};
+
+/* Data for macro expansions */
+#define        MAX_MACRO_EXPANSIONS    255
+static unsigned        MacroNesting    = 0;
+static MacExp*  CurMac         = 0;
+static unsigned LocalName      = 0;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static IdDesc* NewIdDesc (const char* Id)
+/* Create a new IdDesc, initialize and return it */
+{
+    /* Allocate memory */
+    unsigned Len = strlen (Id);
+    IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
+
+    /* Initialize the struct */
+    I->Next = 0;
+    memcpy (I->Id, Id, Len);
+    I->Id [Len] = '\0';
+
+    /* Return the new struct */
+    return I;
+}
+
+
+
+static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
+/* Generate a new macro entry, initialize and return it */
+{
+    /* Allocate memory */
+    unsigned Len = strlen (Name);
+    Macro* M = Xmalloc (sizeof (Macro) + Len);
+
+    /* Initialize the macro struct */
+    M->LocalCount = 0;
+    M->ParamCount = 0;
+    M->Params     = 0;
+    M->TokCount          = 0;
+    M->TokRoot    = 0;
+    M->TokLast    = 0;
+    M->Style     = Style;
+    memcpy (M->Name, Name, Len);
+    M->Name [Len] = '\0';
+
+    /* Insert the macro into the global macro list */
+    M->List = MacroRoot;
+    MacroRoot = M;
+
+    /* Insert the macro into the hash table */
+    M->Next = MacroTab [HashVal];
+    MacroTab [HashVal] = M;
+
+    /* Return the new macro struct */
+    return M;
+}
+
+
+
+static MacExp* NewMacExp (Macro* M)
+/* Create a new expansion structure for the given macro */
+{
+    unsigned I;
+
+    /* Allocate memory */
+    MacExp* E = Xmalloc (sizeof (MacExp));
+
+    /* Initialize the data */
+    E->M                 = M;
+    E->Exp               = M->TokRoot;
+    E->Final     = 0;
+    E->LocalStart = LocalName;
+    LocalName    += M->LocalCount;
+    E->ParamCount = 0;
+    E->Params     = Xmalloc (M->ParamCount * sizeof (TokNode*));
+    E->ParamExp          = 0;
+    for (I = 0; I < M->ParamCount; ++I) {
+       E->Params [I] = 0;
+    }
+
+    /* And return it... */
+    return E;
+}
+
+
+
+static void MacInsertExp (MacExp* E)
+/* Insert a macro expansion into the list */
+{
+    E->Next = CurMac;
+    CurMac  = E;
+    ++MacroNesting;
+}
+
+
+
+static void FreeMacExp (void)
+/* Remove and free the current macro expansion */
+{
+    unsigned I;
+    MacExp* E;
+
+    /* Free the parameter list */
+    for (I = 0; I < CurMac->ParamCount; ++I) {
+       Xfree (CurMac->Params [I]);
+    }
+    Xfree (CurMac->Params);
+
+    /* Free the final token if we have one */
+    if (CurMac->Final) {
+       FreeTokNode (CurMac->Final);
+    }
+
+    /* Reset the list pointer */
+    E = CurMac;
+    CurMac = E->Next;
+    --MacroNesting;
+
+    /* Free the structure itself */
+    Xfree (E);
+}
+
+
+
+static void MacSkipDef (unsigned Style)
+/* Skip a macro definition */
+{
+    if (Style == MAC_STYLE_CLASSIC) {
+       /* Skip tokens until we reach the final .endmacro */
+       while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
+           NextTok ();
+       }
+       if (Tok != TOK_EOF) {
+           SkipUntilSep ();
+       } else {
+           Error (ERR_ENDMACRO_EXPECTED);
+       }
+    } else {
+       /* Skip until end of line */
+       SkipUntilSep ();
+    }
+}
+
+
+
+static Macro* MacFind (const char* Name, unsigned HashVal)
+/* Search for a macro in the hash table */
+{
+    /* Search for the identifier */
+    Macro* M = MacroTab [HashVal];
+    while (M) {
+       if (strcmp (Name, M->Name) == 0) {
+           return M;
+       }
+       M = M->Next;
+    }
+    return 0;
+}
+
+
+
+void MacDef (unsigned Style)
+/* Parse a macro definition */
+{
+    Macro* M;
+    TokNode* T;
+    unsigned HashVal;
+    int HaveParams;
+
+    /* We expect a macro name here */
+    if (Tok != TOK_IDENT) {
+       Error (ERR_IDENT_EXPECTED);
+       MacSkipDef (Style);
+       return;
+    }
+
+    /* Generate the hash value */
+    HashVal = HashStr (SVal) % HASHTAB_SIZE;
+
+    /* Did we already define that macro? */
+    if (MacFind (SVal, HashVal) != 0) {
+               /* Macro is already defined */
+       Error (ERR_SYM_ALREADY_DEFINED, SVal);
+       /* Skip tokens until we reach the final .endmacro */
+       MacSkipDef (Style);
+               return;
+    }
+
+    /* Define the macro */
+    M = NewMacro (SVal, HashVal, Style);
+    NextTok ();
+
+    /* If we have a DEFINE style macro, we may have parameters in braces,
+     * otherwise we may have parameters without braces.
+     */
+    if (Style == MAC_STYLE_CLASSIC) {
+       HaveParams = 1;
+    } else {
+       if (Tok == TOK_LPAREN) {
+           HaveParams = 1;
+           NextTok ();
+       } else {
+           HaveParams = 0;
+       }
+    }
+
+    /* Parse the parameter list */
+    if (HaveParams) {
+
+       while (Tok == TOK_IDENT) {
+
+           /* Create a struct holding the identifier */
+           IdDesc* I = NewIdDesc (SVal);
+
+           /* Insert the struct into the list, checking for duplicate idents */
+           if (M->ParamCount == 0) {
+               M->Params = I;
+           } else {
+               IdDesc* List = M->Params;
+               while (1) {
+                   if (strcmp (List->Id, SVal) == 0) {
+                       Error (ERR_SYM_ALREADY_DEFINED, SVal);
+                   }
+                   if (List->Next == 0) {
+                       break;
+                   } else {
+                       List = List->Next;
+                   }
+               }
+               List->Next = I;
+           }
+           ++M->ParamCount;
+
+                   /* Skip the name */
+           NextTok ();
+
+           /* Maybe there are more params... */
+           if (Tok == TOK_COMMA) {
+               NextTok ();
+           } else {
+               break;
+           }
+       }
+    }
+
+    /* For class macros, we expect a separator token, for define style macros,
+     * we expect the closing paren.
+     */
+    if (Style == MAC_STYLE_CLASSIC) {
+       ConsumeSep ();
+    } else if (HaveParams) {
+       ConsumeRParen ();
+    }
+
+    /* Preparse the macro body. We will read the tokens until we reach end of
+     * file, or a .endmacro (or end of line for DEFINE style macros) and store
+     * them into an token list internal to the macro. For classic macros, there
+     * the .LOCAL command is detected and removed at this time.
+     */
+    while (1) {
+
+       /* Check for end of macro */
+       if (Style == MAC_STYLE_CLASSIC) {
+           /* In classic macros, only .endmacro is allowed */
+           if (Tok == TOK_ENDMACRO) {
+               /* Done */
+               break;
+           }
+           /* May not have end of file in a macro definition */
+           if (Tok == TOK_EOF) {
+               Error (ERR_ENDMACRO_EXPECTED);
+               return;
+           }
+       } else {
+           /* Accept a newline or end of file for new style macros */
+           if (Tok == TOK_SEP || Tok == TOK_EOF) {
+               break;
+           }
+       }
+
+       /* Check for a .LOCAL declaration */
+       if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
+
+           while (1) {
+
+               IdDesc* I;
+
+               /* Skip .local or comma */
+                       NextTok ();
+
+               /* Need an identifer */
+               if (Tok != TOK_IDENT) {
+                   Error (ERR_IDENT_EXPECTED);
+                   SkipUntilSep ();
+                   break;
+               }
+
+               /* Put the identifier into the locals list and skip it */
+                       I = NewIdDesc (SVal);
+               I->Next = M->Locals;
+               M->Locals = I;
+               ++M->LocalCount;
+               NextTok ();
+
+               /* Check for end of list */
+               if (Tok != TOK_COMMA) {
+                   break;
+               }
+
+           }
+
+           /* We need end of line after the locals */
+           ConsumeSep ();
+           continue;
+       }
+
+       /* Create a token node for the current token */
+       T = NewTokNode ();
+
+       /* If the token is an ident, check if it is a local parameter */
+       if (Tok == TOK_IDENT) {
+           unsigned Count = 0;
+           IdDesc* I = M->Params;
+           while (I) {
+               if (strcmp (I->Id, SVal) == 0) {
+                   /* Local param name, replace it */
+                   T->Tok  = TOK_MACPARAM;
+                   T->IVal = Count;
+                   break;
+               }
+               ++Count;
+                       I = I->Next;
+           }
+       }
+
+       /* Insert the new token in the list */
+       if (M->TokCount == 0) {
+           /* First token */
+           M->TokRoot = M->TokLast = T;
+       } else {
+           /* We have already tokens */
+           M->TokLast->Next = T;
+           M->TokLast = T;
+       }
+       ++M->TokCount;
+
+       /* Read the next token */
+       NextTok ();
+    }
+
+    /* Skip the .endmacro for a classic macro */
+    if (Style == MAC_STYLE_CLASSIC) {
+       NextTok ();
+    }
+}
+
+
+
+static void StartExpClassic (Macro* M)
+/* Start expanding the classic macro M */
+{
+    MacExp* E;
+
+    /* Skip the macro name */
+    NextTok ();
+
+    /* Create a structure holding expansion data */
+    E = NewMacExp (M);
+
+    /* Read the actual parameters */
+    while (Tok != TOK_SEP && Tok != TOK_EOF) {
+
+       TokNode* Last;
+
+               /* Check for maximum parameter count */
+       if (E->ParamCount >= M->ParamCount) {
+           Error (ERR_TOO_MANY_PARAMS);
+           SkipUntilSep ();
+           break;
+       }
+
+       /* Read tokens for one parameter, accept empty params */
+       Last = 0;
+       while (Tok != TOK_COMMA && Tok != TOK_SEP) {
+
+           TokNode* T;
+
+           /* Check for end of file */
+           if (Tok == TOK_EOF) {
+               Error (ERR_SYNTAX);
+               return;
+           }
+
+           /* Get the next token in a node */
+           T = NewTokNode ();
+
+           /* Insert it into the list */
+           if (Last == 0) {
+               E->Params [E->ParamCount] = T;
+           } else {
+               Last->Next = T;
+           }
+           Last = T;
+
+           /* And skip it... */
+           NextTok ();
+       }
+
+       /* One parameter more */
+       ++E->ParamCount;
+
+       /* Check for a comma */
+       if (Tok == TOK_COMMA) {
+           NextTok ();
+       } else {
+           break;
+       }
+    }
+
+    /* Insert the newly created structure into the expansion list */
+    MacInsertExp (E);
+}
+
+
+
+static void StartExpDefine (Macro* M)
+/* Start expanding a DEFINE style macro */
+{
+    /* Create a structure holding expansion data */
+    MacExp* E = NewMacExp (M);
+
+    /* A define style macro must be called with as many actual parameters
+     * as there are formal ones. Get the parameter count.
+     */
+    unsigned Count = M->ParamCount;
+
+    /* Skip the current token */
+    NextTok ();
+
+    /* Read the actual parameters */
+    while (Count--) {
+
+               TokNode* Last;
+
+               /* Check if there is really a parameter */
+               if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
+                   Error (ERR_MACRO_PARAM_EXPECTED);
+                   SkipUntilSep ();
+                   return;
+               }
+
+               /* Read tokens for one parameter */
+               Last = 0;
+               do {
+
+                   TokNode* T;
+
+                   /* Get the next token in a node */
+                   T = NewTokNode ();
+
+                   /* Insert it into the list */
+                   if (Last == 0) {
+                       E->Params [E->ParamCount] = T;
+                   } else {
+                       Last->Next = T;
+                   }
+                   Last = T;
+
+           /* And skip it... */
+           NextTok ();
+
+       } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
+
+       /* One parameter more */
+       ++E->ParamCount;
+
+               /* Check for a comma */
+               if (Count > 0) {
+                   if (Tok == TOK_COMMA) {
+                       NextTok ();
+                   } else {
+                       Error (ERR_COMMA_EXPECTED);
+                   }
+               }
+    }
+
+    /* Macro expansion will overwrite the current token. This is a problem
+     * for define style macros since these are called from the scanner level.
+     * To avoid it, remember the current token and re-insert it if macro
+     * expansion is done.
+     */
+    E->Final = NewTokNode ();
+
+    /* Insert the newly created structure into the expansion list */
+    MacInsertExp (E);
+}
+
+
+
+void MacExpandStart (void)
+/* Start expanding the macro in SVal */
+{
+    Macro* M;
+
+    /* Beware of runoff macros */
+    if (MacroNesting ==        MAX_MACRO_EXPANSIONS) {
+       Fatal (FAT_MACRO_NESTING);
+    }
+
+    /* Search for the macro */
+    M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+    CHECK (M != 0);
+
+    /* Call the apropriate subroutine */
+    switch (M->Style) {
+       case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
+       case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
+       default:                Internal ("Invalid macro style: %d", M->Style);
+    }
+}
+
+
+
+int MacExpand (void)
+/* If we're currently expanding a macro, set the the scanner token and
+ * attribute to the next value and return true. If we are not expanding
+ * a macro, return false.
+ */
+{
+    if (MacroNesting == 0) {
+               /* Not expanding a macro */
+        return 0;
+    }
+
+    /* We're expanding a macro. Check if we are expanding one of the
+     * macro parameters.
+     */
+    if (CurMac->ParamExp) {
+
+               /* Ok, use token from parameter list */
+               TokSet (CurMac->ParamExp);
+
+               /* Set pointer to next token */
+               CurMac->ParamExp = CurMac->ParamExp->Next;
+
+               /* Done */
+               return 1;
+
+    } else if (CurMac->Exp) {
+
+               /* We're not expanding a parameter, use next macro token */
+               TokSet (CurMac->Exp);
+
+               /* Set pointer to next token */
+               CurMac->Exp = CurMac->Exp->Next;
+
+               /* Is it a request for actual parameter count? */
+               if (Tok == TOK_PARAMCOUNT) {
+                   Tok  = TOK_INTCON;
+                   IVal = CurMac->ParamCount;
+                   return 1;
+               }
+
+               /* Is it an .exitmacro command? */
+               if (Tok == TOK_EXITMACRO) {
+                   /* Forced exit from macro expansion */
+                   FreeMacExp ();
+                   return MacExpand ();
+               }
+
+               /* Is it the name of a macro parameter? */
+               if (Tok == TOK_MACPARAM) {
+
+                   /* Start to expand the parameter token list */
+                   CurMac->ParamExp = CurMac->Params [IVal];
+
+                   /* Recursive call to expand the parameter */
+                   return MacExpand ();
+               }
+
+               /* If it's an identifier, it may in fact be a local symbol */
+               if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
+                   /* Search for the local symbol in the list */
+                   unsigned Index = 0;
+                   IdDesc* I = CurMac->M->Locals;
+                   while (I) {
+                       if (strcmp (SVal, I->Id) == 0) {
+                           /* This is in fact a local symbol, change the name */
+                           sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
+                           break;
+                       }
+                       /* Next symbol */
+                       ++Index;
+                       I = I->Next;
+                   }
+
+                   /* Done */
+                   return 1;
+               }
+
+               /* The token was successfully set */
+               return 1;
+
+    } else if (CurMac->Final) {
+
+       /* Set the final token and remove it */
+       TokSet (CurMac->Final);
+       FreeTokNode (CurMac->Final);
+       CurMac->Final = 0;
+
+               /* The token was successfully set */
+               return 1;
+
+    } else {
+
+               /* End of macro expansion */
+               FreeMacExp ();
+               return MacExpand ();
+
+    }
+}
+
+
+
+void MacAbort (void)
+/* Abort the current macro expansion */
+{
+    /* Must have an expansion */
+    CHECK (CurMac != 0);
+
+    /* Free current structure */
+    FreeMacExp ();
+}
+
+
+
+int IsMacro (const char* Name)
+/* Return true if the given name is the name of a macro */
+{
+    return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
+}
+
+
+
+int IsDefine (const char* Name)
+/* Return true if the given name is the name of a define style macro */
+{
+    Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+    return (M != 0 && M->Style == MAC_STYLE_DEFINE);
+}
+
+
+
+int InMacExpansion (void)
+/* Return true if we're currently expanding a macro */
+{
+    return MacroNesting != 0;
+}
+
+
+
+
+
+
diff --git a/src/ca65/macro.h b/src/ca65/macro.h
new file mode 100644 (file)
index 0000000..defcd9a
--- /dev/null
@@ -0,0 +1,90 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 macro.h                                  */
+/*                                                                           */
+/*                   Macros for the ca65 macroassembler                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MACRO_H
+#define MACRO_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Macro styles */
+#define MAC_STYLE_CLASSIC      0
+#define MAC_STYLE_DEFINE       1
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void MacDef (unsigned Style);
+/* Parse a macro definition */
+
+void MacExpandStart (void);
+/* Start expanding the macro in SVal */
+
+int MacExpand (void);
+/* If we're currently expanding a macro, set the the scanner token and
+ * attribute to the next value and return true. If we are not expanding
+ * a macro, return false.
+ */
+
+void MacAbort (void);
+/* Abort the current macro expansion */
+
+int IsMacro (const char* Name);
+/* Return true if the given name is the name of a macro */
+
+int IsDefine (const char* Name);
+/* Return true if the given name is the name of a define style macro */
+
+int InMacExpansion (void); 
+/* Return true if we're currently expanding a macro */
+
+
+
+/* End of macro.h */
+
+#endif
+
+
+
diff --git a/src/ca65/main.c b/src/ca65/main.c
new file mode 100644 (file)
index 0000000..1c65f09
--- /dev/null
@@ -0,0 +1,564 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 main.c                                   */
+/*                                                                           */
+/*                Main program for the ca65 macroassembler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macro.h"
+#include "mem.h"
+#include "objcode.h"
+#include "objfile.h"
+#include "options.h"
+#include "pseudo.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "ulabel.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+    fprintf (stderr,
+            "Usage: %s [options] file\n"
+            "Options:\n"
+            "\t-g\t\tAdd debug info to object file\n"
+            "\t-i\t\tIgnore case of symbols\n"
+            "\t-l\t\tCreate a listing if assembly was ok\n"
+                    "\t-o name\t\tName the output file\n"
+            "\t-s\t\tEnable smart mode\n"
+            "\t-v\t\tIncrease verbosity\n"
+            "\t-D name[=value]\tDefine a symbol\n"
+            "\t-U\t\tMark unresolved symbols as import\n"
+            "\t-V\t\tPrint the assembler version\n"
+            "\t-W n\t\tSet warning level n\n"
+            "\t--cpu type\tSet cpu type\n"
+            "\t--pagelength n\tSet the page length for the listing\n"
+                    "\t--smart\t\tEnable smart mode\n",
+            ProgName);
+    exit (EXIT_FAILURE);
+}
+
+
+
+static void UnknownOption (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+    fprintf (stderr, "Unknown option: %s\n", Arg);
+    Usage ();
+}
+
+
+
+static void NeedArg (const char* Arg)
+/* Print an error about a missing option argument and exit. */
+{
+    fprintf (stderr, "Option requires an argument: %s\n", Arg);
+    exit (EXIT_FAILURE);
+}
+
+
+
+static void InvSym (const char* Def)
+/* Print an error about an invalid symbol definition and die */
+{
+    fprintf (stderr, "Invalid symbol definition: `%s'\n", Def);
+    exit (EXIT_FAILURE);
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+    const char* Arg = argv [*ArgNum];
+    if (Arg [Len] != '\0') {
+       /* Argument appended */
+       return Arg + Len;
+    } else {
+       /* Separate argument */
+       Arg = argv [*ArgNum + 1];
+       if (Arg == 0) {
+           /* End of arguments */
+           NeedArg (argv [*ArgNum]);
+       }
+       ++(*ArgNum);
+       return Arg;
+    }
+}
+
+
+
+static void SetOptions (void)
+/* Set the option for the translator */
+{
+    char Buf [256];
+
+    /* Set the translator */
+    sprintf (Buf, "ca65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+    OptTranslator (Buf);
+
+    /* Set date and time */
+    OptDateTime ((unsigned long) time(0));
+}
+
+
+
+static void DefineSymbol (const char* Def)
+/* Define a symbol from the command line */
+{
+    const char* P;
+    unsigned I;
+    long Val;
+    char SymName [MAX_STR_LEN+1];
+
+    /* The symbol must start with a character or underline */
+    if (Def [0] != '_' && !isalpha (Def [0])) {
+       InvSym (Def);
+    }
+    P = Def;
+
+    /* Copy the symbol, checking the rest */
+    I = 0;
+    while (isalnum (*P) || *P == '_') {
+       if (I <= MAX_STR_LEN) {
+           SymName [I++] = *P;
+       }
+       ++P;
+    }
+    SymName [I] = '\0';
+
+    /* Do we have a value given? */
+    if (*P != '=') {
+       if (*P != '\0') {
+           InvSym (Def);
+       }
+       Val = 0;
+    } else {
+       /* We have a value */
+       ++P;
+       if (*P == '$') {
+           ++P;
+           if (sscanf (P, "%lx", &Val) != 1) {
+               InvSym (Def);
+           }
+       } else {
+           if (sscanf (P, "%li", &Val) != 1) {
+               InvSym (Def);
+           }
+               }
+    }
+
+    /* Check if have already a symbol with this name */
+    if (SymIsDef (SymName)) {
+       fprintf (stderr, "`%s' is already defined\n", SymName);
+       exit (EXIT_FAILURE);
+    }
+
+    /* Define the symbol */
+    SymDef (SymName, LiteralExpr (Val), 0);
+}
+
+
+
+static void OptCPU (const char* Opt, const char* Arg)
+/* Handle the --cpu option */
+{
+    if (Arg == 0) {
+       NeedArg (Opt);
+    }
+    if (strcmp (Arg, "6502") == 0) {
+       SetCPU (CPU_6502);
+    } else if (strcmp (Arg, "65C02") == 0) {
+       SetCPU (CPU_65C02);
+    } else if (strcmp (Arg, "65816") == 0) {
+       SetCPU (CPU_65816);
+#ifdef SUNPLUS
+    } else if (strcmp (Arg, "sunplus") == 0) {
+       SetCPU (CPU_SUNPLUS);
+#endif
+    } else {
+       fprintf (stderr, "Invalid CPU: `%s'\n", Arg);
+       exit (EXIT_FAILURE);
+    }
+}
+
+
+
+static void OptPageLength (const char* Opt, const char* Arg)
+/* Handle the --pagelength option */
+{
+    int Len;
+    if (Arg == 0) {
+       NeedArg (Opt);
+    }
+    Len = atoi (Arg);
+    if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
+       fprintf (stderr, "Invalid page length: %d\n", Len);
+       exit (EXIT_FAILURE);
+    }
+    PageLength = Len;
+}
+
+
+
+static void OptSmart (const char* Opt)
+/* Handle the -s/--smart options */
+{
+    SmartMode = 1;
+}
+
+
+
+static void LongOption (int* ArgNum, char* argv [])
+/* Handle a long command line option */
+{
+    const char* Opt = argv [*ArgNum];
+    const char* Arg = argv [*ArgNum+1];
+
+    if (strcmp (Opt, "--cpu") == 0) {
+       OptCPU (Opt, Arg);
+       ++(*ArgNum);
+    } else if (strcmp (Opt, "--pagelength") == 0) {
+       OptPageLength (Opt, Arg);
+       ++(*ArgNum);
+    } else if (strcmp (Opt, "--smart") == 0) {
+               OptSmart (Opt);
+    } else {
+        UnknownOption (Opt);
+    }
+}
+
+
+
+static void OneLine (void)
+/* Assemble one line */
+{
+    char Ident [MAX_STR_LEN+1];
+    int Done = 0;
+
+    /* Initialize the listing line */
+    InitListingLine ();
+
+    if (Tok == TOK_COLON) {
+       /* An unnamed label */
+       ULabDef ();
+       NextTok ();
+    }
+
+    /* Assemble the line */
+    if (Tok == TOK_IDENT) {
+
+       /* Is it a macro? */
+       if (IsMacro (SVal)) {
+
+           /* Yes, start a macro expansion */
+           MacExpandStart ();
+           Done = 1;
+
+       } else {
+
+           /* No, label. Remember the identifier, then skip it */
+           int HadWS = WS;     /* Did we have whitespace before the ident? */
+           strcpy (Ident, SVal);
+           NextTok ();
+
+           /* If a colon follows, this is a label definition. If there
+            * is no colon, it's an assignment.
+            */
+                   if (Tok == TOK_EQ) {
+               /* Skip the '=' */
+               NextTok ();
+               /* Define the symbol with the expression following the
+                * '='
+                */
+               SymDef (Ident, Expression (), 0);
+               /* Don't allow anything after a symbol definition */
+               Done = 1;
+           } else {
+               /* Define a label */
+               SymDef (Ident, CurrentPC (), IsZPSeg ());
+               /* Skip the colon. If NoColonLabels is enabled, allow labels
+                * without a colon if there is no whitespace before the
+                * identifier.
+                */
+               if (Tok != TOK_COLON) {
+                   if (HadWS || !NoColonLabels) {
+                       Error (ERR_COLON_EXPECTED);
+                   }
+                   if (Tok == TOK_NAMESPACE) {
+                       /* Smart :: handling */
+                       NextTok ();
+                   }
+               } else {
+                   /* Skip the colon */
+                   NextTok ();
+               }
+           }
+       }
+    }
+
+    if (!Done) {
+
+       if (TokIsPseudo (Tok)) {
+           /* A control command, IVal is index into table */
+           HandlePseudo ();
+       } else if (Tok == TOK_MNEMO) {
+           /* A mnemonic - assemble one instruction */
+           HandleInstruction (IVal);
+       } else if (Tok == TOK_IDENT && IsMacro (SVal)) {
+           /* A macro expansion */
+           MacExpandStart ();
+       }
+    }
+
+    /* Calling InitListingLine again here is part of a hack that introduces
+     * enough magic to make the PC output in the listing work.
+     */
+    InitListingLine ();
+
+    /* Line separator must come here */
+    ConsumeSep ();
+}
+
+
+
+static void Assemble (void)
+/* Start the ball rolling ... */
+{
+    /* Prime the pump */
+    NextTok ();
+
+    /* Assemble lines until end of file */
+    while (Tok != TOK_EOF) {
+       OneLine ();
+    }
+}
+
+
+
+static void CreateObjFile (void)
+/* Create the object file */
+{
+    /* Open the object, write the header */
+    ObjOpen ();
+
+    /* Write the object file options */
+    WriteOptions ();
+
+    /* Write the list of input files */
+    WriteFiles ();
+
+    /* Write the segment data to the file */
+    WriteSegments ();
+
+    /* Write the import list */
+    WriteImports ();
+
+    /* Write the export list */
+    WriteExports ();
+
+    /* Write debug symbols if requested */
+    WriteDbgSyms ();
+
+    /* Write an updated header and close the file */
+    ObjClose ();
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+    int I;
+
+    /* Set the program name */
+    ProgName = argv [0];
+
+    /* We must have a file name */
+    if (argc < 2) {
+       Usage ();
+    }
+
+    /* Enter the base lexical level. We must do that here, since we may
+     * define symbols using -D.
+     */
+    SymEnterLevel ();
+
+    /* Check the parameters */
+    I = 1;
+    while (I < argc) {
+
+               /* Get the argument */
+               const char* Arg = argv [I];
+
+               /* Check for an option */
+               if (Arg [0] == '-') {
+                   switch (Arg [1]) {
+
+               case '-':
+                   LongOption (&I, argv);
+                   break;
+
+                       case 'g':
+                           DbgSyms = 1;
+                           break;
+
+                       case 'i':
+                           IgnoreCase = 1;
+                           break;
+
+                       case 'l':
+                           Listing = 1;
+                           break;
+
+                       case 'o':
+                           OutFile = GetArg (&I, argv, 2);
+                           break;
+
+                       case 's':
+                           OptSmart (Arg);
+                           break;
+
+                       case 'v':
+                           ++Verbose;
+                           break;
+
+               case 'D':
+                   DefineSymbol (GetArg (&I, argv, 2));
+                   break;
+
+                       case 'U':
+                           AutoImport = 1;
+                           break;
+
+                       case 'V':
+                           fprintf (stderr,
+                                    "ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
+                                    VER_MAJOR, VER_MINOR, VER_PATCH);
+                           break;
+
+                       case 'W':
+                           WarnLevel = atoi (GetArg (&I, argv, 2));
+                           break;
+
+                       default:
+                           UnknownOption (Arg);
+                   break;
+
+           }
+               } else {
+           /* Filename. Check if we already had one */
+           if (InFile) {
+               fprintf (stderr, "Don't know what to do with `%s'\n", Arg);
+               Usage ();
+           } else {
+               InFile = Arg;
+           }
+       }
+
+       /* Next argument */
+       ++I;
+    }
+
+    /* Do we have an input file? */
+    if (InFile == 0) {
+       fprintf (stderr, "No input file\n");
+       exit (EXIT_FAILURE);
+    }
+
+    /* Initialize the scanner, open the input file */
+    InitScanner (InFile);
+
+    /* Define the default options */
+    SetOptions ();
+
+    /* Assemble the input */
+    Assemble ();
+
+    /* If we didn't have any errors, check the unnamed labels */
+    if (ErrorCount == 0) {
+        ULabCheck ();                                          
+    }
+
+    /* If we didn't have any errors, check the symbol table */
+    if (ErrorCount == 0) {
+        SymCheck ();
+    }
+
+    /* If we didn't have any errors, check and resolve the segment data */
+    if (ErrorCount == 0) {
+        SegCheck ();
+    }
+
+    /* Dump the data */
+    if (Verbose >= 2) {
+        SymDump (stdout);
+        SegDump ();
+    }
+
+    /* If we didn't have any errors, create the object and listing files */
+    if (ErrorCount == 0) {
+       CreateObjFile ();
+       if (Listing) {
+           CreateListing ();
+       }
+    }
+
+    /* Close the input file */
+    DoneScanner ();
+
+    /* Return an apropriate exit code */
+    return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+
+
diff --git a/src/ca65/make/gcc.mak b/src/ca65/make/gcc.mak
new file mode 100644 (file)
index 0000000..8d5c694
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# gcc Makefile for a65, link65 & libr65
+#
+
+CFLAGS         = -g -O2 -Wall
+CC     = gcc
+LDFLAGS        =
+
+OBJS =  condasm.o      \
+       ea.o            \
+        error.o                \
+        expr.o         \
+       fname.o         \
+       fragment.o      \
+        global.o               \
+        instr.o                \
+       listing.o       \
+       macpack.o       \
+               macro.o         \
+        main.o         \
+        mem.o          \
+        objcode.o      \
+        objfile.o      \
+               options.o       \
+        pseudo.o       \
+        scanner.o      \
+       strexpr.o       \
+        symtab.o       \
+               toknode.o       \
+       ulabel.o
+
+LIBS = ../common/common.a
+
+EXECS = ca65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ca65:   $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+       rm -f *~ core *.lst
+
+zap:   clean
+       rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
diff --git a/src/ca65/make/watcom.mak b/src/ca65/make/watcom.mak
new file mode 100644 (file)
index 0000000..7ba0b5e
--- /dev/null
@@ -0,0 +1,140 @@
+#
+# CA65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS =         condasm.obj     \
+       ea.obj          \
+       error.obj       \
+       expr.obj        \
+       fname.obj       \
+       fragment.obj    \
+       global.obj      \
+               instr.obj       \
+       listing.obj     \
+       macpack.obj     \
+       macro.obj       \
+       main.obj        \
+       mem.obj         \
+       objcode.obj     \
+       objfile.obj     \
+       options.obj     \
+       pseudo.obj      \
+       scanner.obj     \
+       strexpr.obj     \
+       symtab.obj      \
+       toknode.obj     \
+       ulabel.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:           ca65
+
+ca65:          ca65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ca65.exe:      $(OBJS) $(LIBS)
+       $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE condasm.obj
+FILE ea.obj
+FILE error.obj
+FILE expr.obj
+FILE fname.obj
+FILE fragment.obj
+FILE global.obj
+FILE instr.obj
+FILE listing.obj
+FILE macpack.obj
+FILE macro.obj
+FILE main.obj
+FILE mem.obj
+FILE objcode.obj
+FILE objfile.obj
+FILE options.obj
+FILE pseudo.obj
+FILE scanner.obj
+FILE strexpr.obj
+FILE symtab.obj
+FILE toknode.obj
+FILE ulabel.obj
+LIBRARY ..\common\common.lib
+|
+
+clean:
+       @if exist *.obj del *.obj
+       @if exist ca65.exe del ca65.exe
+
+strip:
+       @-wstrip ca65.exe
+
diff --git a/src/ca65/mem.c b/src/ca65/mem.c
new file mode 100644 (file)
index 0000000..7f10aa8
--- /dev/null
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                  mem.c                                   */
+/*                                                                          */
+/*              Memory allocation for the ca65 macroassembler               */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+    void* p;
+
+    p = malloc (size);
+    if (p == 0 && size != 0) {
+       Fatal (FAT_OUT_OF_MEMORY);
+    }
+
+    /* Return a pointer to the block */
+    return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+    free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+    unsigned len;
+
+    len = strlen (s) + 1;
+    return memcpy (Xmalloc (len), s, len);
+}
+
+
+
diff --git a/src/ca65/mem.h b/src/ca65/mem.h
new file mode 100644 (file)
index 0000000..4a6871c
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.h                                   */
+/*                                                                           */
+/*              Memory allocation for the ca65 macroassembler               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
diff --git a/src/ca65/objcode.c b/src/ca65/objcode.c
new file mode 100644 (file)
index 0000000..029e01e
--- /dev/null
@@ -0,0 +1,842 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objcode.c                                 */
+/*                                                                           */
+/*            Objectcode management for the ca65 macroassembler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "../common/segdefs.h"
+
+#include "error.h"
+#include "fragment.h"
+#include "global.h"
+#include "listing.h"
+#include "mem.h"
+#include "objfile.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "objcode.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Are we in absolute mode or in relocatable mode? */
+int            RelocMode = 1;
+unsigned long  AbsPC     = 0;          /* PC if in absolute mode */
+
+
+
+typedef struct Segment_ Segment;
+struct Segment_ {
+    Segment*               List;               /* List of all segments */
+    Fragment*              Root;               /* Root of fragment list */
+    Fragment*              Last;               /* Pointer to last fragment */
+    unsigned char   Align;             /* Segment alignment */
+    unsigned char   SegType;                   /* True if zero page segment */
+    unsigned long   PC;
+    unsigned               Num;                /* Segment number */
+    char*                  Name;               /* Segment name */
+};
+
+
+
+/* Predefined segments */
+static Segment NullSeg = {
+    0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
+};
+static Segment ZeropageSeg = {
+    &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
+};
+static Segment DataSeg = {
+    &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
+};
+static Segment BssSeg = {
+    &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
+};
+static Segment RODataSeg = {
+    &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
+};
+static Segment CodeSeg = {
+    &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
+};
+
+/* Number of segments */
+static unsigned SegmentCount = 6;
+
+/* List of all segments */
+static Segment* SegmentList = &CodeSeg;
+static Segment* SegmentLast = &NullSeg;
+
+/* Currently active segment */
+static Segment*        ActiveSeg = &CodeSeg;
+
+
+
+/*****************************************************************************/
+/*                                   Segment management                             */
+/*****************************************************************************/
+
+
+
+static Segment* NewSegment (const char* Name, unsigned SegType)
+/* Create a new segment, insert it into the global list and return it */
+{
+    Segment* S;
+    const char* N;
+
+    /* Check for too many segments */
+    if (SegmentCount >= 256) {
+       Fatal (FAT_TOO_MANY_SEGMENTS);
+    }
+
+    /* Check the segment name for invalid names */
+    N = Name;
+    if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
+       Error (ERR_ILLEGAL_SEGMENT, Name);
+    }
+    do {
+       if (*N != '_' && !isalnum (*N)) {
+           Error (ERR_ILLEGAL_SEGMENT, Name);
+           break;
+       }
+       ++N;
+    } while (*N);
+
+    /* Create a new segment */
+    S = Xmalloc (sizeof (*S));
+
+    /* Initialize it */
+    S->List    = 0;
+    S->Root    = 0;
+    S->Last    = 0;
+    S->Align   = 0;
+    S->SegType = SegType;
+    S->PC      = 0;
+    S->Num     = SegmentCount++;
+    S->Name    = StrDup (Name);
+
+    /* Insert it into the segment list */
+    SegmentLast->List = S;
+    SegmentLast = S;
+
+    /* And return it... */
+    return S;
+}
+
+
+
+void UseCodeSeg (void)
+/* Use the code segment */
+{
+    ActiveSeg = &CodeSeg;
+}
+
+
+
+void UseRODataSeg (void)
+/* Use the r/o data segment */
+{
+    ActiveSeg = &RODataSeg;
+}
+
+
+
+void UseDataSeg (void)
+/* Use the data segment */
+{
+    ActiveSeg = &DataSeg;
+}
+
+
+
+void UseBssSeg (void)
+/* Use the BSS segment */
+{
+    ActiveSeg = &BssSeg;
+}
+
+
+
+void UseZeropageSeg (void)
+/* Use the zero page segment */
+{
+    ActiveSeg = &ZeropageSeg;
+}
+
+
+
+void UseNullSeg (void)
+/* Use the null segment */
+{
+    ActiveSeg = &NullSeg;
+}
+
+
+
+void UseSeg (const char* Name, unsigned SegType)
+/* Use the segment with the given name */
+{
+    Segment* Seg = SegmentList;
+    while (Seg) {
+       if (strcmp (Seg->Name, Name) == 0) {
+           /* We found this segment. Check if the type is identical */
+           if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
+               Error (ERR_SEG_ATTR_MISMATCH);
+               /* Use the new attribute to avoid errors */
+               Seg->SegType = SegType;
+                   }
+                   ActiveSeg = Seg;
+           return;
+       }
+       /* Check next segment */
+       Seg = Seg->List;
+    }
+
+    /* Segment is not in list, create a new one */
+    if (SegType == SEGTYPE_DEFAULT) {
+       SegType = SEGTYPE_ABS;
+    }
+    Seg = NewSegment (Name, SegType);
+    ActiveSeg = Seg;
+}
+
+
+
+unsigned long GetPC (void)
+/* Get the program counter of the current segment */
+{
+    return RelocMode? ActiveSeg->PC : AbsPC;
+}
+
+
+
+void SetAbsPC (unsigned long PC)
+/* Set the program counter in absolute mode */
+{
+    RelocMode = 0;
+    AbsPC = PC;
+}
+
+
+
+unsigned GetSegNum (void)
+/* Get the number of the current segment */
+{
+    return ActiveSeg->Num;
+}
+
+
+
+void SegAlign (unsigned Power, int Val)
+/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
+ * actual fill value will be determined by the linker), otherwise use the
+ * given value.
+ */
+{
+    unsigned char Data [4];
+    unsigned long Align = (1UL << Power) - 1;
+    unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
+    unsigned long Count = NewPC - ActiveSeg->PC;
+
+    if (Val != -1) {
+       /* User defined fill value */
+       memset (Data, Val, sizeof (Data));
+       while (Count) {
+           if (Count > sizeof (Data)) {
+               EmitData (Data, sizeof (Data));
+               Count -= sizeof (Data);
+           } else {
+               EmitData (Data, Count);
+               Count = 0;
+           }
+       }
+    } else {
+       /* Linker defined fill value */
+       EmitFill (Count);
+    }
+
+    /* Remember the alignment in the header */
+    if (ActiveSeg->Align < Power) {
+       ActiveSeg->Align = Power;
+    }
+}
+
+
+
+int IsZPSeg (void)
+/* Return true if the current segment is a zeropage segment */
+{
+    return (ActiveSeg->SegType == SEGTYPE_ZP);
+}
+
+
+
+int IsFarSeg (void)
+/* Return true if the current segment is a far segment */
+{
+    return (ActiveSeg->SegType == SEGTYPE_FAR);
+}
+
+
+
+unsigned GetSegType (unsigned SegNum)
+/* Return the type of the segment with the given number */
+{
+    /* Search for the segment */
+    Segment* S = SegmentList;
+    while (S && SegNum) {
+       --SegNum;
+       S = S->List;
+    }
+
+    /* Did we find it? */
+    if (S == 0) {
+       FAIL ("Invalid segment number");
+    }
+
+    /* Return the segment type */
+    return S->SegType;
+}
+
+
+
+void SegCheck (void)
+/* Check the segments for range and other errors */
+{
+    Segment* S = SegmentList;
+    while (S) {
+       Fragment* F = S->Root;
+       while (F) {
+                   if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+                       F->V.Expr = FinalizeExpr (F->V.Expr);
+                       if (IsConstExpr (F->V.Expr)) {
+                   /* We are able to evaluate the expression. Get the value
+                    * and check for range errors.
+                    */
+                   unsigned I;
+                   long Val = GetExprVal (F->V.Expr);
+                   int Abs = (F->Type != FRAG_SEXPR);
+
+                   if (F->Len == 1) {
+                       if (Abs) {
+                           /* Absolute value */
+                           if (Val > 255) {
+                               PError (&F->Pos, ERR_RANGE);
+                           }
+                       } else {
+                           /* PC relative value */
+                           if (Val < -128 || Val > 127) {
+                               PError (&F->Pos, ERR_RANGE);
+                           }
+                       }
+                   } else if (F->Len == 2) {
+                       if (Abs) {
+                           /* Absolute value */
+                           if (Val > 65535) {
+                               PError (&F->Pos, ERR_RANGE);
+                           }
+                       } else {
+                           /* PC relative value */
+                           if (Val < -32768 || Val > 32767) {
+                               PError (&F->Pos, ERR_RANGE);
+                           }
+                       }
+                   }
+
+                   /* Convert the fragment into a literal fragment */
+                   for (I = 0; I < F->Len; ++I) {
+                       F->V.Data [I] = Val & 0xFF;
+                       Val >>= 8;
+                   }
+                   F->Type = FRAG_LITERAL;
+               } else {
+                   /* We cannot evaluate the expression now, leave the job for
+                    * the linker. However, we are able to check for explicit
+                    * byte expressions and we will do so.
+                    */
+                   if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
+                       PError (&F->Pos, ERR_RANGE);
+                   }
+               }
+           }
+           F = F->Next;
+       }
+       S = S->List;
+    }
+}
+
+
+
+void SegDump (void)
+/* Dump the contents of all segments */
+{
+    unsigned X = 0;
+    Segment* S = SegmentList;
+    printf ("\n");
+    while (S) {
+       unsigned I;
+       Fragment* F;
+       int State = -1;
+               printf ("New segment: %s", S->Name);
+       F = S->Root;
+       while (F) {
+           if (F->Type == FRAG_LITERAL) {
+               if (State != 0) {
+                   printf ("\n  Literal:");
+                   X = 15;
+                   State = 0;
+               }
+               for (I = 0; I < F->Len; ++I) {
+                   printf (" %02X", F->V.Data [I]);
+                   X += 3;
+               }
+           } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+                       State = 1;
+               printf ("\n  Expression (%u): ", F->Len);
+               DumpExpr (F->V.Expr);
+           } else if (F->Type == FRAG_FILL) {
+               State = 1;
+               printf ("\n  Fill bytes (%u)", F->Len);
+           } else {
+               Internal ("Unknown fragment type: %u", F->Type);
+           }
+                   if (X > 65) {
+               State = -1;
+           }
+           F = F->Next;
+       }
+       printf ("\n  End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
+       S = S->List;
+    }
+    printf ("\n");
+}
+
+
+
+static void WriteOneSeg (Segment* Seg)
+/* Write one segment to the object file */
+{
+    Fragment* Frag;
+    Fragment* F;
+    unsigned long Size;
+
+    /* Write the segment name followed by the byte count in this segment */
+    ObjWriteStr (Seg->Name);
+    ObjWrite32 (Seg->PC);
+    ObjWrite8 (Seg->Align);
+    ObjWrite8 (Seg->SegType);
+
+    /* Now walk through the fragment list for this segment and write the
+     * fragments.
+     */
+    Frag = Seg->Root;
+    while (Frag) {
+
+       /* Write data depending on the type */
+               switch (Frag->Type) {
+
+           case FRAG_LITERAL:
+               /* To make the object file somewhat smaller, write all literal
+                * data of this and the following fragments preceeded by the
+                * length.
+                */
+               F = Frag;
+               Size = 0;
+               while (F && F->Type == FRAG_LITERAL) {
+                   Size += F->Len;
+                   F = F->Next;
+               }
+               if (Size < 0x100) {
+                   ObjWrite8 (FRAG_LITERAL8);
+                   ObjWrite8 (Size);
+               } else if (Size < 0x10000) {
+                   ObjWrite8 (FRAG_LITERAL16);
+                   ObjWrite16 (Size);
+               } else if (Size < 0x1000000) {
+                   ObjWrite8 (FRAG_LITERAL24);
+                   ObjWrite24 (Size);
+               } else {
+                   ObjWrite8 (FRAG_LITERAL32);
+                   ObjWrite32 (Size);
+               }
+
+               /* Now write the literal data */
+               F = Frag;
+               while (F && F->Type == FRAG_LITERAL) {
+                   ObjWriteData (F->V.Data, F->Len);
+                   Frag = F;
+                   F = F->Next;
+               }
+               break;
+
+           case FRAG_EXPR:
+               switch (Frag->Len) {
+                   case 1:   ObjWrite8 (FRAG_EXPR8);   break;
+                   case 2:   ObjWrite8 (FRAG_EXPR16);  break;
+                   case 3:   ObjWrite8 (FRAG_EXPR24);  break;
+                   case 4:   ObjWrite8 (FRAG_EXPR32);  break;
+                   default:  Internal ("Invalid fragment size: %u", Frag->Len);
+               }
+               WriteExpr (Frag->V.Expr);
+               break;
+
+           case FRAG_SEXPR:
+               switch (Frag->Len) {
+                   case 1:   ObjWrite8 (FRAG_SEXPR8);  break;
+                   case 2:   ObjWrite8 (FRAG_SEXPR16); break;
+                   case 3:   ObjWrite8 (FRAG_SEXPR24); break;
+                   case 4:   ObjWrite8 (FRAG_SEXPR32); break;
+                   default:  Internal ("Invalid fragment size: %u", Frag->Len);
+               }
+               WriteExpr (Frag->V.Expr);
+               break;
+
+           case FRAG_FILL:
+               ObjWrite8 (FRAG_FILL);
+               ObjWrite16 (Frag->Len);
+               break;
+
+           default:
+               Internal ("Invalid fragment type: %u", Frag->Type);
+
+       }
+
+               /* Write the file position of this fragment */
+       ObjWritePos (&Frag->Pos);
+
+       /* Next fragment */
+       Frag = Frag->Next;
+    }
+}
+
+
+
+void WriteSegments (void)
+/* Write the segment data to the object file */
+{
+    Segment* Seg;
+
+    /* Tell the object file module that we're about to start the seg list */
+    ObjStartSegments ();
+
+    /* First thing is segment count */
+    ObjWrite8 (SegmentCount);
+
+    /* Now walk through all segments and write them to the object file */
+    Seg = SegmentList;
+    while (Seg) {
+       /* Write one segment */
+       WriteOneSeg (Seg);
+       /* Next segment */
+       Seg = Seg->List;
+    }
+
+    /* Done writing segments */
+    ObjEndSegments ();
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static void IncPC (unsigned Value)
+/* Increment the PC counter */
+{
+    ActiveSeg->PC += Value;
+    if (!RelocMode) {
+       AbsPC += Value;
+    }
+}
+
+
+
+static Fragment* NewFragment (unsigned char Type, unsigned short Len)
+/* Create, initialize and return a new fragment. The fragment will be inserted
+ * into the current segment.
+ */
+{
+    Fragment* F;
+
+    /* Create a new fragment */
+    F = Xmalloc (sizeof (*F));
+
+    /* Initialize it */
+    F->List    = 0;
+    F->Next    = 0;
+    F->LineList = 0;
+    F->Pos     = CurPos;
+    F->Len     = Len;
+    F->Type    = Type;
+
+    /* Insert it into the list of all segments */
+    if (FragList == 0) {
+       FragList = F;
+    } else {
+       FragLast->List = F;
+    }
+    FragLast = F;
+
+    /* Insert it into the current segment */
+    if (ActiveSeg->Root) {
+       ActiveSeg->Last->Next = F;
+       ActiveSeg->Last = F;
+    } else {
+       ActiveSeg->Root = ActiveSeg->Last = F;
+    }
+
+    /* Add this fragment to the current listing line */
+    if (LineCur) {
+       if (LineCur->FragList == 0) {
+           LineCur->FragList = F;
+           /* First fragment - set the PC
+           LineCur->PC    = GetPC ();
+           LineCur->Reloc = RelocMode;    
+*/
+       } else {
+                   LineCur->FragLast->LineList = F;
+       }
+       LineCur->FragLast = F;
+    }
+
+    /* Increment the program counter */
+    IncPC (Len);
+
+    /* And return it */
+    return F;
+}
+
+
+
+void Emit0 (unsigned char OPC)
+/* Emit an instruction with a zero sized operand */
+{
+    /* First fragment, wrong type or out of space, create new one */
+    Fragment* F = NewFragment (FRAG_LITERAL, 1);
+    F->V.Data [0] = OPC;
+}
+
+
+
+void Emit1 (unsigned char OPC, ExprNode* Value)
+/* Emit an instruction with an one byte argument */
+{
+    Emit0 (OPC);
+    EmitByte (Value);
+}
+
+
+
+void Emit2 (unsigned char OPC, ExprNode* Value)
+/* Emit an instruction with a two byte argument */
+{
+    Emit0 (OPC);
+    EmitWord (Value);
+}
+
+
+
+void Emit3 (unsigned char OPC, ExprNode* Expr)
+/* Emit an instruction with a three byte argument */
+{
+    Emit0 (OPC);
+    EmitFarAddr (Expr);
+}
+
+
+
+void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
+/* Emit an instruction with a three byte argument and separate bank */
+{
+    Emit0 (OPC);
+    EmitWord (Expr);
+    EmitByte (Bank);
+}
+
+
+
+void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
+/* Emit an opcode with a PC relative argument of one or two bytes */
+{
+    Fragment* F;
+    Emit0 (OPC);
+    F = NewFragment (FRAG_SEXPR, Size);
+    F->V.Expr = Expr;
+}
+
+
+
+void EmitData (const unsigned char* Data, unsigned Size)
+/* Emit data into the current segment */
+{
+    /* Create lots of fragments for the data */
+    while (Size) {
+       Fragment* F;
+
+       /* Determine the length of the next fragment */
+       unsigned Len = Size;
+               if (Len > sizeof (F->V.Data)) {
+           Len = sizeof (F->V.Data);
+               }
+
+       /* Create a new fragment */
+       F = NewFragment (FRAG_LITERAL, Len);
+
+       /* Copy the data */
+       memcpy (F->V.Data, Data, Len);
+
+       /* Next chunk */
+       Data += Len;
+       Size -= Len;
+
+    }
+}
+
+
+
+void EmitByte (ExprNode* Expr)
+/* Emit one byte */
+{
+    if (IsConstExpr (Expr)) {
+       /* Constant expression, emit literal byte */
+       long Val = GetExprVal (Expr);
+       FreeExpr (Expr);
+       if ((Val & ~0xFF) != 0) {
+           Error (ERR_RANGE);
+       }
+       Emit0 (Val & 0xFF);
+    } else {
+       /* Create a new fragment */
+       Fragment* F = NewFragment (FRAG_EXPR, 1);
+
+       /* Set the data */
+       F->V.Expr = Expr;
+    }
+}
+
+
+
+void EmitWord (ExprNode* Expr)
+/* Emit one word */
+{
+    if (IsConstExpr (Expr)) {
+       /* Constant expression, emit literal byte */
+       long Val = GetExprVal (Expr);
+       FreeExpr (Expr);
+               if ((Val & ~0xFFFF) != 0) {
+           Error (ERR_RANGE);
+       }
+       Emit0 (Val & 0xFF);
+       Emit0 ((Val >> 8) & 0xFF);
+    } else {
+       /* Create a new fragment */
+       Fragment* F = NewFragment (FRAG_EXPR, 2);
+
+       /* Set the data */
+       F->V.Expr = Expr;
+    }
+}
+
+
+
+void EmitFarAddr (ExprNode* Expr)
+/* Emit a 24 bit expression */
+{
+    if (IsConstExpr (Expr)) {
+       /* Constant expression, emit literal byte */
+       long Val = GetExprVal (Expr);
+       FreeExpr (Expr);
+               if ((Val & ~0xFFFFFF) != 0) {
+           Error (ERR_RANGE);
+       }
+       Emit0 (Val & 0xFF);
+       Emit0 ((Val >> 8) & 0xFF);
+       Emit0 ((Val >> 16) & 0xFF);
+    } else {
+       /* Create a new fragment */
+       Fragment* F = NewFragment (FRAG_EXPR, 3);
+
+       /* Set the data */
+       F->V.Expr = Expr;
+    }
+}
+
+
+
+void EmitDWord (ExprNode* Expr)
+/* Emit one dword */
+{
+    if (IsConstExpr (Expr)) {
+       /* Constant expression, emit literal byte */
+       long Val = GetExprVal (Expr);
+       FreeExpr (Expr);
+       Emit0 (Val & 0xFF);
+       Emit0 ((Val >> 8) & 0xFF);
+               Emit0 ((Val >> 16) & 0xFF);
+       Emit0 ((Val >> 24) & 0xFF);
+    } else {
+       /* Create a new fragment */
+       Fragment* F = NewFragment (FRAG_EXPR, 4);
+
+       /* Set the data */
+       F->V.Expr = Expr;
+    }
+}
+
+
+
+void EmitFill (unsigned long Count)
+/* Emit Count fill bytes */
+{
+    while (Count) {
+       /* Calculate the size of the next chunk */
+       unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
+       Count -= Chunk;
+
+       /* Emit one chunk */
+       NewFragment (FRAG_FILL, Chunk);
+    }
+}
+
+
+
diff --git a/src/ca65/objcode.h b/src/ca65/objcode.h
new file mode 100644 (file)
index 0000000..b4b0d48
--- /dev/null
@@ -0,0 +1,168 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objcode.h                                 */
+/*                                                                           */
+/*            Objectcode management for the ca65 macroassembler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJCODE_H
+#define OBJCODE_H
+
+
+
+#include "../common/segdefs.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Are we in absolute mode or in relocatable mode? */
+extern int     RelocMode;
+
+
+
+/*****************************************************************************/
+/*                           Segment management                             */
+/*****************************************************************************/
+
+
+
+void UseCodeSeg (void);
+/* Use the code segment */
+
+void UseRODataSeg (void);
+/* Use the r/o data segment */
+
+void UseDataSeg (void);
+/* Use the data segment */
+
+void UseBssSeg (void);
+/* Use the BSS segment */
+
+void UseZeropageSeg (void);
+/* Use the zero page segment */
+
+void UseNullSeg (void);
+/* Use the null segment */
+
+void UseSeg (const char* Name, unsigned SegType);
+/* Use the segment with the given name */
+
+unsigned GetSegNum (void);
+/* Get the number of the current segment */
+
+void SegAlign (unsigned Power, int Val);
+/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
+ * actual fill value will be determined by the linker), otherwise use the
+ * given value.
+ */
+
+int IsZPSeg (void);
+/* Return true if the current segment is a zeropage segment */
+
+int IsFarSeg (void);
+/* Return true if the current segment is a far segment */
+
+unsigned GetSegType (unsigned SegNum);
+/* Return the type of the segment with the given number */
+
+unsigned long GetPC (void);
+/* Get the program counter of the current segment */
+
+void SetAbsPC (unsigned long AbsPC);
+/* Set the program counter in absolute mode */
+
+void SegCheck (void);
+/* Check the segments for range and other errors */
+
+void SegDump (void);
+/* Dump the contents of all segments */
+
+void WriteSegments (void);
+/* Write the segment data to the object file */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Emit0 (unsigned char OPC);
+/* Emit an instruction with a zero sized operand */
+
+void Emit1 (unsigned char OPC, ExprNode* Value);
+/* Emit an instruction with an one byte argument */
+
+void Emit2 (unsigned char OPC, ExprNode* Value);
+/* Emit an instruction with a two byte argument */
+
+void Emit3 (unsigned char OPC, ExprNode* Expr);
+/* Emit an instruction with a three byte argument */
+
+void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank);
+/* Emit an instruction with a three byte argument and separate bank */
+
+void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size);
+/* Emit an opcode with a PC relative argument of one or two bytes */
+
+void EmitData (const unsigned char* Data, unsigned Size);
+/* Emit data into the current segment */
+
+void EmitByte (ExprNode* Expr);
+/* Emit one byte */
+
+void EmitWord (ExprNode* Expr);
+/* Emit one word */
+
+void EmitFarAddr (ExprNode* Expr);
+/* Emit a 24 bit expression */
+
+void EmitDWord (ExprNode* Expr);
+/* Emit one dword */
+
+void EmitFill (unsigned long Count);
+/* Emit Count fill bytes */
+
+
+
+/* End of objcode.h */
+
+#endif
+               
+
+
diff --git a/src/ca65/objfile.c b/src/ca65/objfile.c
new file mode 100644 (file)
index 0000000..b3218fe
--- /dev/null
@@ -0,0 +1,351 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objfile.c                                 */
+/*                                                                           */
+/*        Object file writing routines for the ca65 macroassembler          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/objdefs.h"
+
+#include "global.h"
+#include "error.h"
+#include "fname.h"
+#include "mem.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* File descriptor */
+static FILE* F = 0;
+
+/* Default extension */
+#define        OBJ_EXT ".o"
+
+/* Header structure */
+static ObjHeader Header = {
+    OBJ_MAGIC,
+    OBJ_VERSION
+};
+
+
+
+/*****************************************************************************/
+/*                        Internally used functions                         */
+/*****************************************************************************/
+
+
+
+static void ObjWriteError (void)
+/* Called on a write error. Will try to close and remove the file, then
+ * print a fatal error.
+ */
+{
+    /* Remember the error */
+    int Error = errno;
+
+    /* Force a close of the file, ignoring errors */
+    fclose (F);
+
+    /* Try to remove the file, also ignoring errors */
+    remove (OutFile);
+
+    /* Now abort with a fatal error */
+    Fatal (FAT_CANNOT_WRITE_OUTPUT, OutFile, strerror (Error));
+}
+
+
+
+static void ObjWriteHeader (void)
+/* Write the object file header to the current file position */
+{
+    ObjWrite32 (Header.Magic);
+    ObjWrite16 (Header.Version);
+    ObjWrite16 (Header.Flags);
+    ObjWrite32 (Header.OptionOffs);
+    ObjWrite32 (Header.OptionSize);
+    ObjWrite32 (Header.FileOffs);
+    ObjWrite32 (Header.FileSize);
+    ObjWrite32 (Header.SegOffs);
+    ObjWrite32 (Header.SegSize);
+    ObjWrite32 (Header.ImportOffs);
+    ObjWrite32 (Header.ImportSize);
+    ObjWrite32 (Header.ExportOffs);
+    ObjWrite32 (Header.ExportSize);
+    ObjWrite32 (Header.DbgSymOffs);
+    ObjWrite32 (Header.DbgSymSize);
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ObjOpen (void)
+/* Open the object file for writing, write a dummy header */
+{
+    /* Do we have a name for the output file? */
+    if (OutFile == 0) {
+       /* We don't have an output name explicitly given, construct one from
+        * the name of the input file.
+        */
+       OutFile = MakeFilename (InFile, OBJ_EXT);
+    }
+
+    /* Create the output file */
+    F = fopen (OutFile, "w+b");
+    if (F == 0) {
+       Fatal (FAT_CANNOT_OPEN_OUTPUT, OutFile, strerror (errno));
+    }
+
+    /* Write a dummy header */
+    ObjWriteHeader ();
+}
+
+
+
+void ObjClose (void)
+/* Write an update header and close the object file. */
+{
+    /* Go back to the beginning */
+    if (fseek (F, 0, SEEK_SET) != 0) {
+       ObjWriteError ();
+    }
+
+    /* If we have debug infos, set the flag in the header */
+    if (DbgSyms) {
+        Header.Flags |= OBJ_FLAGS_DBGINFO;
+    }
+
+    /* Write the updated header */
+    ObjWriteHeader ();
+
+    /* Close the file */
+    if (fclose (F) != 0) {
+       ObjWriteError ();
+    }
+}
+
+
+
+void ObjWrite8 (unsigned char V)
+/* Write an 8 bit value to the file */
+{
+    if (putc (V, F) == EOF) {
+       ObjWriteError ();
+    }
+}
+
+
+
+void ObjWrite16 (unsigned V)
+/* Write a 16 bit value to the file */
+{
+    ObjWrite8 (V);
+    ObjWrite8 (V >> 8);
+}
+
+
+
+void ObjWrite24 (unsigned long V)
+/* Write a 24 bit value to the file */
+{
+    ObjWrite8 (V);
+    ObjWrite8 (V >> 8);
+    ObjWrite8 (V >> 16);
+}
+
+
+
+void ObjWrite32 (unsigned long V)
+/* Write a 32 bit value to the file */
+{
+    ObjWrite8 (V);
+    ObjWrite8 (V >> 8);
+    ObjWrite8 (V >> 16);
+    ObjWrite8 (V >> 24);
+}
+
+
+
+void ObjWriteStr (const char* S)
+/* Write a string to the object file */
+{
+    unsigned Len = strlen (S);
+    if (Len > 255) {
+       Internal ("String too long in ObjWriteStr");
+    }
+
+    /* Write the string with a length byte preceeded (this is easier for
+     * the reading routine than the C format since the length is known in
+     * advance).
+     */
+    ObjWrite8 ((unsigned char) Len);
+    ObjWriteData (S, Len);
+}
+
+
+
+void ObjWriteData (const void* Data, unsigned Size)
+/* Write literal data to the file */
+{
+    if (fwrite (Data, 1, Size, F) != Size) {
+       ObjWriteError ();
+    }
+}
+
+
+
+void ObjWritePos (const FilePos* Pos)
+/* Write a file position to the object file */
+{
+    /* Write the line number as 24 bit value to save one byte */
+    ObjWrite24 (Pos->Line);
+    ObjWrite8  (Pos->Col);
+    if (Pos->Name == 0) {
+       /* Position is outside file scope, use the main file instead */
+       ObjWrite8 (0);
+    } else {
+        ObjWrite8  (Pos->Name - 1);
+    }
+}
+
+
+
+void ObjStartOptions (void)
+/* Mark the start of the option section */
+{
+    Header.OptionOffs = ftell (F);
+}
+
+
+
+void ObjEndOptions (void)
+/* Mark the end of the option section */
+{
+    Header.OptionSize = ftell (F) - Header.OptionOffs;
+}
+
+
+
+void ObjStartFiles (void)
+/* Mark the start of the files section */
+{
+    Header.FileOffs = ftell (F);
+}
+
+
+
+void ObjEndFiles (void)
+/* Mark the end of the files section */
+{
+    Header.FileSize = ftell (F) - Header.FileOffs;
+}
+
+
+
+void ObjStartSegments (void)
+/* Mark the start of the segment section */
+{
+    Header.SegOffs = ftell (F);
+}
+
+
+
+void ObjEndSegments (void)
+/* Mark the end of the segment section */
+{
+    Header.SegSize = ftell (F) - Header.SegOffs;
+}
+
+
+
+void ObjStartImports (void)
+/* Mark the start of the import section */
+{
+    Header.ImportOffs = ftell (F);
+}
+
+
+
+void ObjEndImports (void)
+/* Mark the end of the import section */
+{
+    Header.ImportSize = ftell (F) - Header.ImportOffs;
+}
+
+
+
+void ObjStartExports (void)
+/* Mark the start of the export section */
+{
+    Header.ExportOffs = ftell (F);
+}
+
+
+
+void ObjEndExports (void)
+/* Mark the end of the export section */
+{
+    Header.ExportSize = ftell (F) - Header.ExportOffs;
+}
+
+
+
+void ObjStartDbgSyms (void)
+/* Mark the start of the debug symbol section */
+{
+    Header.DbgSymOffs = ftell (F);
+}
+
+
+
+void ObjEndDbgSyms (void)
+/* Mark the end of the debug symbol section */
+{
+    Header.DbgSymSize = ftell (F) - Header.DbgSymOffs;
+}
+
+
+
diff --git a/src/ca65/objfile.h b/src/ca65/objfile.h
new file mode 100644 (file)
index 0000000..27c19fd
--- /dev/null
@@ -0,0 +1,121 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objfile.h                                 */
+/*                                                                           */
+/*        Object file writing routines for the ca65 macroassembler          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ObjOpen (void);
+/* Open the object file for writing, write a dummy header */
+
+void ObjClose (void);
+/* Write an update header and close the object file. */
+
+void ObjWrite8 (unsigned char V);
+/* Write an 8 bit value to the file */
+
+void ObjWrite16 (unsigned V);
+/* Write a 16 bit value to the file */
+
+void ObjWrite24 (unsigned long V);
+/* Write a 24 bit value to the file */
+
+void ObjWrite32 (unsigned long V);
+/* Write a 32 bit value to the file */
+
+void ObjWriteStr (const char* S);
+/* Write a string to the object file */
+
+void ObjWriteData (const void* Data, unsigned Size);
+/* Write literal data to the file */
+
+void ObjWritePos (const FilePos* Pos);
+/* Write a file position to the object file */
+
+void ObjStartOptions (void);
+/* Mark the start of the option section */
+
+void ObjEndOptions (void);
+/* Mark the end of the option section */
+
+void ObjStartFiles (void);
+/* Mark the start of the files section */
+
+void ObjEndFiles (void);
+/* Mark the end of the files section */
+
+void ObjStartSegments (void);
+/* Mark the start of the segment section */
+
+void ObjEndSegments (void);
+/* Mark the end of the segment section */
+
+void ObjStartImports (void);
+/* Mark the start of the import section */
+
+void ObjEndImports (void);
+/* Mark the end of the import section */
+
+void ObjStartExports (void);
+/* Mark the start of the export section */
+
+void ObjEndExports (void);
+/* Mark the end of the export section */
+
+void ObjStartDbgSyms (void);
+/* Mark the start of the debug symbol section */
+
+void ObjEndDbgSyms (void);
+/* Mark the end of the debug symbol section */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
diff --git a/src/ca65/options.c b/src/ca65/options.c
new file mode 100644 (file)
index 0000000..ca05f0b
--- /dev/null
@@ -0,0 +1,202 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                options.c                                 */
+/*                                                                           */
+/*             Object file options for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "../common/optdefs.h"
+
+#include "mem.h"
+#include "error.h"
+#include "objfile.h"
+#include "options.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Option list */
+static Option*         OptRoot = 0;
+static Option*         OptLast = 0;
+static unsigned                OptCount = 0;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static Option* NewOption (unsigned char Type)
+/* Create a new option, insert it into the list and return it */
+{
+    Option* Opt;
+
+    /* Allocate memory */
+    Opt = Xmalloc (sizeof (*Opt));
+
+    /* Initialize fields */
+    Opt->Next  = 0;
+    Opt->Type  = Type;
+    Opt->V.Str = 0;
+
+    /* Insert it into the list */
+    if (OptRoot == 0) {
+       OptRoot = Opt;
+    } else {
+               OptLast->Next = Opt;
+    }
+    OptLast = Opt;
+
+    /* One more option now */
+    ++OptCount;
+
+    /* Return the new struct */
+    return Opt;
+}
+
+
+
+void OptStr (unsigned char Type, const char* Text)
+/* Add a string option */
+{
+    Option* O;
+
+    /* String must have less than 255 bytes */
+    if (strlen (Text) > 255) {
+       Fatal (FAT_STRING_TOO_LONG);
+    }
+    O        = NewOption (Type);
+    O->V.Str = StrDup (Text);
+}
+
+
+
+void OptComment (const char* Comment)
+/* Add a comment */
+{
+    OptStr (OPT_COMMENT, Comment);
+}
+
+
+
+void OptAuthor (const char* Author)
+/* Add an author statement */
+{
+    OptStr (OPT_AUTHOR, Author);
+}
+
+
+
+void OptTranslator (const char* Translator)
+/* Add a translator option */
+{
+    OptStr (OPT_TRANSLATOR, Translator);
+}
+
+
+
+void OptCompiler (const char* Compiler)
+/* Add a compiler option */
+{
+    OptStr (OPT_COMPILER, Compiler);
+}
+
+
+
+void OptOS (const char* OS)
+/* Add an operating system option */
+{
+    OptStr (OPT_OS, OS);
+}
+
+
+
+void OptDateTime (unsigned long DateTime)
+/* Add a date/time option */
+{
+    Option* O = NewOption (OPT_DATETIME);
+    O->V.Val = DateTime;
+}
+
+
+
+void WriteOptions (void)
+/* Write the options to the object file */
+{
+    Option* O;
+
+    /* Tell the object file module that we're about to start the options */
+    ObjStartOptions ();
+
+    /* Write the option count */
+    ObjWrite16 (OptCount);
+
+    /* Walk through the list and write the options */
+    O = OptRoot;
+    while (O) {
+
+       /* Write the type of the option */
+       ObjWrite8 (O->Type);
+
+       /* Write the argument */
+       switch (O->Type & OPT_ARGMASK) {
+
+           case OPT_ARGSTR:
+               ObjWriteStr (O->V.Str);
+               break;
+
+           case OPT_ARGNUM:
+               ObjWrite32 (O->V.Val);
+               break;
+
+           default:
+               Internal ("Invalid option type: $%02X", O->Type & 0xFF);
+
+       }
+
+       /* Next option */
+       O = O->Next;
+
+    }
+
+    /* Done writing options */
+    ObjEndOptions ();
+}
+
+
+
diff --git a/src/ca65/options.h b/src/ca65/options.h
new file mode 100644 (file)
index 0000000..1c6839b
--- /dev/null
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                options.h                                 */
+/*                                                                           */
+/*             Object file options for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void OptStr (unsigned char Type, const char* Text);
+/* Add a string option */
+
+void OptComment (const char* Comment);
+/* Add a comment */
+
+void OptAuthor (const char* Author);
+/* Add an author statement */
+
+void OptTranslator (const char* Translator);
+/* Add a translator option */
+
+void OptCompiler (const char* Compiler);
+/* Add a compiler option */
+
+void OptOS (const char* OS);
+/* Add an operating system option */
+
+void OptDateTime (unsigned long DateTime);
+/* Add a date/time option */
+
+void WriteOptions (void);
+/* Write the options to the object file */
+
+              
+
+/* End of options.h */
+
+#endif
+
+
+
diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c
new file mode 100644 (file)
index 0000000..f2ad9b3
--- /dev/null
@@ -0,0 +1,1190 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                pseudo.c                                  */
+/*                                                                           */
+/*             Pseudo instructions for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../common/bitops.h"
+
+#include "condasm.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macpack.h"
+#include "macro.h"
+#include "objcode.h"
+#include "options.h"
+#include "scanner.h"
+#include "strexpr.h"
+#include "symtab.h"
+#include "pseudo.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Keyword we're about to handle */
+static char Keyword [sizeof (SVal)+1] = ".";
+
+
+
+/*****************************************************************************/
+/*                              Forwards                                    */
+/*****************************************************************************/
+
+
+
+static void DoUnexpected (void);
+
+
+
+/*****************************************************************************/
+/*                             Helper functions                             */
+/*****************************************************************************/
+
+
+
+static void SetBoolOption (unsigned char* Flag)
+/* Read a on/off/+/- option and set flag accordingly */
+{
+    static const char* Keys[] = {
+               "OFF",
+       "ON",
+    };
+
+    if (Tok == TOK_PLUS) {
+               *Flag = 1;
+       NextTok ();
+    } else if (Tok == TOK_MINUS) {
+       *Flag = 0;
+       NextTok ();
+    } else if (Tok == TOK_IDENT) {
+               /* Map the keyword to a number */
+               switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
+           case 0:     *Flag = 0; NextTok ();          break;
+           case 1:     *Flag = 1; NextTok ();          break;
+           default:    ErrorSkip (ERR_ONOFF_EXPECTED); break;
+       }
+    } else if (Tok == TOK_SEP || Tok == TOK_EOF) {
+       /* Without anything assume switch on */
+       *Flag = 1;
+    } else {
+               ErrorSkip (ERR_ONOFF_EXPECTED);
+    }
+}
+
+
+
+static void ExportImport (void (*SymFunc) (const char*, int), int ZP)
+/* Export or import symbols */
+{
+    while (1) {
+       if (Tok != TOK_IDENT) {
+                   ErrorSkip (ERR_IDENT_EXPECTED);
+           break;
+       }
+       SymFunc (SVal, ZP);
+       NextTok ();
+       if (Tok == TOK_COMMA) {
+           NextTok ();
+       } else {
+           break;
+       }
+    }
+}
+
+
+
+static long IntArg (long Min, long Max)
+/* Read an integer argument and check a range. Accept the token "unlimited"
+ * and return -1 in this case.
+ */
+{
+    if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
+       NextTok ();
+       return -1;
+    } else {
+       long Val = ConstExpression ();
+       if (Val < Min || Val > Max) {
+           Error (ERR_RANGE);
+           Val = Min;
+       }
+       return Val;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            Handler functions                             */
+/*****************************************************************************/
+
+
+
+static void DoA16 (void)
+/* Switch the accu to 16 bit mode (assembler only) */
+{
+    if (GetCPU() != CPU_65816) {
+       Error (ERR_816_MODE_ONLY);
+    } else {
+               /* Immidiate mode has two extension bytes */
+       ExtBytes [AMI_IMM_ACCU] = 2;
+    }
+}
+
+
+
+static void DoA8 (void)
+/* Switch the accu to 8 bit mode (assembler only) */
+{
+    if (GetCPU() != CPU_65816) {
+       Error (ERR_816_MODE_ONLY);
+    } else {
+       /* Immidiate mode has one extension byte */
+       ExtBytes [AMI_IMM_ACCU] = 1;
+    }
+}
+
+
+
+static void DoAddr (void)
+/* Define addresses */
+{
+    while (1) {
+       if (GetCPU() == CPU_65816) {
+                   EmitWord (ForceWordExpr (Expression ()));
+       } else {
+           /* Do a range check */
+           EmitWord (Expression ());
+               }
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+static void DoAlign (void)
+/* Align the PC to some boundary */
+{
+    long Val;
+    long Align;
+    unsigned Bit;
+
+    /* Read the alignment value */
+    Align = ConstExpression ();
+    if (Align <= 0 || Align > 0x10000) {
+               ErrorSkip (ERR_RANGE);
+       return;
+    }
+
+    /* Optional value follows */
+    if (Tok == TOK_COMMA) {
+       NextTok ();
+       Val = ConstExpression ();
+       /* We need a byte value here */
+       if (!IsByteRange (Val)) {
+                   ErrorSkip (ERR_RANGE);
+           return;
+       }
+    } else {
+       Val = -1;
+    }
+
+    /* Check if the alignment is a power of two */
+    Bit = BitFind (Align);
+    if (Align != (0x01UL << Bit)) {
+       Error (ERR_ALIGN);
+    } else {
+       SegAlign (Bit, (int) Val);
+    }
+}
+
+
+
+static void DoASCIIZ (void)
+/* Define text with a zero terminator */
+{
+    while (1) {
+       if (StringExpression () == 0) {
+           ErrorSkip (ERR_STRCON_EXPECTED);
+           return;
+       }
+       EmitData (SVal, strlen (SVal));
+       NextTok ();
+       if (Tok == TOK_COMMA) {
+           NextTok ();
+       } else {
+           break;
+       }
+    }
+    Emit0 (0);
+}
+
+
+
+static void DoAutoImport (void)
+/* Mark unresolved symbols as imported */
+{
+    SetBoolOption (&AutoImport);
+}
+
+
+
+static void DoBss (void)
+/* Switch to the BSS segment */
+{
+    UseBssSeg ();
+}
+
+
+
+static void DoByte (void)
+/* Define bytes */
+{
+    while (1) {
+       if (StringExpression () != 0) {
+           /* A string */
+           EmitData (SVal, strlen (SVal));
+           NextTok ();
+       } else {
+           EmitByte (Expression ());
+       }
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+           /* Do smart handling of dangling comma */
+           if (Tok == TOK_SEP) {
+               Error (ERR_UNEXPECTED_EOL);
+               break;
+           }
+       }
+    }
+}
+
+
+
+static void DoCase (void)
+/* Switch the IgnoreCase option */
+{
+    SetBoolOption (&IgnoreCase);
+    IgnoreCase = !IgnoreCase;
+}
+
+
+
+static void DoCode (void)
+/* Switch to the code segment */
+{
+    UseCodeSeg ();
+}
+
+
+
+static void DoData (void)
+/* Switch to the data segment */
+{
+    UseDataSeg ();
+}
+
+
+
+static void DoDByt (void)
+/* Output double bytes */
+{
+    while (1) {
+       EmitWord (SwapExpr (Expression ()));
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+static void DoDebugInfo (void)
+/* Switch debug info on or off */
+{
+    SetBoolOption (&DbgSyms);
+}
+
+
+
+static void DoDefine (void)
+/* Define a one line macro */
+{
+    MacDef (MAC_STYLE_DEFINE);
+}
+
+
+
+static void DoDWord (void)
+/* Define dwords */
+{
+    while (1) {
+               EmitDWord (Expression ());
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+static void DoEnd (void)
+/* End of assembly */
+{
+    ForcedEnd = 1;
+}
+
+
+
+static void DoEndProc (void)
+/* Leave a lexical level */
+{
+    SymLeaveLevel ();
+}
+
+
+
+static void DoError (void)
+/* Use error */
+{
+    if (StringExpression () == 0) {
+       ErrorSkip (ERR_STRCON_EXPECTED);
+    } else {
+               Error (ERR_USER, SVal);
+       SkipUntilSep ();
+    }
+}
+
+
+
+static void DoExitMacro (void)
+/* Exit a macro expansion */
+{
+    if (!InMacExpansion ()) {
+       /* We aren't expanding a macro currently */
+               DoUnexpected ();
+    } else {
+       MacAbort ();
+    }
+}
+
+
+
+static void DoExport (void)
+/* Export a symbol */
+{
+    ExportImport (SymExport, 0);
+}
+
+
+
+static void DoExportZP (void)
+/* Export a zeropage symbol */
+{
+    ExportImport (SymExport, 1);
+}
+
+
+
+static void DoFarAddr (void)
+/* Define far addresses (24 bit) */
+{
+    while (1) {
+               EmitFarAddr (Expression ());
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+static void DoFeature (void)
+/* Switch the Feature option */
+{
+    int Feature;
+
+    static const char* Keys[] = {
+               "DOLLAR_IS_PC",
+       "LABELS_WITHOUT_COLONS",
+       "LOOSE_STRING_TERM",
+       "AT_IN_IDENTIFIERS",
+       "DOLLAR_IN_IDENTIFIERS",
+    };
+
+    /* Allow a list of comma separated keywords */
+    while (1) {
+
+       /* We expect an identifier */
+       if (Tok != TOK_IDENT) {
+           ErrorSkip (ERR_IDENT_EXPECTED);
+           return;
+       }
+
+       /* Map the keyword to a number */
+       Feature = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+       if (Feature < 0) {
+           /* Not found */
+           ErrorSkip (ERR_ILLEGAL_FEATURE);
+           return;
+       }
+
+       /* Skip the keyword */
+       NextTok ();
+
+       /* Switch the feature on */
+       switch (Feature) {
+           case 0:     DollarIsPC      = 1;    break;
+           case 1:     NoColonLabels   = 1;    break;
+           case 2:     LooseStringTerm = 1;    break;
+           case 3:     AtInIdents      = 1;    break;
+           case 4:     DollarInIdents  = 1;    break;
+           default:    Internal ("Invalid feature: %d", Feature);
+       }
+
+       /* Allow more than one keyword */
+       if (Tok == TOK_COMMA) {
+           NextTok ();
+       } else {
+           break;
+       }
+    }
+}
+
+
+
+static void DoFileOpt (void)
+/* Insert a file option */
+{
+    long OptNum;
+
+    /* The option type may be given as a keyword or as a number. */
+    if (Tok == TOK_IDENT) {
+
+       /* Option given as keyword */
+       static const char* Keys [] = {
+           "AUTHOR", "COMMENT", "COMPILER"
+       };
+
+       /* Map the option to a number */
+       OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+       if (OptNum < 0) {
+           /* Not found */
+           ErrorSkip (ERR_OPTION_KEY_EXPECTED);
+           return;
+       }
+
+       /* Skip the keyword */
+       NextTok ();
+
+       /* Must be followed by a comma */
+       ConsumeComma ();
+
+       /* We accept only string options for now */
+       if (StringExpression () == 0) {
+           ErrorSkip (ERR_STRCON_EXPECTED);
+           return;
+       }
+
+               /* Insert the option */
+       switch (OptNum) {
+
+           case 0:
+               /* Author */
+               OptAuthor (SVal);
+               break;
+
+           case 1:
+               /* Comment */
+               OptComment (SVal);
+               break;
+
+           case 2:
+               /* Compiler */
+               OptCompiler (SVal);
+               break;
+
+           default:
+               Internal ("Invalid OptNum: %l", OptNum);
+
+       }
+
+       /* Done */
+       NextTok ();
+
+    } else {
+
+       /* Option given as number */
+               OptNum = ConstExpression ();
+       if (!IsByteRange (OptNum)) {
+           ErrorSkip (ERR_RANGE);
+           return;
+       }
+
+       /* Must be followed by a comma */
+       ConsumeComma ();
+
+       /* We accept only string options for now */
+       if (StringExpression () == 0) {
+           ErrorSkip (ERR_STRCON_EXPECTED);
+           return;
+       }
+
+       /* Insert the option */
+       OptStr ((unsigned char) OptNum, SVal);
+
+       /* Done */
+       NextTok ();
+    }
+}
+
+
+
+static void DoGlobal (void)
+/* Declare a global symbol */
+{
+    ExportImport (SymGlobal, 0);
+}
+
+
+
+static void DoGlobalZP (void)
+/* Declare a global zeropage symbol */
+{
+    ExportImport (SymGlobal, 1);
+}
+
+
+
+static void DoI16 (void)
+/* Switch the index registers to 16 bit mode (assembler only) */
+{
+    if (GetCPU() != CPU_65816) {
+       Error (ERR_816_MODE_ONLY);
+    } else {
+               /* Immidiate mode has two extension bytes */
+       ExtBytes [AMI_IMM_INDEX] = 2;
+    }
+}
+
+
+
+static void DoI8 (void)
+/* Switch the index registers to 16 bit mode (assembler only) */
+{
+    if (GetCPU() != CPU_65816) {
+       Error (ERR_816_MODE_ONLY);
+    } else {
+       /* Immidiate mode has one extension byte */
+       ExtBytes [AMI_IMM_INDEX] = 1;
+    }
+}
+
+
+
+static void DoImport (void)
+/* Import a symbol */
+{
+    ExportImport (SymImport, 0);
+}
+
+
+
+static void DoImportZP (void)
+/* Import a zero page symbol */
+{
+    ExportImport (SymImport, 1);
+}
+
+
+
+static void DoIncBin (void)
+/* Include a binary file */
+{
+    /* Name must follow */
+    if (StringExpression () == 0) {
+       ErrorSkip (ERR_STRCON_EXPECTED);
+    } else {
+       /* Try to open the file */
+       FILE* F = fopen (SVal, "rb");
+       if (F == 0) {
+           Error (ERR_CANNOT_OPEN_INCLUDE, SVal, strerror (errno));
+       } else {
+           unsigned char Buf [1024];
+           size_t Count;
+           /* Read chunks and insert them into the output */
+           while ((Count = fread (Buf, 1, sizeof (Buf), F)) > 0) {
+               EmitData (Buf, Count);
+           }
+           /* Close the file, ignore errors since it's r/o */
+           (void) fclose (F);
+       }
+       /* Skip the name */
+       NextTok ();
+    }
+}
+
+
+
+static void DoInclude (void)
+/* Include another file */
+{
+    char Name [MAX_STR_LEN+1];
+
+    /* Name must follow */
+    if (StringExpression () == 0) {
+       ErrorSkip (ERR_STRCON_EXPECTED);
+    } else {
+       strcpy (Name, SVal);
+       NextTok ();
+       NewInputFile (Name);
+    }
+}
+
+
+
+static void DoLineCont (void)
+/* Switch the use of line continuations */
+{
+    SetBoolOption (&LineCont);
+}
+
+
+
+static void DoList (void)
+/* Enable/disable the listing */
+{
+    /* Get the setting */
+    unsigned char List;
+    SetBoolOption (&List);
+
+    /* Manage the counter */
+    if (List) {
+       EnableListing ();
+    } else {
+       DisableListing ();
+    }
+}
+
+
+
+static void DoListBytes (void)
+/* Set maximum number of bytes to list for one line */
+{
+    SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
+}
+
+
+
+static void DoLocalChar (void)
+/* Define the character that starts local labels */
+{
+    if (Tok != TOK_CHARCON) {
+       ErrorSkip (ERR_CHARCON_EXPECTED);
+    } else {
+       if (IVal != '@' && IVal != '?') {
+           Error (ERR_ILLEGAL_LOCALSTART);
+       } else {
+           LocalStart = IVal;
+               }
+       NextTok ();
+    }
+}
+
+
+
+static void DoMacPack (void)
+/* Insert a macro package */
+{
+    /* Macro package names */
+    static const char* Keys [] = {
+       "GENERIC",
+               "LONGBRANCH",
+    };
+
+    int Package;
+
+    /* We expect an identifier */
+    if (Tok != TOK_IDENT) {
+       ErrorSkip (ERR_IDENT_EXPECTED);
+       return;
+    }
+
+    /* Map the keyword to a number */
+    Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+    if (Package < 0) {
+       /* Not found */
+       ErrorSkip (ERR_ILLEGAL_MACPACK);
+       return;
+    }
+
+    /* Skip the package name */
+    NextTok ();
+
+    /* Insert the package */
+    InsertMacPack (Package);
+}
+
+
+
+static void DoMacro (void)
+/* Start a macro definition */
+{
+    MacDef (MAC_STYLE_CLASSIC);
+}
+
+
+
+static void DoNull (void)
+/* Switch to the NULL segment */
+{
+    UseNullSeg ();
+}
+
+
+
+static void DoOrg (void)
+/* Start absolute code */
+{
+    long PC = ConstExpression ();
+    if (PC < 0 || PC > 0xFFFF) {
+       Error (ERR_RANGE);
+       return;
+    }
+    SetAbsPC (PC);
+}
+
+
+
+static void DoOut (void)
+/* Output a string */
+{
+    if (StringExpression () == 0) {
+       ErrorSkip (ERR_STRCON_EXPECTED);
+    } else {
+       /* Output the string and be sure to flush the output to keep it in
+        * sync with any error messages if the output is redirected to a file.
+        */
+       printf ("%s\n", SVal);
+       fflush (stdout);
+       NextTok ();
+    }
+}
+
+
+
+static void DoP02 (void)
+/* Switch to 6502 CPU */
+{
+    SetCPU (CPU_6502);
+}
+
+
+
+static void DoPC02 (void)
+/* Switch to 65C02 CPU */
+{
+    SetCPU (CPU_65C02);
+}
+
+
+
+static void DoP816 (void)
+/* Switch to 65816 CPU */
+{
+    SetCPU (CPU_65816);
+}
+
+
+
+static void DoPageLength (void)
+/* Set the page length for the listing */
+{
+    PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
+}
+
+
+
+static void DoProc (void)
+/* Start a new lexical scope */
+{
+    if (Tok == TOK_IDENT) {
+       /* The new scope has a name */
+       SymDef (SVal, CurrentPC (), IsZPSeg ());
+       NextTok ();
+    }
+    SymEnterLevel ();
+}
+
+
+
+static void DoReloc (void)
+/* Enter relocatable mode */
+{
+    RelocMode = 1;
+}
+
+
+
+static void DoRepeat (void)
+/* Repeat some instruction block */
+{
+    ErrorSkip (ERR_NOT_IMPLEMENTED);
+}
+
+
+
+static void DoRes (void)
+/* Reserve some number of storage bytes */
+{
+    long Count;
+    long Val;
+
+    Count = ConstExpression ();
+    if (Count > 0xFFFF || Count < 0) {
+       ErrorSkip (ERR_RANGE);
+       return;
+    }
+    if (Tok == TOK_COMMA) {
+       NextTok ();
+       Val = ConstExpression ();
+       /* We need a byte value here */
+       if (!IsByteRange (Val)) {
+                   ErrorSkip (ERR_RANGE);
+           return;
+       }
+
+       /* Emit constant values */
+       while (Count--) {
+           Emit0 ((unsigned char) Val);
+       }
+
+    } else {
+       /* Emit fill fragments */
+       EmitFill (Count);
+    }
+}
+
+
+
+static void DoROData (void)
+/* Switch to the r/o data segment */
+{
+    UseRODataSeg ();
+}
+
+
+
+static void DoSegment (void)
+/* Switch to another segment */
+{
+    static const char* AttrTab [] = {
+       "ZEROPAGE", "DIRECT",
+       "ABSOLUTE",
+       "FAR", "LONG"
+    };
+    char Name [sizeof (SVal)];
+    int SegType;
+
+    if (StringExpression () == 0) {
+       ErrorSkip (ERR_STRCON_EXPECTED);
+    } else {
+
+       /* Save the name of the segment and skip it */
+       strcpy (Name, SVal);
+       NextTok ();
+
+       /* Check for an optional segment attribute */
+       SegType = SEGTYPE_DEFAULT;
+       if (Tok == TOK_COMMA) {
+           NextTok ();
+           if (Tok != TOK_IDENT) {
+               ErrorSkip (ERR_IDENT_EXPECTED);
+           } else {
+               int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
+               switch (Attr) {
+
+                   case 0:
+                   case 1:
+                       /* Zeropage */
+                       SegType = SEGTYPE_ZP;
+                       break;
+
+                   case 2:
+                       /* Absolute */
+                       SegType = SEGTYPE_ABS;
+                       break;
+
+                   case 3:
+                   case 4:
+                       /* Far */
+                       SegType = SEGTYPE_FAR;
+                       break;
+
+                   default:
+                       Error (ERR_ILLEGAL_SEG_ATTR);
+               }
+               NextTok ();
+           }
+       }
+
+       /* Set the segment */
+       UseSeg (Name, SegType);
+    }
+}
+
+
+
+static void DoSmart (void)
+/* Smart mode on/off */
+{
+    SetBoolOption (&SmartMode);
+}
+
+
+
+static void DoSunPlus (void)
+/* Switch to the SUNPLUS CPU */
+{
+    SetCPU (CPU_SUNPLUS);
+}
+
+
+
+static void DoUnexpected (void)
+/* Got an unexpected keyword */
+{
+    Error (ERR_UNEXPECTED, Keyword);
+    SkipUntilSep ();
+}
+
+
+
+static void DoWord (void)
+/* Define words */
+{
+    while (1) {
+               EmitWord (Expression ());
+       if (Tok != TOK_COMMA) {
+           break;
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+static void DoZeropage (void)
+/* Switch to the zeropage segment */
+{
+    UseZeropageSeg ();
+}
+
+
+
+/*****************************************************************************/
+/*                               Table data                                 */
+/*****************************************************************************/
+
+
+
+/* Control commands flags */
+enum {
+    ccNone     = 0x0000,               /* No special flags */
+    ccKeepToken        = 0x0001                /* Do not skip the current token */
+};
+
+/* Control command table */
+struct CtrlDesc_ {
+    unsigned           Flags;                  /* Flags for this directive */
+    void               (*Handler) (void);      /* Command handler */
+};
+typedef struct CtrlDesc_ CtrlDesc;
+
+#define PSEUDO_COUNT   (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
+static CtrlDesc CtrlCmdTab [] = {
+    { ccNone,          DoA16           },
+    { ccNone,          DoA8            },
+    { ccNone,          DoAddr          },      /* .ADDR */
+    { ccNone,          DoAlign         },
+    { ccNone,          DoASCIIZ        },
+    { ccNone,          DoAutoImport    },
+    { ccNone,          DoUnexpected    },      /* .BLANK */
+    { ccNone,          DoBss           },
+    { ccNone,          DoByte          },
+    { ccNone,          DoCase          },
+    { ccNone,          DoCode          },
+    { ccNone,          DoUnexpected    },      /* .CONST */
+    { ccNone,          DoUnexpected    },      /* .CPU */
+    { ccNone,          DoData          },
+    { ccNone,          DoDByt          },
+    { ccNone,          DoDebugInfo     },
+    { ccNone,          DoDefine        },
+    { ccNone,          DoUnexpected    },      /* .DEFINED */
+    { ccNone,          DoDWord         },
+    { ccKeepToken,     DoConditionals  },      /* .ELSE */
+    { ccKeepToken,     DoConditionals  },      /* .ELSEIF */
+    { ccNone,          DoEnd           },
+    { ccKeepToken,     DoConditionals  },      /* .ENDIF */
+    { ccNone,          DoUnexpected    },      /* .ENDMACRO */
+    { ccNone,          DoEndProc       },
+    { ccNone,          DoUnexpected    },      /* .ENDREPEAT */
+    { ccNone,          DoError         },
+    { ccNone,          DoExitMacro     },
+    { ccNone,          DoExport        },
+    { ccNone,          DoExportZP      },
+    { ccNone,          DoFarAddr       },
+    { ccNone,          DoFeature       },
+    { ccNone,          DoFileOpt       },
+    { ccNone,          DoGlobal        },
+    { ccNone,          DoGlobalZP      },
+    { ccNone,          DoI16           },
+    { ccNone,          DoI8            },
+    { ccKeepToken,     DoConditionals  },      /* .IF */
+    { ccKeepToken,     DoConditionals  },      /* .IFBLANK */
+    { ccKeepToken,     DoConditionals  },      /* .IFCONST */
+    { ccKeepToken,     DoConditionals  },      /* .IFDEF */
+    { ccKeepToken,             DoConditionals  },      /* .IFNBLANK */
+    { ccKeepToken,     DoConditionals  },      /* .IFNCONST */
+    { ccKeepToken,     DoConditionals  },      /* .IFNDEF */
+    { ccKeepToken,     DoConditionals  },      /* .IFNREF */
+    { ccKeepToken,     DoConditionals  },      /* .IFP02 */
+    { ccKeepToken,     DoConditionals  },      /* .IFP816 */
+    { ccKeepToken,     DoConditionals  },      /* .IFPC02 */
+    { ccKeepToken,     DoConditionals  },      /* .IFREF */
+    { ccNone,          DoImport        },
+    { ccNone,          DoImportZP      },
+    { ccNone,          DoIncBin        },
+    { ccNone,          DoInclude       },
+    { ccNone,          DoLineCont      },
+    { ccNone,          DoList          },
+    { ccNone,                  DoListBytes     },
+    { ccNone,          DoUnexpected    },      /* .LOCAL */
+    { ccNone,          DoLocalChar     },
+    { ccNone,          DoMacPack       },
+    { ccNone,          DoMacro         },
+    { ccNone,                  DoUnexpected    },      /* .MATCH */
+    { ccNone,          DoNull          },
+    { ccNone,          DoOrg           },
+    { ccNone,          DoOut           },
+    { ccNone,          DoP02           },
+    { ccNone,          DoP816          },
+    { ccNone,                  DoPageLength    },
+    { ccNone,          DoUnexpected    },      /* .PARAMCOUNT */
+    { ccNone,          DoPC02          },
+    { ccNone,          DoProc          },
+    { ccNone,          DoUnexpected    },      /* .REFERENCED */
+    { ccNone,          DoReloc         },
+    { ccNone,          DoRepeat        },
+    { ccNone,          DoRes           },
+    { ccNone,          DoROData        },
+    { ccNone,          DoSegment       },
+    { ccNone,          DoSmart         },
+    { ccNone,                  DoUnexpected    },      /* .STRING */
+    { ccNone,          DoSunPlus       },
+    { ccNone,          DoWord          },
+    { ccNone,                  DoUnexpected    },      /* .XMATCH */
+    { ccNone,          DoZeropage      },
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int TokIsPseudo (unsigned Tok)
+/* Return true if the given token is a pseudo instruction token */
+{
+    return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
+}
+
+
+
+void HandlePseudo (void)
+/* Handle a pseudo instruction */
+{
+    CtrlDesc* D;
+
+    /* Calculate the index into the table */
+    unsigned Index = Tok - TOK_FIRSTPSEUDO;
+
+    /* Safety check */
+    if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
+       Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
+                 PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
+    }
+    CHECK (Index < PSEUDO_COUNT);
+
+    /* Get the pseudo intruction descriptor */
+    D = &CtrlCmdTab [Index];
+
+    /* Remember the instruction, then skip it if needed */
+    if ((D->Flags & ccKeepToken) == 0) {
+       strcpy (Keyword+1, SVal);
+       NextTok ();
+    }
+
+    /* Call the handler */
+    D->Handler ();
+}
+
+
+
diff --git a/src/ca65/pseudo.h b/src/ca65/pseudo.h
new file mode 100644 (file)
index 0000000..5f67b6e
--- /dev/null
@@ -0,0 +1,74 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                pseudo.h                                  */
+/*                                                                           */
+/*             Pseudo instructions for the ca65 macroassembler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef PSEUDO_H
+#define PSEUDO_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Are we inside a .IF condition that has been evaluated to TRUE? */
+extern unsigned char IfCond;
+
+/* How many .IFs are currently open? */
+extern unsigned OpenIfs;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int TokIsPseudo (unsigned Tok);
+/* Return true if the given token is a pseudo instruction token */
+
+void HandlePseudo (void);
+/* Handle a pseudo instruction */
+
+
+
+/* End of pseudo.h */
+
+#endif
+
+
+
diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c
new file mode 100644 (file)
index 0000000..8e5261f
--- /dev/null
@@ -0,0 +1,1202 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                scanner.c                                 */
+/*                                                                           */
+/*                 The scanner for the ca65 macroassembler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "condasm.h"
+#include "error.h"
+#include "fname.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macro.h"
+#include "mem.h"
+#include "objfile.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+enum Token Tok = TOK_NONE;             /* Current token */
+int WS;                                        /* Flag: Whitespace before token */
+long IVal;                             /* Integer token attribute */
+char SVal [MAX_STR_LEN+1];             /* String token attribute */
+
+FilePos        CurPos = { 0, 0, 0 };           /* Name and position in current file */
+
+
+
+/* Struct to handle include files. Note: The length of the input line may
+ * not exceed 255+1, since the column is stored in the file position struct
+ * as a character. Increasing this value means changing the FilePos struct,
+ * and the read and write routines in the assembler and linker.
+ */
+typedef struct InputFile_ InputFile;
+struct InputFile_ {
+    FILE*                  F;                  /* Input file descriptor */
+    FilePos        Pos;                /* Position in file */
+    enum Token     Tok;                /* Last token */
+    int                    C;                  /* Last character */
+    char                   Line[256];          /* The current input line */
+    InputFile*     Next;               /* Linked list of input files */
+};
+
+/* Struct to handle textual input data */
+typedef struct InputData_ InputData;
+struct InputData_ {
+    const char*            Data;               /* Pointer to the data */
+    const char*     Pos;               /* Pointer to current position */
+    int                    Malloced;           /* Memory was malloced */
+    enum Token     Tok;                /* Last token */
+    int                    C;                  /* Last character */
+    InputData*     Next;               /* Linked list of input data */
+};
+
+/* List of input files */
+static struct {
+    unsigned long  MTime;              /* Time of last modification */
+    unsigned long  Size;               /* Size of file */
+    const char*           Name;                /* Name of file */
+} Files [MAX_INPUT_FILES];
+static unsigned    FileCount = 0;
+
+/* Current input variables */
+static InputFile* IFile = 0;
+static InputData* IData = 0;
+static unsigned          ICount = 0;           /* Count of input files */
+static int       C = 0;
+
+/* Force end of assembly */
+int              ForcedEnd = 0;
+
+/* List of dot keywords with the corresponding tokens */
+struct DotKeyword {
+    const char*        Key;                    /* MUST be first field */
+    enum Token  Tok;
+} DotKeywords [] = {
+    { "A16",           TOK_A16         },
+    { "A8",            TOK_A8          },
+    { "ADDR",          TOK_ADDR        },
+    { "ALIGN",         TOK_ALIGN       },
+    { "AND",           TOK_BAND        },
+    { "ASCIIZ",                TOK_ASCIIZ      },
+    { "AUTOIMPORT",    TOK_AUTOIMPORT  },
+    { "BITAND",                TOK_AND         },
+    { "BITNOT",                TOK_NOT         },
+    { "BITOR",         TOK_OR          },
+    { "BITXOR",                TOK_XOR         },
+    { "BLANK",         TOK_BLANK       },
+    { "BSS",           TOK_BSS         },
+    { "BYTE",          TOK_BYTE        },
+    { "CASE",          TOK_CASE        },
+    { "CODE",          TOK_CODE        },
+    { "CONST",                 TOK_CONST       },
+    { "CPU",           TOK_CPU         },
+    { "DATA",                  TOK_DATA        },
+    { "DBYT",                  TOK_DBYT        },
+    { "DEBUGINFO",     TOK_DEBUGINFO   },
+    { "DEF",                   TOK_DEFINED     },
+    { "DEFINE",                TOK_DEFINE      },
+    { "DEFINED",       TOK_DEFINED     },
+    { "DWORD",                 TOK_DWORD       },
+    { "ELSE",                  TOK_ELSE        },
+    { "ELSEIF",                TOK_ELSEIF      },
+    { "END",                   TOK_END         },
+    { "ENDIF",                 TOK_ENDIF       },
+    { "ENDMAC",                TOK_ENDMACRO    },
+    { "ENDMACRO",      TOK_ENDMACRO    },
+    { "ENDPROC",       TOK_ENDPROC     },
+    { "ENDREP",                TOK_ENDREP      },
+    { "ENDREPEAT",     TOK_ENDREP      },
+    { "ERROR",                 TOK_ERROR       },
+    { "EXITMAC",       TOK_EXITMACRO   },
+    { "EXITMACRO",     TOK_EXITMACRO   },
+    { "EXPORT",                TOK_EXPORT      },
+    { "EXPORTZP",      TOK_EXPORTZP    },
+    { "FARADDR",       TOK_FARADDR     },
+    { "FEATURE",       TOK_FEATURE     },
+    { "FILEOPT",       TOK_FILEOPT     },
+    { "FOPT",                  TOK_FILEOPT     },
+    { "GLOBAL",                TOK_GLOBAL      },
+    { "GLOBALZP",      TOK_GLOBALZP    },
+    { "I16",                   TOK_I16         },
+    { "I8",                    TOK_I8          },
+    { "IF",                    TOK_IF          },
+    { "IFBLANK",       TOK_IFBLANK     },
+    { "IFCONST",       TOK_IFCONST     },
+    { "IFDEF",                 TOK_IFDEF       },
+    { "IFNBLANK",      TOK_IFNBLANK    },
+    { "IFNCONST",      TOK_IFNCONST    },
+    { "IFNDEF",                TOK_IFNDEF      },
+    { "IFNREF",                TOK_IFNREF      },
+    { "IFP02",         TOK_IFP02       },
+    { "IFP816",                TOK_IFP816      },
+    { "IFPC02",                TOK_IFPC02      },
+    { "IFREF",         TOK_IFREF       },
+    { "IMPORT",                TOK_IMPORT      },
+    { "IMPORTZP",      TOK_IMPORTZP    },
+    { "INCBIN",                TOK_INCBIN      },
+    { "INCLUDE",       TOK_INCLUDE     },
+    { "LINECONT",      TOK_LINECONT    },
+    { "LIST",          TOK_LIST        },
+    { "LISTBYTES",     TOK_LISTBYTES   },
+    { "LOCAL",         TOK_LOCAL       },
+    { "LOCALCHAR",     TOK_LOCALCHAR   },
+    { "MAC",           TOK_MACRO       },
+    { "MACPACK",       TOK_MACPACK     },
+    { "MACRO",         TOK_MACRO       },
+    { "MATCH",         TOK_MATCH       },
+    { "MOD",           TOK_MOD         },
+    { "NOT",           TOK_BNOT        },
+    { "NULL",          TOK_NULL        },
+    { "OR",            TOK_BOR         },
+    { "ORG",           TOK_ORG         },
+    { "OUT",           TOK_OUT         },
+    { "P02",           TOK_P02         },
+    { "P816",          TOK_P816        },
+    { "PAGELEN",       TOK_PAGELENGTH  },
+    { "PAGELENGTH",    TOK_PAGELENGTH  },
+    { "PARAMCOUNT",    TOK_PARAMCOUNT  },
+    { "PC02",          TOK_PC02        },
+    { "PROC",          TOK_PROC        },
+    { "REF",           TOK_REFERENCED  },
+    { "REFERENCED",    TOK_REFERENCED  },
+    { "RELOC",         TOK_RELOC       },
+    { "REPEAT",                TOK_REPEAT      },
+    { "RES",           TOK_RES         },
+    { "RODATA",                TOK_RODATA      },
+    { "SEGMENT",       TOK_SEGMENT     },
+    { "SHL",           TOK_SHL         },
+    { "SHR",           TOK_SHR         },
+    { "SMART",         TOK_SMART       },
+    { "STRING",                TOK_STRING      },
+    { "SUNPLUS",       TOK_SUNPLUS     },
+    { "WORD",          TOK_WORD        },
+    { "XMATCH",                TOK_XMATCH      },
+    { "XOR",           TOK_BXOR        },
+    { "ZEROPAGE",      TOK_ZEROPAGE    },
+};
+
+
+
+/*****************************************************************************/
+/*                                Forwards                                  */
+/*****************************************************************************/
+
+
+
+static void NextChar (void);
+/* Read the next character from the input file */
+
+
+
+/*****************************************************************************/
+/*                   Character classification functions                     */
+/*****************************************************************************/
+
+
+
+static int IsBlank (int C)
+/* Return true if the character is a blank or tab */
+{
+    return (C == ' ' || C == '\t');
+}
+
+
+
+static int IsDigit (int C)
+/* Return true if the character is a digit */
+{
+    return isdigit (C);
+}
+
+
+
+static int IsXDigit (int C)
+/* Return true if the character is a hexadecimal digit */
+{
+    return isxdigit (C);
+}
+
+
+
+static int IsDDigit (int C)
+/* Return true if the character is a dual digit */
+{
+    return (C == '0' || C == '1');
+}
+
+
+
+static int IsIdChar (int C)
+/* Return true if the character is a valid character for an identifier */
+{
+    return isalnum (C)                         ||
+          (C == '_')                   ||
+          (C == '@' && AtInIdents)     ||
+          (C == '$' && DollarInIdents);
+}
+
+
+
+static int IsIdStart (int C)
+/* Return true if the character may start an identifier */
+{
+    return isalpha (C) || C == '_';
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+const char* GetFileName (unsigned char Name)
+/* Get the name of a file where the name index is known */
+{
+    PRECONDITION (Name <= FileCount);
+    if (Name == 0) {
+       /* Name was defined outside any file scope, use the name of the first
+        * file instead. Errors are then reported with a file position of
+        * line zero in the first file.
+        */
+       if (FileCount == 0) {
+           /* No files defined until now */
+                   return "(outside file scope)";
+       } else {
+           return Files [0].Name;
+       }
+    } else {
+        return Files [Name-1].Name;
+    }
+}
+
+
+
+void NewInputFile (const char* Name)
+/* Open a new input file */
+{
+    InputFile* I;
+    FILE* F;
+
+    /* Insert a copy of the filename into the list */
+    if (FileCount >= MAX_INPUT_FILES) {
+       Fatal (FAT_MAX_INPUT_FILES);
+    }
+    Files [FileCount].Name = StrDup (Name);
+
+    /* First try to open the file */
+    F = fopen (Name, "r");
+    if (F == 0) {
+
+       /* Error (fatal error if this is the main file) */
+       if (ICount == 0) {
+           Fatal (FAT_CANNOT_OPEN_INPUT, Name, strerror (errno));
+       } else {
+           Error (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
+           Xfree (Files [FileCount].Name);
+       }
+
+    } else {
+
+       /* Stat the file and remember the values */
+       struct stat Buf;
+       if (fstat (fileno (F), &Buf) != 0) {
+           Fatal (FAT_CANNOT_STAT_INPUT, Name, strerror (errno));
+       }
+       Files [FileCount].MTime = Buf.st_mtime;
+       Files [FileCount].Size  = Buf.st_size;
+       ++FileCount;
+
+       /* Create a new state variable and initialize it */
+               I           = Xmalloc (sizeof (*I));
+               I->F        = F;
+               I->Pos.Line = 0;
+       I->Pos.Col  = 0;
+               I->Pos.Name = FileCount;
+       I->Tok      = Tok;
+       I->C        = C;
+        I->Line[0]  = '\0';
+
+       /* Use the new file */
+       I->Next     = IFile;
+       IFile       = I;
+       ++ICount;
+
+       /* Prime the pump */
+       NextChar ();
+    }
+}
+
+
+
+void DoneInputFile (void)
+/* Close the current input file */
+{
+    InputFile* I;
+
+    /* Restore the old token */
+    Tok = IFile->Tok;
+    C   = IFile->C;
+
+    /* Save a pointer to the current struct, then set it back */
+    I     = IFile;
+    IFile = I->Next;
+
+    /* Cleanup the current stuff */
+    fclose (I->F);
+    Xfree (I);
+    --ICount;
+}
+
+
+
+void NewInputData (const char* Data, int Malloced)
+/* Add a chunk of input data to the input stream */
+{
+    InputData* I;
+
+    /* Create a new state variable and initialize it */
+    I                  = Xmalloc (sizeof (*I));
+    I->Data    = Data;
+    I->Pos     = Data;
+    I->Malloced = Malloced;
+    I->Tok             = Tok;
+    I->C        = C;
+
+    /* Use the new data */
+    I->Next    = IData;
+    IData      = I;
+
+    /* Prime the pump */
+    NextChar ();
+}
+
+
+
+static void DoneInputData (void)
+/* End the current input data stream */
+{
+    InputData* I;
+
+    /* Restore the old token */
+    Tok = IData->Tok;
+    C   = IData->C;
+
+    /* Save a pointer to the current struct, then set it back */
+    I     = IData;
+    IData = I->Next;
+
+    /* Cleanup the current stuff */
+    if (I->Malloced) {
+       Xfree (I->Data);
+    }
+    Xfree (I);
+}
+
+
+
+static unsigned DigitVal (unsigned char C)
+/* Convert a digit into it's numerical representation */
+{
+    if (IsDigit (C)) {
+       return C - '0';
+    } else {
+               return toupper (C) - 'A' + 10;
+    }
+}
+
+
+
+static void NextChar (void)
+/* Read the next character from the input file */
+{
+    /* If we have an input data structure, read from there */
+    if (IData) {
+
+               C = *IData->Pos++;
+               if (C == '\0') {
+                   /* End of input data, will set to last file char */
+                   DoneInputData ();
+               }
+
+    } else {
+
+       /* Check for end of line, read the next line if needed */
+               while (IFile->Line [IFile->Pos.Col] == '\0') {
+
+           /* End of current line reached, read next line */
+           if (fgets (IFile->Line, sizeof (IFile->Line), IFile->F) == 0) {
+               /* End of file. Add an empty line to the listing. This is a
+                * small hack needed to keep the PC output in sync.
+                */
+               NewListingLine ("", IFile->Pos.Name, ICount);
+               C = EOF;
+               return;
+           }
+
+           /* One more line */
+           IFile->Pos.Line++;
+           IFile->Pos.Col = 0;
+
+           /* Remember the new line for the listing */
+           NewListingLine (IFile->Line, IFile->Pos.Name, ICount);
+
+       }
+
+       /* Return the next character from the file */
+       C = IFile->Line [IFile->Pos.Col++];
+
+    }
+}
+
+
+
+void UpcaseSVal (void)
+/* Make SVal upper case */
+{
+    unsigned I = 0;
+    while (SVal [I]) {
+       SVal [I] = toupper (SVal [I]);
+       ++I;
+    }
+}
+
+
+
+static int CmpDotKeyword (const void* K1, const void* K2)
+/* Compare function for the dot keyword search */
+{
+    return strcmp (((struct DotKeyword*)K1)->Key, ((struct DotKeyword*)K2)->Key);
+}
+
+
+
+static unsigned char FindDotKeyword (void)
+/* Find the dot keyword in SVal. Return the corresponding token if found,
+ * return TOK_NONE if not found.
+ */
+{
+    static const struct DotKeyword K = { SVal, 0 };
+    struct DotKeyword* R;
+
+    /* If we aren't in ignore case mode, we have to uppercase the keyword */
+    if (!IgnoreCase) {
+       UpcaseSVal ();
+    }
+
+    /* Search for the keyword */
+    R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
+                sizeof (DotKeywords [0]), CmpDotKeyword);
+    if (R != 0) {
+       return R->Tok;
+    } else {
+       return TOK_NONE;
+    }
+}
+
+
+
+static void ReadIdent (void)
+/* Read an identifier from the current input position into Ident. It is
+ * assumed that the first character has already been checked.
+ */
+{
+    /* Read the identifier */
+    unsigned I = 0;
+    do {
+       if (I < MAX_STR_LEN) {
+           SVal [I++] = C;
+       }
+       NextChar ();
+    } while (IsIdChar (C));
+    SVal [I] = '\0';
+
+    /* If we should ignore case, convert the identifier to upper case */
+    if (IgnoreCase) {
+       UpcaseSVal ();
+    }
+}
+
+
+
+static unsigned ReadStringConst (int StringTerm)
+/* Read a string constant into SVal. Check for maximum string length and all
+ * other stuff.        The length of the string is returned.
+ */
+{
+    unsigned I;
+
+    /* Skip the leading string terminator */
+    NextChar ();
+
+    /* Read the string */
+    I = 0;
+    while (1) {
+       if (C == StringTerm) {
+           break;
+       }
+       if (C == '\n' || C == EOF) {
+           Error (ERR_NEWLINE_IN_STRING);
+           break;
+       }
+
+       /* Check for string length, print an error message once */
+       if (I == MAX_STR_LEN) {
+           Error (ERR_STRING_TOO_LONG);
+       } else if (I < MAX_STR_LEN) {
+           SVal [I] = C;
+       }
+       ++I;
+
+       /* Skip the character */
+       NextChar ();
+    }
+
+    /* Skip the trailing terminator */
+    NextChar ();
+
+    /* Terminate the string */
+    if (I >= MAX_STR_LEN) {
+       I = MAX_STR_LEN;
+    }
+    SVal [I] = '\0';
+
+    /* Return the length of the string */
+    return I;
+}
+
+
+
+void NextTok (void)
+/* Read the next raw token from the input stream */
+{
+    /* If we've a forced end of assembly, don't read further */
+    if (ForcedEnd) {
+       Tok = TOK_EOF;
+       return;
+    }
+
+    /* If we're expanding a macro, the tokens come from the macro expansion */
+    if (MacExpand ()) {
+       return;
+    }
+
+Again:
+    /* Skip whitespace, remember if we had some */
+    if ((WS = IsBlank (C)) != 0) {
+       do {
+           NextChar ();
+        } while (IsBlank (C));
+    }
+
+    /* If we're reading from the file, update the location from where the
+     * next token will be read. If we're reading from input data, keep the
+     * current position.
+     */
+    if (IData == 0) {
+        CurPos = IFile->Pos;
+    }
+
+    /* Hex number or PC symbol? */
+    if (C == '$') {
+       NextChar ();
+
+       /* Hex digit must follow or DollarIsPC must be enabled */
+       if (!IsXDigit (C)) {
+           if (DollarIsPC) {
+               Tok = TOK_PC;
+               return;
+           } else {
+               Error (ERR_HEX_DIGIT_EXPECTED);
+           }
+       }
+
+       /* Read the number */
+       IVal = 0;
+       while (IsXDigit (C)) {
+           if (IVal & 0xF0000000) {
+               Error (ERR_NUM_OVERFLOW);
+               IVal = 0;
+           }
+           IVal = (IVal << 4) + DigitVal (C);
+           NextChar ();
+       }
+
+       /* This is an integer constant */
+       Tok = TOK_INTCON;
+       return;
+    }
+
+    /* Dual number? */
+    if (C == '%') {
+       NextChar ();
+
+       /* 0 or 1 must follow */
+       if (!IsDDigit (C)) {
+           Error (ERR_01_EXPECTED);
+       }
+
+       /* Read the number */
+       IVal = 0;
+       while (IsDDigit (C)) {
+           if (IVal & 0x80000000) {
+               Error (ERR_NUM_OVERFLOW);
+               IVal = 0;
+           }
+           IVal = (IVal << 1) + DigitVal (C);
+           NextChar ();
+       }
+
+       /* This is an integer constant */
+       Tok = TOK_INTCON;
+       return;
+    }
+
+    /* Decimal number? */
+    if (IsDigit (C)) {
+
+       /* Read the number */
+       IVal = 0;
+       while (IsDigit (C)) {
+           if (IVal > (0xFFFFFFFF / 10)) {
+                       Error (ERR_NUM_OVERFLOW);
+               IVal = 0;
+           }
+           IVal = (IVal * 10) + DigitVal (C);
+           NextChar ();
+       }
+
+       /* This is an integer constant */
+               Tok = TOK_INTCON;
+       return;
+    }
+
+    /* Control command? */
+    if (C == '.') {
+
+       NextChar ();
+
+       if (!IsIdStart (C)) {
+           Error (ERR_PSEUDO_EXPECTED);
+           /* Try to read an identifier */
+           goto Again;
+       }
+
+       /* Read the identifier */
+       ReadIdent ();
+
+       /* Search the keyword */
+       Tok = FindDotKeyword ();
+       if (Tok == TOK_NONE) {
+           /* Not found */
+           Error (ERR_PSEUDO_EXPECTED);
+           goto Again;
+       }
+       return;
+    }
+
+    /* Local symbol? */
+    if (C == LocalStart) {
+
+       /* Read the identifier */
+       ReadIdent ();
+
+       /* Start character alone is not enough */
+        if (SVal [1] == '\0') {
+           Error (ERR_IDENT_EXPECTED);
+                   goto Again;
+       }
+
+               /* An identifier */
+       Tok = TOK_IDENT;
+       return;
+    }
+
+
+    /* Identifier or keyword? */
+    if (IsIdStart (C)) {
+
+       /* Read the identifier */
+       ReadIdent ();
+
+               /* Check for special names */
+        if (SVal [1] == '\0') {
+           switch (toupper (SVal [0])) {
+
+               case 'A':
+                   Tok = TOK_A;
+                   return;
+
+               case 'X':
+                   Tok = TOK_X;
+                   return;
+
+               case 'Y':
+                   Tok = TOK_Y;
+                   return;
+
+               case 'S':
+                   Tok = TOK_S;
+                   return;
+
+               default:
+                   Tok = TOK_IDENT;
+                   return;
+           }
+       }
+
+       /* Search for an opcode */
+       IVal = FindInstruction (SVal);
+       if (IVal >= 0) {
+           /* This is a mnemonic */
+                   Tok = TOK_MNEMO;
+               } else if (IsDefine (SVal)) {
+           /* This is a define style macro - expand it */
+           MacExpandStart ();
+           if (!MacExpand ()) {
+               goto Again;
+           }
+       } else {
+           /* An identifier */
+           Tok = TOK_IDENT;
+       }
+       return;
+    }
+
+    /* Ok, let's do the switch */
+CharAgain:
+    switch (C) {
+
+       case '+':
+           NextChar ();
+           Tok = TOK_PLUS;
+           return;
+
+       case '-':
+           NextChar ();
+           Tok = TOK_MINUS;
+           return;
+
+       case '/':
+           NextChar ();
+           Tok = TOK_DIV;
+           return;
+
+       case '*':
+           NextChar ();
+           Tok = TOK_MUL;
+           return;
+
+       case '^':
+           NextChar ();
+           Tok = TOK_XOR;
+           return;
+
+       case '&':
+           NextChar ();
+           if (C == '&') {
+               NextChar ();
+               Tok = TOK_BAND;
+           } else {
+               Tok = TOK_AND;
+           }
+                   return;
+
+       case '|':
+           NextChar ();
+           if (C == '|') {
+               NextChar ();
+               Tok = TOK_BOR;
+           } else {
+               Tok = TOK_OR;
+           }
+           return;
+
+       case ':':
+           NextChar ();
+           switch (C) {
+
+               case ':':
+                   NextChar ();
+                   Tok = TOK_NAMESPACE;
+                   break;
+
+               case '-':
+                   IVal = 0;
+                   do {
+                       --IVal;
+                       NextChar ();
+                   } while (C == '-');
+                   Tok = TOK_ULABEL;
+                   break;
+
+               case '+':
+                   IVal = 0;
+                   do {
+                       ++IVal;
+                       NextChar ();
+                   } while (C == '+');
+                   Tok = TOK_ULABEL;
+                   break;
+
+               default:
+                   Tok = TOK_COLON;
+                   break;
+           }
+           return;
+
+       case ',':
+           NextChar ();
+           Tok = TOK_COMMA;
+           return;
+
+       case ';':
+           NextChar ();
+           while (C != '\n' && C != EOF) {
+               NextChar ();
+           }
+           goto CharAgain;
+
+       case '#':
+           NextChar ();
+           Tok = TOK_HASH;
+           return;
+
+       case '(':
+           NextChar ();
+           Tok = TOK_LPAREN;
+           return;
+
+       case ')':
+                   NextChar ();
+            Tok = TOK_RPAREN;
+           return;
+
+       case '[':
+           NextChar ();
+           Tok = TOK_LBRACK;
+           return;
+
+       case ']':
+           NextChar ();
+           Tok = TOK_RBRACK;
+           return;
+
+       case '<':
+           NextChar ();
+           if (C == '=') {
+               NextChar ();
+               Tok = TOK_LE;
+           } else if (C == '<') {
+               NextChar ();
+               Tok = TOK_SHL;
+           } else if (C == '>') {
+               NextChar ();
+               Tok = TOK_NE;
+           } else {
+               Tok = TOK_LT;
+           }
+           return;
+
+       case '=':
+           NextChar ();
+                   Tok = TOK_EQ;
+           return;
+
+       case '!':
+           NextChar ();
+           Tok = TOK_BNOT;
+           return;
+
+       case '>':
+           NextChar ();
+           if (C == '=') {
+               NextChar ();
+               Tok = TOK_GE;
+                   } else if (C == '>') {
+               NextChar ();
+               Tok = TOK_SHR;
+           } else {
+               Tok = TOK_GT;
+           }
+           return;
+
+        case '~':
+           NextChar ();
+           Tok = TOK_NOT;
+           return;
+
+       case '\'':
+           /* Hack: If we allow ' as terminating character for strings, read
+            * the following stuff as a string, and check for a one character
+            * string later.
+            */
+           if (LooseStringTerm) {
+               if (ReadStringConst ('\'') == 1) {
+                   IVal = SVal[0];
+                   Tok = TOK_CHARCON;
+               } else {
+                   Tok = TOK_STRCON;
+               }
+           } else {
+               /* Always a character constant */
+               NextChar ();
+               if (C == '\n' || C == EOF) {
+                   Error (ERR_ILLEGAL_CHARCON);
+                   goto CharAgain;
+               }
+               IVal = C;
+               Tok = TOK_CHARCON;
+               NextChar ();
+               if (C != '\'') {
+                   Error (ERR_ILLEGAL_CHARCON);
+               } else {
+                   NextChar ();
+               }
+           }
+           return;
+
+       case '\"':
+           ReadStringConst ('\"');
+           Tok = TOK_STRCON;
+           return;
+
+       case '\\':
+           /* Line continuation? */
+           if (LineCont) {
+               NextChar ();
+               if (C == '\n') {
+                   /* Handle as white space */
+                   NextChar ();
+                   C = ' ';
+                   goto Again;
+               }
+           }
+           break;
+
+        case '\n':
+           NextChar ();
+           Tok = TOK_SEP;
+           return;
+
+        case EOF:
+           /* Check if we have any open .IFs in this file */
+           CheckOpenIfs ();
+
+           /* If this was an include file, then close it and handle like a
+            * separator. Do not close the main file, but return EOF.
+            */
+           if (ICount > 1) {
+               DoneInputFile ();
+           } else {
+               Tok = TOK_EOF;
+           }
+           return;
+
+    }
+
+    /* If we go here, we could not identify the current character. Skip it
+     * and try again.
+     */
+    Error (ERR_INVALID_CHAR, C & 0xFF);
+    NextChar ();
+    goto Again;
+}
+
+
+
+void Consume (enum Token Expected, unsigned ErrMsg)
+/* Consume Expected, print an error if we don't find it */
+{
+    if (Tok == Expected) {
+       NextTok ();
+    } else {
+       Error (ErrMsg);
+    }
+}
+
+
+
+void ConsumeSep (void)
+/* Consume a separator token */
+{
+    /* Accept an EOF as separator */
+    if (Tok != TOK_EOF) {
+       if (Tok != TOK_SEP) {
+           Error (ERR_TOO_MANY_CHARS);
+           SkipUntilSep ();
+       } else {
+           NextTok ();
+       }
+    }
+}
+
+
+
+void ConsumeLParen (void)
+/* Consume a left paren */
+{
+    Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED);
+}
+
+
+
+void ConsumeRParen (void)
+/* Consume a right paren */
+{
+    Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED);
+}
+
+
+
+void ConsumeComma (void)
+/* Consume a comma */
+{
+    Consume (TOK_COMMA, ERR_COMMA_EXPECTED);
+}
+
+
+
+void SkipUntilSep (void)
+/* Skip tokens until we reach a line separator */
+{
+    while (Tok != TOK_SEP && Tok != TOK_EOF) {
+       NextTok ();
+    }
+}
+
+
+
+int TokHasSVal (enum Token Tok)
+/* Return true if the given token has an attached SVal */
+{
+    return (Tok == TOK_IDENT || Tok == TOK_STRCON);
+}
+
+
+
+int TokHasIVal (enum Token Tok)
+/* Return true if the given token has an attached IVal */
+{
+    return (Tok == TOK_INTCON || Tok == TOK_CHARCON || Tok == TOK_MNEMO);
+}
+
+
+
+int GetSubKey (const char** Keys, unsigned Count)
+/* Search for a subkey in a table of keywords. The current token must be an
+ * identifier and all keys must be in upper case. The identifier will be
+ * uppercased in the process. The function returns the index of the keyword,
+ * or -1 if the keyword was not found.
+ */
+{
+    unsigned I;
+
+    /* Must have an identifier */
+    PRECONDITION (Tok == TOK_IDENT);
+
+    /* If we aren't in ignore case mode, we have to uppercase the identifier */
+    if (!IgnoreCase) {
+       UpcaseSVal ();
+    }
+
+    /* Do a linear search (a binary search is not worth the effort) */
+    for (I = 0; I < Count; ++I) {
+       if (strcmp (SVal, Keys [I]) == 0) {
+           /* Found it */
+           return I;
+       }
+    }
+
+    /* Not found */
+    return -1;
+}
+
+
+
+void WriteFiles (void)
+/* Write the list of input files to the object file */
+{
+    unsigned I;
+
+    /* Tell the obj file module that we're about to start the file list */
+    ObjStartFiles ();
+
+    /* Write the file count */
+    ObjWrite8 (FileCount);
+
+    /* Write the file data */
+    for (I = 0; I < FileCount; ++I) {
+       ObjWrite32 (Files [I].MTime);
+       ObjWrite32 (Files [I].Size);
+       ObjWriteStr (Files [I].Name);
+    }
+
+    /* Done writing files */
+    ObjEndFiles ();
+}
+
+
+
+void InitScanner (const char* InFile)
+/* Initialize the scanner, open the given input file */
+{
+    /* Open the input file */
+    NewInputFile (InFile);
+}
+
+
+
+void DoneScanner (void)
+/* Release scanner resources */
+{
+    DoneInputFile ();
+}
+
+
+
diff --git a/src/ca65/scanner.h b/src/ca65/scanner.h
new file mode 100644 (file)
index 0000000..813a54f
--- /dev/null
@@ -0,0 +1,283 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                scanner.h                                 */
+/*                                                                           */
+/*                 The scanner for the ca65 macroassembler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Tokens */
+enum Token {
+    TOK_NONE,          /* Start value, invalid */
+    TOK_EOF,                   /* End of input file */
+    TOK_SEP,           /* Separator (usually newline) */
+    TOK_IDENT,         /* An identifier */
+    TOK_MNEMO,                 /* A mnemonic */
+
+    TOK_INTCON,        /* Integer constant */
+    TOK_CHARCON,       /* Character constant */
+    TOK_STRCON,                /* String constant */
+
+    TOK_A,             /* A)ccu */
+    TOK_X,             /* X register */
+    TOK_Y,             /* Y register */
+    TOK_S,             /* S register */
+
+    TOK_ULABEL,                /* :++ or :-- */
+
+    TOK_EQ,            /* = */
+    TOK_NE,            /* <> */
+    TOK_LT,            /* < */
+    TOK_GT,            /* > */
+    TOK_LE,            /* <= */
+    TOK_GE,            /* >= */
+
+    TOK_BAND,                  /* .and */
+    TOK_BOR,           /* .or */
+    TOK_BXOR,                  /* .xor */
+    TOK_BNOT,          /* .not */
+
+    TOK_PLUS,          /* + */
+    TOK_MINUS,         /* - */
+    TOK_MUL,           /* * */
+    TOK_STAR = TOK_MUL,        /* Alias */
+    TOK_DIV,           /* / */
+    TOK_MOD,           /* ! */
+    TOK_OR,            /* | */
+    TOK_XOR,           /* ^ */
+    TOK_AND,           /* & */
+    TOK_SHL,           /* << */
+    TOK_SHR,           /* >> */
+    TOK_NOT,           /* ~ */
+
+    TOK_PC,            /* $ if enabled */
+    TOK_NAMESPACE,     /* :: */
+    TOK_DOT,           /* . */
+    TOK_COMMA,         /* , */
+    TOK_HASH,          /* # */
+    TOK_COLON,                 /* : */
+    TOK_LPAREN,                /* ( */
+    TOK_RPAREN,                /* ) */
+    TOK_LBRACK,                /* [ */
+    TOK_RBRACK,                /* ] */
+
+    TOK_MACPARAM,      /* Macro parameter, not generated by scanner */
+
+    /* The next ones are tokens for the pseudo instructions. Keep together! */
+    TOK_FIRSTPSEUDO,
+    TOK_A16            = TOK_FIRSTPSEUDO,
+    TOK_A8,
+    TOK_ADDR,
+    TOK_ALIGN,
+    TOK_ASCIIZ,
+    TOK_AUTOIMPORT,
+    TOK_BLANK,
+    TOK_BSS,
+    TOK_BYTE,
+    TOK_CASE,
+    TOK_CODE,
+    TOK_CONST,
+    TOK_CPU,
+    TOK_DATA,
+    TOK_DBYT,
+    TOK_DEBUGINFO,
+    TOK_DEFINE,
+    TOK_DEFINED,
+    TOK_DWORD,
+    TOK_ELSE,
+    TOK_ELSEIF,
+    TOK_END,
+    TOK_ENDIF,
+    TOK_ENDMACRO,
+    TOK_ENDPROC,
+    TOK_ENDREP,
+    TOK_ERROR,
+    TOK_EXITMACRO,
+    TOK_EXPORT,
+    TOK_EXPORTZP,
+    TOK_FARADDR,
+    TOK_FEATURE,
+    TOK_FILEOPT,
+    TOK_GLOBAL,
+    TOK_GLOBALZP,
+    TOK_I16,
+    TOK_I8,
+    TOK_IF,
+    TOK_IFBLANK,
+    TOK_IFCONST,
+    TOK_IFDEF,
+    TOK_IFNBLANK,
+    TOK_IFNCONST,
+    TOK_IFNDEF,
+    TOK_IFNREF,
+    TOK_IFP02,
+    TOK_IFP816,
+    TOK_IFPC02,
+    TOK_IFREF,
+    TOK_IMPORT,
+    TOK_IMPORTZP,
+    TOK_INCBIN,
+    TOK_INCLUDE,
+    TOK_LINECONT,
+    TOK_LIST,
+    TOK_LISTBYTES,
+    TOK_LOCAL,
+    TOK_LOCALCHAR,
+    TOK_MACPACK,
+    TOK_MACRO,
+    TOK_MATCH,
+    TOK_NULL,
+    TOK_ORG,
+    TOK_OUT,
+    TOK_P02,
+    TOK_P816,
+    TOK_PAGELENGTH,
+    TOK_PARAMCOUNT,
+    TOK_PC02,
+    TOK_PROC,
+    TOK_REFERENCED,
+    TOK_RELOC,
+    TOK_REPEAT,
+    TOK_RES,
+    TOK_RODATA,
+    TOK_SEGMENT,
+    TOK_SMART,
+    TOK_STRING,
+    TOK_SUNPLUS,
+    TOK_WORD,
+    TOK_XMATCH,
+    TOK_ZEROPAGE,
+    TOK_LASTPSEUDO     = TOK_ZEROPAGE,
+
+    TOK_COUNT                  /* Count of tokens */
+};
+
+
+
+/* Scanner variables */
+#define MAX_INPUT_FILES        254             /* No more than this files total */
+#define MAX_STR_LEN            255             /* Maximum length of any string */
+extern enum Token Tok;                 /* Current token */
+extern int WS;                                 /* Flag: Whitespace before token */
+extern long IVal;                              /* Integer token attribute */
+extern char SVal [MAX_STR_LEN+1];      /* String token attribute */
+
+extern FilePos         CurPos;                 /* Name and position in file */
+extern int             ForcedEnd;              /* Force end of assembly */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+const char* GetFileName (unsigned char Name);
+/* Get the name of a file where the name index is known */
+
+void NewInputFile (const char* Name);
+/* Open a new input file */
+
+void DoneInputFile (void);
+/* Close the current input file */
+
+void NewInputData (const char* Data, int Malloced);
+/* Add a chunk of input data to the input stream */
+
+void UpcaseSVal (void);
+/* Make SVal upper case */
+
+void NextTok (void);
+/* Read the next token from the input stream */
+
+void Consume (enum Token Expected, unsigned ErrMsg);
+/* Consume Token, print an error if we don't find it */
+
+void ConsumeSep (void);
+/* Consume a separator token */
+
+void ConsumeLParen (void);
+/* Consume a left paren */
+
+void ConsumeRParen (void);
+/* Consume a right paren */
+
+void ConsumeComma (void);
+/* Consume a comma */
+
+void SkipUntilSep (void);
+/* Skip tokens until we reach a line separator */
+
+int TokHasSVal (enum Token Tok);
+/* Return true if the given token has an attached SVal */
+
+int TokHasIVal (enum Token Tok);
+/* Return true if the given token has an attached IVal */
+
+int GetSubKey (const char** Keys, unsigned Count);
+/* Search for a subkey in a table of keywords. The current token must be an
+ * identifier and all keys must be in upper case. The identifier will be
+ * uppercased in the process. The function returns the index of the keyword,
+ * or -1 if the keyword was not found.
+ */
+
+void WriteFiles (void);
+/* Write the list of input files to the object file */
+
+void InitScanner (const char* InFile);
+/* Initialize the scanner, open the given input file */
+
+void DoneScanner (void);
+/* Release scanner resources */
+
+
+
+/* End of scanner.h */
+
+#endif
+
+
+
diff --git a/src/ca65/strexpr.c b/src/ca65/strexpr.c
new file mode 100644 (file)
index 0000000..e3d30ba
--- /dev/null
@@ -0,0 +1,97 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                strexpr.c                                 */
+/*                                                                           */
+/*             String expressions for the ca65 macroassembler               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "error.h"
+#include "expr.h"
+#include "scanner.h"
+#include "strexpr.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+const char* StringExpression (void)
+/* Evaluate a string expression. If there are no errors, the function will
+ * place the string into the token attribute buffer SVal and the token will
+ * be TOK_STRCON. A pointer to the buffer is returned.
+ * If there was an error, a NULL pointer is returned.
+ */
+{
+    char Buf [sizeof (SVal)];
+
+    /* Check for a string constant or a function that returns a string */
+    switch (Tok) {
+
+       case TOK_STRING:
+           NextTok ();
+           ConsumeLParen ();
+           if (Tok == TOK_IDENT) {
+               /* Save the identifier, then skip it */
+               strcpy (Buf, SVal);
+               NextTok ();
+           } else {
+               /* Numeric expression */
+               long Val = ConstExpression ();
+               sprintf (Buf, "%ld", Val);
+           }
+           if (Tok != TOK_RPAREN) {
+               Error (ERR_RPAREN_EXPECTED);
+           }
+           /* Overwrite the token, do not skip it! */
+           strcpy (SVal, Buf);
+           Tok = TOK_STRCON;
+           break;
+
+       case TOK_STRCON:
+           /* We already have a string */
+           break;
+
+       default:
+           /* Error - no string constant */
+           return 0;
+    }
+
+    /* Return a pointer to the buffer */
+    return SVal;
+}
+
+
+
diff --git a/src/ca65/strexpr.h b/src/ca65/strexpr.h
new file mode 100644 (file)
index 0000000..9457b9f
--- /dev/null
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                strexpr.h                                 */
+/*                                                                           */
+/*             String expressions for the ca65 macroassembler               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef STREXPR_H
+#define STREXPR_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+const char* StringExpression (void);
+/* Evaluate a string expression. If there are no errors, the function will
+ * place the string into the token attribute buffer SVal and the token will
+ * be TOK_STRCON. A pointer to the buffer is returned.
+ * If there was an error, a NULL pointer is returned.
+ */
+
+
+
+/* End of strexpr.h */
+
+#endif
+
+
+
diff --git a/src/ca65/symentry.h b/src/ca65/symentry.h
new file mode 100644 (file)
index 0000000..bbc1c89
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               symentry.h                                 */
+/*                                                                           */
+/*         Symbol table entry forward for the ca65 macroassembler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SYMENTRY_H
+#define SYMENTRY_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Forward declaration for struct SymEntry */
+typedef struct SymEntry_ SymEntry;
+
+
+
+/* End of symentry.h */
+
+#endif
+
+
+
diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c
new file mode 100644 (file)
index 0000000..53843eb
--- /dev/null
@@ -0,0 +1,1127 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                symtab.c                                  */
+/*                                                                           */
+/*                Symbol table for the ca65 macroassembler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/symdefs.h"
+#include "../common/hashstr.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "expr.h"
+#include "objfile.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Bits for the Flags value in SymEntry */
+#define SF_USER                0x0001          /* User bit */
+#define SF_TRAMPOLINE          0x0002          /* Trampoline entry */
+#define SF_EXPORT              0x0004          /* Export this symbol */
+#define SF_IMPORT      0x0008          /* Import this symbol */
+#define SF_GLOBAL      0x0010          /* Global symbol */
+#define SF_ZP                  0x0020          /* Declared as zeropage symbol */
+#define SF_ABS         0x0040          /* Declared as absolute symbol */
+#define SF_INDEXED     0x0800          /* Index is valid */
+#define SF_CONST       0x1000          /* The symbol has a constant value */
+#define SF_MULTDEF             0x2000          /* Multiply defined symbol */
+#define        SF_DEFINED      0x4000          /* Defined */
+#define SF_REFERENCED  0x8000          /* Referenced */
+
+/* Combined stuff */
+#define SF_UNDEFMASK   (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
+#define SF_UNDEFVAL    (SF_REFERENCED)
+#define SF_IMPMASK     (SF_TRAMPOLINE | SF_IMPORT | SF_REFERENCED)
+#define SF_IMPVAL      (SF_IMPORT | SF_REFERENCED)
+#define SF_EXPMASK     (SF_TRAMPOLINE | SF_EXPORT)
+#define SF_EXPVAL      (SF_EXPORT)
+#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
+#define SF_DBGINFOVAL  (SF_DEFINED)
+
+
+
+/* Structure of a symbol table entry */
+struct SymEntry_ {
+    SymEntry*                      Left;       /* Lexically smaller entry */
+    SymEntry*              Right;      /* Lexically larger entry */
+    SymEntry*              List;       /* List of all entries */
+    SymEntry*                      Locals;     /* Root of subtree for local symbols */
+    struct SymTable_*      SymTab;     /* Table this symbol is in, 0 for locals */
+    FilePos                        Pos;        /* File position for this symbol */
+    unsigned                Flags;     /* Symbol flags */
+    unsigned               Index;      /* Index of import/export entries */
+    union {
+        struct ExprNode_*   Expr;              /* Expression if CONST not set */
+       long                Val;        /* Value (if CONST set) */
+       SymEntry*           Sym;        /* Symbol (if trampoline entry) */
+    } V;
+    char                           Name [1];   /* Dynamic allocation */
+};
+
+
+
+/* Definitions for the hash table */
+#define MAIN_HASHTAB_SIZE      213
+#define SUB_HASHTAB_SIZE       53
+typedef struct SymTable_ SymTable;
+struct SymTable_ {
+    unsigned           TableSlots;     /* Number of hash table slots */
+    unsigned           TableEntries;   /* Number of entries in the table */
+    SymTable*          BackLink;       /* Link to enclosing scope if any */
+    SymEntry*          Table [1];      /* Dynamic allocation */
+};
+
+
+
+/* Symbol table variables */
+static SymEntry*               SymList = 0;    /* List of all symbol table entries */
+static SymEntry*       SymLast = 0;    /* Pointer to last defined symbol */
+static SymTable*       SymTab  = 0;    /* Pointer to current symbol table */
+static SymTable*       RootTab = 0;    /* Root symbol table */
+static unsigned                ImportCount = 0;/* Counter for import symbols */
+static unsigned        ExportCount = 0;/* Counter for export symbols */
+
+
+
+/*****************************************************************************/
+/*                                Internally used functions                         */
+/*****************************************************************************/
+
+
+
+static int IsLocal (const char* Name)
+/* Return true if Name is the name of a local symbol */
+{
+    return (*Name == LocalStart);
+}
+
+
+
+static SymEntry* NewSymEntry (const char* Name)
+/* Allocate a symbol table entry, initialize and return it */
+{
+    SymEntry* S;
+    unsigned Len;
+
+    /* Get the length of the name */
+    Len = strlen (Name);
+
+    /* Allocate memory */
+    S = Xmalloc (sizeof (SymEntry) + Len);
+
+    /* Initialize the entry */
+    S->Left   = 0;
+    S->Right  = 0;
+    S->Locals = 0;
+    S->SymTab = 0;
+    S->Flags  = 0;
+    S->V.Expr = 0;
+    S->Pos    = CurPos;
+    memcpy (S->Name, Name, Len+1);
+
+    /* Insert it into the list of all entries */
+    S->List = SymList;
+    SymList = S;
+
+    /* Return the initialized entry */
+    return S;
+}
+
+
+
+static SymTable* NewSymTable (unsigned Size)
+/* Allocate a symbol table on the heap and return it */
+{
+    SymTable* S;
+
+    /* Allocate memory */
+    S = Xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
+
+    /* Set variables and clear hash table entries */
+    S->TableSlots   = Size;
+    S->TableEntries = 0;
+    S->BackLink     = 0;
+    while (Size--) {
+       S->Table [Size] = 0;
+    }
+
+    /* Return the prepared struct */
+    return S;
+}
+
+
+
+static int SearchSymTab (SymEntry* T, const char* Name, SymEntry** E)
+/* Search in the given table for a name (Hash is the hash value of Name and
+ * is given as parameter so that it will not get calculated twice if we search
+ * in more than one table). If we find the symbol, the function will return 0
+ * and put the entry pointer into E. If we did not find the symbol, and the
+ * tree is empty, E is set to NULL. If the tree is not empty, E will be set to
+ * the last entry, and the result of the function is <0 if the entry should
+ * be inserted on the left side, and >0 if it should get inserted on the right
+ * side.
+ */
+{
+    int Cmp;
+
+    /* Is there a tree? */
+    if (T == 0) {
+       *E = 0;
+       return 1;
+    }
+
+    /* We have a table, search it */
+    while (1) {
+       /* Choose next entry */
+       Cmp = strcmp (Name, T->Name);
+       if (Cmp < 0 && T->Left) {
+           T = T->Left;
+       } else if (Cmp > 0 && T->Right) {
+           T = T->Right;
+       } else {
+           /* Found or end of search */
+           break;
+               }
+    }
+
+    /* Return the search result */
+    *E = T;
+    return Cmp;
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static SymEntry* SymFind (SymTable* Tab, const char* Name, int AllocNew)
+/* Find a new symbol table entry in the given table. If AllocNew is given and
+ * the entry is not found, create a new one. Return the entry found, or the
+ * new entry created, or - in case AllocNew is zero - return 0.
+ */
+{
+    SymEntry* S;
+    int Cmp;
+    unsigned Hash;
+
+    if (IsLocal (Name)) {
+
+       /* Local symbol, get the table */
+       if (!SymLast) {
+           /* No last global, so there's no local table */
+           Error (ERR_ILLEGAL_LOCAL_USE);
+           if (AllocNew) {
+               return NewSymEntry (Name);
+           } else {
+               return 0;
+           }
+               }
+
+       /* Search for the symbol if we have a table */
+        Cmp = SearchSymTab (SymLast->Locals, Name, &S);
+
+       /* If we found an entry, return it */
+       if (Cmp == 0) {
+           return S;
+       }
+
+       if (AllocNew) {
+
+           /* Otherwise create a new entry, insert and return it */
+           SymEntry* N = NewSymEntry (Name);
+           if (S == 0) {
+               SymLast->Locals = N;
+           } else if (Cmp < 0) {
+               S->Left = N;
+           } else {
+               S->Right = N;
+           }
+           return N;
+       }
+
+    } else {
+
+       /* Global symbol: Get the hash value for the name */
+       Hash = HashStr (Name) % Tab->TableSlots;
+
+       /* Search for the entry */
+       Cmp = SearchSymTab (Tab->Table [Hash], Name, &S);
+
+       /* If we found an entry, return it */
+       if (Cmp == 0) {
+           /* Check for a trampoline entry, in this case return the real
+            * symbol.
+            */
+           if (S->Flags & SF_TRAMPOLINE) {
+               return S->V.Sym;
+           } else {
+               return S;
+           }
+       }
+
+       if (AllocNew) {
+
+           /* Otherwise create a new entry, insert and return it */
+           SymEntry* N = NewSymEntry (Name);
+           if (S == 0) {
+               Tab->Table [Hash] = N;
+           } else if (Cmp < 0) {
+               S->Left = N;
+           } else {
+               S->Right = N;
+           }
+                   N->SymTab = Tab;
+           ++Tab->TableEntries;
+           return N;
+
+       }
+    }
+
+    /* We did not find the entry and AllocNew is false. */
+    return 0;
+}
+
+
+
+static SymEntry* SymFindAny (SymTable* Tab, const char* Name)
+/* Find a symbol in any table */
+{
+    SymEntry* Sym;
+    do {
+       /* Search in the current table */
+       Sym = SymFind (Tab, Name, 0);
+       if (Sym) {
+           /* Found, return it */
+           return Sym;
+       } else {
+           /* Not found, search in the backlink, if we have one */
+           Tab = Tab->BackLink;
+       }
+    } while (Sym == 0 && Tab != 0);
+
+    /* Not found */
+    return 0;
+}
+
+
+
+static SymEntry* SymRefInternal (SymTable* Table, const char* Name)
+/* Search for the symbol in the given table and return it */
+{
+    SymEntry* S;
+
+    /* Try to find the symbol, create a new one if the symbol does not exist */
+    S = SymFind (Table, Name, 1);
+
+    /* Mark the symbol as referenced */
+    S->Flags |= SF_REFERENCED;
+
+    /* Return it */
+    return S;
+}
+
+
+
+void SymEnterLevel (void)
+/* Enter a new lexical level */
+{
+    if (RootTab == 0) {
+               /* Create the main symbol table */
+               RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
+    } else {
+               /* Create a local symbol table */
+               SymTable* LocalSyms;
+       LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
+       LocalSyms->BackLink = SymTab;
+               SymTab = LocalSyms;
+    }
+}
+
+
+
+void SymLeaveLevel (void)
+/* Leave the current lexical level */
+{
+    SymTab = SymTab->BackLink;
+}
+
+
+
+void SymDef (const char* Name, ExprNode* Expr, int ZP)
+/* Define a new symbol */
+{
+    SymEntry* S;
+
+    /* Do we have such a symbol? */
+    S = SymFind (SymTab, Name, 1);
+    if (S->Flags & SF_IMPORT) {
+               /* Defined symbol is marked as imported external symbol */
+               Error (ERR_SYM_ALREADY_IMPORT);
+               return;
+    }
+    if (S->Flags & SF_DEFINED) {
+               /* Multiple definition */
+               Error (ERR_SYM_ALREADY_DEFINED, Name);
+               S->Flags |= SF_MULTDEF;
+               return;
+    }
+
+    /* Set the symbol data */
+    if (IsConstExpr (Expr)) {
+               /* Expression is const, store the value */
+               S->Flags |= SF_CONST;
+               S->V.Val = GetExprVal (Expr);
+               FreeExpr (Expr);
+    } else {
+               /* Not const, store the expression */
+        S->V.Expr  = Expr;
+    }
+    S->Flags |= SF_DEFINED;
+    if (ZP) {
+       S->Flags |= SF_ZP;
+    }
+
+    /* If the symbol is a ZP symbol, check if the value is in correct range */
+    if (S->Flags & SF_ZP) {
+       /* Already marked as ZP symbol by some means */
+       if (!IsByteExpr (Expr)) {
+           Error (ERR_RANGE);
+       }
+    }
+
+    /* If this is not a local symbol, remember it as the last global one */
+    if (!IsLocal (Name)) {
+               SymLast = S;
+    }
+}
+
+
+
+SymEntry* SymRef (const char* Name)
+/* Search for the symbol and return it */
+{
+    /* Reference the symbol in the current table */
+    return SymRefInternal (SymTab, Name);
+}
+
+
+
+SymEntry* SymRefGlobal (const char* Name)
+/* Search for the symbol in the global namespace and return it */
+{
+    /* Reference the symbol in the current table */
+    return SymRefInternal (RootTab, Name);
+}
+
+
+
+void SymImport (const char* Name, int ZP)
+/* Mark the given symbol as an imported symbol */
+{
+    SymEntry* S;
+
+    /* Don't accept local symbols */
+    if (IsLocal (Name)) {
+       Error (ERR_ILLEGAL_LOCAL_USE);
+       return;
+    }
+
+    /* Do we have such a symbol? */
+    S = SymFind (SymTab, Name, 1);
+    if (S->Flags & SF_DEFINED) {
+       Error (ERR_SYM_ALREADY_DEFINED, Name);
+       S->Flags |= SF_MULTDEF;
+       return;
+    }
+    if (S->Flags & SF_EXPORT) {
+       /* The symbol is already marked as exported symbol */
+       Error (ERR_SYM_ALREADY_EXPORT);
+       return;
+    }
+
+    /* If the symbol is marked as global, check the symbol size, then do
+     * silently remove the global flag
+     */
+    if (S->Flags & SF_GLOBAL) {
+       if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+           Error (ERR_SYM_REDECL_MISMATCH);
+       }
+        S->Flags &= ~SF_GLOBAL;
+    }
+
+    /* Set the symbol data */
+    S->Flags |= SF_IMPORT;
+    if (ZP) {
+       S->Flags |= SF_ZP;
+    }
+}
+
+
+
+void SymExport (const char* Name, int ZP)
+/* Mark the given symbol as an exported symbol */
+{
+    SymEntry* S;
+
+    /* Don't accept local symbols */
+    if (IsLocal (Name)) {
+       Error (ERR_ILLEGAL_LOCAL_USE);
+       return;
+    }
+
+    /* Do we have such a symbol? */
+    S = SymFind (SymTab, Name, 1);
+    if (S->Flags & SF_IMPORT) {
+       /* The symbol is already marked as imported external symbol */
+       Error (ERR_SYM_ALREADY_IMPORT);
+       return;
+    }
+
+    /* If the symbol is marked as global, check the symbol size, then do
+     * silently remove the global flag
+     */
+    if (S->Flags & SF_GLOBAL) {
+       if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+           Error (ERR_SYM_REDECL_MISMATCH);
+       }
+        S->Flags &= ~SF_GLOBAL;
+    }
+
+    /* Set the symbol data */
+    S->Flags |= SF_EXPORT | SF_REFERENCED;
+    if (ZP) {
+       S->Flags |= SF_ZP;
+    }
+}
+
+
+
+void SymGlobal (const char* Name, int ZP)
+/* Mark the given symbol as a global symbol, that is, as a symbol that is
+ * either imported or exported.
+ */
+{
+    SymEntry* S;
+
+    /* Don't accept local symbols */
+    if (IsLocal (Name)) {
+       Error (ERR_ILLEGAL_LOCAL_USE);
+       return;
+    }
+
+    /* Search for this symbol, create a new entry if needed */
+    S = SymFind (SymTab, Name, 1);
+
+    /* If the symbol is already marked as import or export, check the
+     * size of the definition, then bail out. */
+    if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
+       if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+           Error (ERR_SYM_REDECL_MISMATCH);
+       }
+       return;
+    }
+
+    /* Mark the symbol */
+    S->Flags |= SF_GLOBAL;
+    if (ZP) {
+       S->Flags |= SF_ZP;
+    }
+}
+
+
+
+int SymIsDef (const char* Name)
+/* Return true if the given symbol is already defined */
+{
+    SymEntry* S = SymFindAny (SymTab, Name);
+    return S != 0 && (S->Flags & (SF_DEFINED | SF_IMPORT)) != 0;
+}
+
+
+
+int SymIsRef (const char* Name)
+/* Return true if the given symbol has been referenced */
+{
+    SymEntry* S = SymFindAny (SymTab, Name);
+    return S != 0 && (S->Flags & SF_REFERENCED) != 0;
+}
+
+
+
+int SymIsConst (SymEntry* S)
+/* Return true if the given symbol has a constant value */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Check for constness */
+    if (S->Flags & SF_CONST) {
+       return 1;
+    } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
+       /* Constant expression, remember the value */
+       ExprNode* Expr = S->V.Expr;
+               S->Flags |= SF_CONST;
+       S->V.Val = GetExprVal (Expr);
+       FreeExpr (Expr);
+       return 1;
+    }
+    return 0;
+}
+
+
+
+int SymIsZP (SymEntry* S)
+/* Return true if the symbol is explicitly marked as zeropage symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* If the symbol is not a global symbol, was not defined before, check the
+     * enclosing scope for a symbol with the same name, and return the ZP
+     * attribute of this symbol if we find one.
+     */
+    if (!IsLocal (S->Name)                                             &&
+       (S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0     &&
+       S->SymTab->BackLink != 0) {
+
+       /* Try to find a symbol with the same name in the enclosing scope */
+       SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
+
+       /* If we found one, use the ZP flag */
+       if (E && (E->Flags & SF_ZP) != 0) {
+           S->Flags |= SF_ZP;
+       }
+    }
+
+    /* Check the ZP flag */
+    return (S->Flags & SF_ZP) != 0;
+}
+
+
+
+int SymIsImport (SymEntry* S)
+/* Return true if the given symbol is marked as import */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Check the import flag */
+    return (S->Flags & SF_IMPORT) != 0;
+}
+
+
+
+int SymHasExpr (SymEntry* S)
+/* Return true if the given symbol has an associated expression */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Check the expression */
+    return ((S->Flags & SF_DEFINED) != 0 &&
+           (S->Flags & SF_IMPORT)  == 0 &&
+           (S->Flags & SF_CONST)   == 0);
+}
+
+
+
+void SymFinalize (SymEntry* S)
+/* Finalize a symbol expression if there is one */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Check if we have an expression */
+    if (SymHasExpr (S)) {
+       S->V.Expr = FinalizeExpr (S->V.Expr);
+    }
+}
+
+
+
+void SymMarkUser (SymEntry* S)
+/* Set a user mark on the specified symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Set the bit */
+    S->Flags |= SF_USER;
+}
+
+
+
+void SymUnmarkUser (SymEntry* S)
+/* Remove a user mark from the specified symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Reset the bit */
+    S->Flags &= ~SF_USER;
+}
+
+
+
+int SymHasUserMark (SymEntry* S)
+/* Return the state of the user mark for the specified symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    /* Check the bit */
+    return (S->Flags & SF_USER) != 0;
+}
+
+
+
+long GetSymVal (SymEntry* S)
+/* Return the symbol value */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
+    return S->V.Val;
+}
+
+
+
+ExprNode* GetSymExpr (SymEntry* S)
+/* Get the expression for a non-const symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+
+    PRECONDITION (S != 0 && (S->Flags & SF_CONST) == 0);
+    return S->V.Expr;
+}
+
+
+
+const char* GetSymName (SymEntry* S)
+/* Return the name of the symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+    return S->Name;
+}
+
+
+
+unsigned GetSymIndex (SymEntry* S)
+/* Return the symbol index for the given symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+    PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
+    return S->Index;
+}
+
+
+
+const FilePos* GetSymPos (SymEntry* S)
+/* Return the position of first occurence in the source for the given symbol */
+{
+    /* Resolve trampoline entries */
+    if (S->Flags & SF_TRAMPOLINE) {
+       S = S->V.Sym;
+    }
+    PRECONDITION (S != 0);
+    return &S->Pos;
+}
+
+
+
+static void SymCheckUndefined (SymEntry* S)
+/* Handle an undefined symbol */
+{
+    /* Undefined symbol. It may be...
+     *
+     *   - An undefined symbol in a nested lexical level. In this
+     *     case, search for the symbol in the higher levels and
+     *            make the entry a trampoline entry if we find one.
+     *
+     *   - If the symbol is not found, it is a real undefined symbol.
+     *     If the AutoImport flag is set, make it an import. If the
+     *     AutoImport flag is not set, it's an error.
+     */
+    SymEntry* Sym = 0;
+    if (S->SymTab) {
+       /* It's a global symbol, get the higher level table */
+       SymTable* Tab = S->SymTab->BackLink;
+       while (Tab) {
+           Sym = SymFindAny (Tab, S->Name);
+           if (Sym) {
+               if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
+                   /* We've found a symbol in a higher level that is
+                    * either defined in the source, or an import.
+                    */
+                    break;
+               } else {
+                   /* The symbol found is undefined itself. Look further */
+                   Tab = Sym->SymTab->BackLink;
+               }
+           } else {
+               /* No symbol found */
+               break;
+           }
+       }
+    }
+    if (Sym) {
+       /* We found the symbol in a higher level. Make S a trampoline
+        * symbol. Beware: We have to transfer the symbol attributes to
+        * the real symbol and check for any conflicts.
+        */
+       S->Flags |= SF_TRAMPOLINE;
+       S->V.Sym = Sym;
+
+       /* Transfer the flags. Note: S may not be imported, since in that
+        * case it wouldn't be undefined.
+        */
+               if (S->Flags & SF_EXPORT) {
+           if (Sym->Flags & SF_IMPORT) {
+               /* The symbol is already marked as imported external symbol */
+               PError (&S->Pos, ERR_SYM_ALREADY_IMPORT);
+           }
+           Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
+       }
+
+       /* Transfer the referenced flag */
+       Sym->Flags |= (S->Flags & SF_REFERENCED);
+
+    } else {
+       /* The symbol is definitely undefined */
+       if (S->Flags & SF_EXPORT) {
+           /* We will not auto-import an export */
+           PError (&S->Pos, ERR_EXPORT_UNDEFINED, S->Name);
+       } else {
+           if (AutoImport) {
+               /* Mark as import, will be indexed later */
+               S->Flags |= SF_IMPORT;
+           } else {
+               /* Error */
+               PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
+           }
+       }
+    }
+}
+
+
+
+void SymCheck (void)
+/* Run through all symbols and check for anomalies and errors */
+{
+    SymEntry* S;
+
+    /* Check for open lexical levels */
+    if (SymTab->BackLink != 0) {
+       Error (ERR_OPEN_PROC);
+    }
+
+    /* First pass: Walk through all symbols, checking for undefined's and
+     * changing them to trampoline symbols or make them imports.
+     */
+    S = SymList;
+    while (S) {
+       /* If the symbol is marked as global, mark it as export, if it is
+        * already defined, otherwise mark it as import.
+        */
+       if (S->Flags & SF_GLOBAL) {
+           S->Flags &= ~SF_GLOBAL;
+           if (S->Flags & SF_DEFINED) {
+               S->Flags |= SF_EXPORT;
+           } else {
+               S->Flags |= SF_IMPORT;
+           }
+       }
+
+       /* Handle undefined symbols */
+               if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
+           /* This is an undefined symbol. Handle it. */
+           SymCheckUndefined (S);
+       }
+
+       /* Next symbol */
+       S = S->List;
+    }
+
+    /* Second pass: Walk again through the symbols. Ignore undefined's, since
+     * we handled them in the last pass, and ignore trampoline symbols, since
+     * we handled them in the last pass, too.
+     */
+    S = SymList;
+    while (S) {
+       if ((S->Flags & SF_TRAMPOLINE) == 0 &&
+           (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+           if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
+               /* Symbol was defined but never referenced */
+               PWarning (&S->Pos, WARN_SYM_NOT_REFERENCED, S->Name);
+           }
+           if (S->Flags & SF_IMPORT) {
+               if ((S->Flags & SF_REFERENCED) == 0) {
+                   /* Imported symbol is not referenced */
+                   PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, S->Name);
+               } else {
+                   /* Give the import an index, count imports */
+                   S->Index = ImportCount++;
+                   S->Flags |= SF_INDEXED;
+               }
+           }
+           if (S->Flags & SF_EXPORT) {
+               /* Give the export an index, count exports */
+               S->Index = ExportCount++;
+               S->Flags |= SF_INDEXED;
+           }
+       }
+
+       /* Next symbol */
+       S = S->List;
+    }
+}
+
+
+
+void SymDump (FILE* F)
+/* Dump the symbol table */
+{
+    SymEntry* S = SymList;
+
+    while (S) {
+       /* Ignore trampoline symbols */
+       if ((S->Flags & SF_TRAMPOLINE) != 0) {
+           printf ("%-24s %s %s %s %s %s\n",
+                   S->Name,
+                   (S->Flags & SF_DEFINED)? "DEF" : "---",
+                   (S->Flags & SF_REFERENCED)? "REF" : "---",
+                   (S->Flags & SF_IMPORT)? "IMP" : "---",
+                   (S->Flags & SF_EXPORT)? "EXP" : "---",
+                   (S->Flags & SF_ZP)? "ZP" : "--");
+       }
+       /* Next symbol */
+       S = S->List;
+    }
+}
+
+
+
+void WriteImports (void)
+/* Write the imports list to the object file */
+{
+    SymEntry* S;
+
+    /* Tell the object file module that we're about to start the imports */
+    ObjStartImports ();
+
+    /* Write the import count to the list */
+    ObjWrite16 (ImportCount);
+
+    /* Walk throught list and write all imports to the file */
+    S = SymList;
+    while (S) {
+       if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
+           if (S->Flags & SF_ZP) {
+               ObjWrite8 (IMP_ZP);
+           } else {
+               ObjWrite8 (IMP_ABS);
+           }
+                   ObjWriteStr (S->Name);
+           ObjWritePos (&S->Pos);
+       }
+       S = S->List;
+    }
+
+    /* Done writing imports */
+    ObjEndImports ();
+}
+
+
+
+void WriteExports (void)
+/* Write the exports list to the object file */
+{
+    SymEntry* S;
+
+    /* Tell the object file module that we're about to start the exports */
+    ObjStartExports ();
+
+    /* Write the export count to the list */
+    ObjWrite16 (ExportCount);
+
+    /* Walk throught list and write all exports to the file */
+    S = SymList;
+    while (S) {
+               if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
+                   unsigned char ExprMask;
+
+           /* Finalize an associated expression if we have one */
+           SymFinalize (S);
+
+           /* Check if the symbol is const */
+           ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+
+           /* Write the type */
+           if (S->Flags & SF_ZP) {
+               ObjWrite8 (EXP_ZP | ExprMask);
+           } else {
+               ObjWrite8 (EXP_ABS | ExprMask);
+           }
+                   ObjWriteStr (S->Name);
+           if (ExprMask == EXP_CONST) {
+               /* Constant value */
+               ObjWrite32 (S->V.Val);
+           } else {
+               /* Expression involved */
+               WriteExpr (S->V.Expr);
+            }
+           ObjWritePos (&S->Pos);
+       }
+       S = S->List;
+    }
+
+    /* Done writing exports */
+    ObjEndExports ();
+}
+
+
+
+void WriteDbgSyms (void)
+/* Write a list of all symbols to the object file */
+{
+    unsigned Count;
+    SymEntry* S;
+
+    /* Tell the object file module that we're about to start the debug info */
+    ObjStartDbgSyms ();
+
+    /* Check if debug info is requested */
+    if (DbgSyms) {
+
+       /* Walk through the list and count the symbols */
+       Count = 0;
+       S = SymList;
+       while (S) {
+           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+               ++Count;
+           }
+           S = S->List;
+       }
+
+       /* Safety check */
+       if (Count > 0xFFFF) {
+           Fatal (FAT_TOO_MANY_SYMBOLS);
+       }
+
+       /* Write the symbol count to the list */
+       ObjWrite16 (Count);
+
+               /* Walk through list and write all symbols to the file */
+       S = SymList;
+       while (S) {
+           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+               unsigned char ExprMask;
+
+               /* Finalize an associated expression if we have one */
+               SymFinalize (S);
+
+               /* Check if the symbol is const */
+               ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+
+               /* Write the type */
+               if (S->Flags & SF_ZP) {
+                   ObjWrite8 (EXP_ZP | ExprMask);
+               } else {
+                   ObjWrite8 (EXP_ABS | ExprMask);
+               }
+               ObjWriteStr (S->Name);
+               if (ExprMask == EXP_CONST) {
+                   /* Constant value */
+                   ObjWrite32 (S->V.Val);
+               } else {
+                   /* Expression involved */
+                   WriteExpr (S->V.Expr);
+               }
+               ObjWritePos (&S->Pos);
+           }
+           S = S->List;
+       }
+
+    } else {
+
+       /* No debug symbols */
+       ObjWrite16 (0);
+
+    }
+
+    /* Done writing debug symbols */
+    ObjEndDbgSyms ();
+}
+
+
+
diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h
new file mode 100644 (file)
index 0000000..1d29ec8
--- /dev/null
@@ -0,0 +1,145 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                symtab.h                                  */
+/*                                                                           */
+/*                Symbol table for the ca65 macroassembler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SYMTAB_H
+#define SYMTAB_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void SymEnterLevel (void);
+/* Enter a new lexical level */
+
+void SymLeaveLevel (void);
+/* Leave the current lexical level */
+
+void SymDef (const char* Name, ExprNode* Expr, int ZP);
+/* Define a new symbol */
+
+SymEntry* SymRef (const char* Name);
+/* Search for the symbol and return it */
+
+SymEntry* SymRefGlobal (const char* Name);
+/* Search for the symbol in the global namespace and return it */
+
+int SymIsDef (const char* Name);
+/* Return true if the given symbol is already defined */
+
+int SymIsRef (const char* Name);
+/* Return true if the given symbol has been referenced */
+
+void SymImport (const char* Name, int ZP);
+/* Mark the given symbol as an imported symbol */
+
+void SymExport (const char* Name, int ZP);
+/* Mark the given symbol as an exported symbol */
+
+void SymGlobal (const char* Name, int ZP);
+/* Mark the given symbol as a global symbol, that is, as a symbol that is
+ * either imported or exported.
+ */
+
+int SymIsConst (SymEntry* Sym);
+/* Return true if the given symbol has a constant value */
+
+int SymIsZP (SymEntry* Sym);
+/* Return true if the symbol is explicitly marked as zeropage symbol */
+
+int SymIsImport (SymEntry* Sym);
+/* Return true if the given symbol is marked as import */
+
+int SymHasExpr (SymEntry* Sym);
+/* Return true if the given symbol has an associated expression */
+
+void SymMarkUser (SymEntry* Sym);
+/* Set a user mark on the specified symbol */
+
+void SymUnmarkUser (SymEntry* Sym);
+/* Remove a user mark from the specified symbol */
+
+int SymHasUserMark (SymEntry* Sym);
+/* Return the state of the user mark for the specified symbol */
+
+long GetSymVal (SymEntry* Sym);
+/* Return the symbol value */
+
+ExprNode* GetSymExpr (SymEntry* Sym);
+/* Get the expression for a non-const symbol */
+
+const char* GetSymName (SymEntry* Sym);
+/* Return the name of the symbol */
+
+unsigned GetSymIndex (SymEntry* Sym);
+/* Return the symbol index for the given symbol */
+
+const FilePos* GetSymPos (SymEntry* Sym);
+/* Return the position of first occurence in the source for the given symbol */
+
+void SymCheck (void);
+/* Run through all symbols and check for anomalies and errors */
+
+void SymDump (FILE* F);
+/* Dump the symbol table */
+
+void WriteImports (void);
+/* Write the imports list to the object file */
+
+void WriteExports (void);
+/* Write the exports list to the object file */
+
+void WriteDbgSyms (void);
+/* Write a list of all symbols to the object file */
+
+
+
+/* End of symtab.h */
+
+#endif
+
+
+
diff --git a/src/ca65/toknode.c b/src/ca65/toknode.c
new file mode 100644 (file)
index 0000000..b1eeb8b
--- /dev/null
@@ -0,0 +1,117 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                toknode.c                                 */
+/*                                                                           */
+/*               Token list node for the ca65 macroassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "scanner.h"
+#include "toknode.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+TokNode* NewTokNode (void)
+/* Create and return a token node with the current token value */
+{
+    TokNode* T;
+
+    /* Allocate memory */
+    unsigned Len = TokHasSVal (Tok)? strlen (SVal) : 0;
+    T = Xmalloc (sizeof (TokNode) + Len);
+
+    /* Initialize the token contents */
+    T->Next    = 0;
+    T->Tok     = Tok;
+    T->WS      = WS;
+    T->IVal    = IVal;
+    memcpy (T->SVal, SVal, Len);
+    T->SVal [Len] = '\0';
+
+    /* Return the node */
+    return T;
+}
+
+
+
+void FreeTokNode (TokNode* T)
+/* Free the given token node */
+{
+    Xfree (T);
+}
+
+
+
+void TokSet (TokNode* T)
+/* Set the scanner token from the given token node */
+{
+    /* Set the values */
+    Tok  = T->Tok;
+    WS   = T->WS;
+    IVal = T->IVal;
+    strcpy (SVal, T->SVal);
+}
+
+
+
+enum TC TokCmp (const TokNode* T)
+/* Compare the token given as parameter against the current token */
+{
+    if (T->Tok != Tok) {
+       /* Different token */
+       return tcDifferent;
+    }
+     
+    /* If the token has string attribute, check it */
+    if (TokHasSVal (T->Tok)) {
+       if (strcmp  (T->SVal, SVal) != 0) {
+           return tcSameToken;
+       }
+    } else if (TokHasIVal (T->Tok)) {
+       if (T->IVal != IVal) {
+           return tcSameToken;
+       }
+    }
+        
+    /* Tokens are identical */
+    return tcIdentical;
+}
+
+
+
diff --git a/src/ca65/toknode.h b/src/ca65/toknode.h
new file mode 100644 (file)
index 0000000..e3580e2
--- /dev/null
@@ -0,0 +1,94 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                toknode.h                                 */
+/*                                                                           */
+/*               Token list node for the ca65 macroassembler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef TOKNODE_H
+#define TOKNODE_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Struct holding a token */
+typedef struct TokNode_ TokNode;
+struct TokNode_ {
+    TokNode*                   Next;           /* For single linked list */
+    enum Token         Tok;            /* Token value */
+    int                        WS;             /* Whitespace before token? */
+    long                       IVal;           /* Integer token attribute */
+    char                       SVal [1];       /* String attribute, dyn. allocated */
+};
+
+
+
+/* Return codes for TokCmp - higher numeric code means better match */
+enum TC {
+    tcDifferent,                       /* Different tokents */
+    tcSameToken,                       /* Same token, different attribute */
+    tcIdentical                                /* Identical (token + attribute) */
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+TokNode* NewTokNode (void);
+/* Create and return a token node with the current token value */
+
+void FreeTokNode (TokNode* T);
+/* Free the given token node */
+
+void TokSet (TokNode* T);
+/* Set the scanner token from the given token node */
+
+enum TC TokCmp (const TokNode* T);
+/* Compare the token given as parameter against the current token */
+
+
+
+/* End of toknode.h */
+
+#endif
+
+
+
+
diff --git a/src/ca65/ulabel.c b/src/ca65/ulabel.c
new file mode 100644 (file)
index 0000000..adfe2e5
--- /dev/null
@@ -0,0 +1,242 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                ulabel.c                                  */
+/*                                                                           */
+/*               Unnamed labels for the ca65 macroassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "../common/filepos.h"
+
+#include "error.h"
+#include "expr.h"
+#include "mem.h"
+#include "scanner.h"
+#include "ulabel.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Struct that describes an unnamed label */
+typedef struct ULabel_ ULabel;
+struct ULabel_ {
+    ULabel*            Prev;                   /* Pointer to previous node in list */
+    ULabel*            Next;                   /* Pointer to next node in list */
+    FilePos    Pos;                    /* Position of the label in the source */
+    ExprNode*  Val;                    /* The label value - may be NULL */
+};
+
+/* List management */
+static ULabel*  ULabRoot               = 0;    /* Root of the list */
+static ULabel*  ULabLast       = 0;    /* Last ULabel */
+static ULabel*  ULabLastDef    = 0;    /* Last defined ULabel */
+static unsigned        ULabCount       = 0;    /* Number of labels */
+static unsigned ULabDefCount   = 0;    /* Number of defined labels */
+static ULabel** ULabList       = 0;    /* Array with pointers to all labels */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static ULabel* NewULabel (ExprNode* Val)
+/* Create a new ULabel and insert it into the list. The function will move
+ * ULabelLast, but not ULabelLastDef. The created label structure is returned.
+ */
+{
+    /* Allocate memory for the ULabel structure */
+    ULabel* L = Xmalloc (sizeof (ULabel));
+
+    /* Initialize the fields */
+    L->Pos = CurPos;
+    L->Val = Val;
+
+    /* Insert the label into the list */
+    L->Next = 0;
+    if (ULabRoot == 0) {
+       /* First label */
+       L->Prev = 0;
+       ULabRoot = L;
+    } else {
+       ULabLast->Next = L;
+       L->Prev = ULabLast;
+    }
+    ULabLast = L;
+
+    /* One label more */
+    ++ULabCount;
+
+    /* Return the created label */
+    return L;
+}
+
+
+
+ExprNode* ULabRef (int Which)
+/* Get an unnamed label. If Which is negative, it is a backreference (a
+ * reference to an already defined label), and the function will return a
+ * segment relative expression. If Which is positive, it is a forward ref,
+ * and the function will return a expression node for an unnamed label that
+ * must be resolved later.
+ */
+{
+    ULabel* L;
+
+    /* Which can never be 0 */
+    PRECONDITION (Which != 0);
+
+    /* Which is never really big (usually -3..+3), so a linear search is
+     * the best we can do here.
+     */
+    L = ULabLastDef;
+    if (Which < 0) {
+       /* Backward reference */
+       while (Which < -1 && L != 0) {
+           L = L->Prev;
+           ++Which;
+       }
+       if (L == 0) {
+           /* Label does not exist */
+           Error (ERR_UNDEFINED_LABEL);
+           /* We must return something valid */
+           return CurrentPC();
+       } else {
+           /* Return a copy of the label value */
+           return CloneExpr (L->Val);
+       }
+    } else {
+       /* Forward reference. Create labels as needed */
+       unsigned LabelNum = ULabDefCount + Which - 1;
+       while (Which > 0) {
+           if (L->Next == 0) {
+               NewULabel (0);
+           }
+           L = L->Next;
+           --Which;
+       }
+       /* Return an unnamed label expression */
+               return ULabelExpr (LabelNum);
+    }
+}
+
+
+
+void ULabDef (void)
+/* Define an unnamed label at the current PC */
+{
+    /* Create a new label if needed, or use an existing one */
+    if (ULabLastDef == 0 || ULabLastDef->Next == 0) {
+       /* The last label is also the last defined label, we need a new one */
+       ULabLastDef = NewULabel (CurrentPC ());
+    } else {
+       /* We do already have the label, but it's undefined until now */
+       ULabLastDef = ULabLastDef->Next;
+       ULabLastDef->Val = CurrentPC ();
+       ULabLastDef->Pos = CurPos;
+    }
+    ++ULabDefCount;
+}
+
+
+
+int ULabCanResolve (void)
+/* Return true if we can resolve arbitrary ULabels. */
+{
+    /* We can resolve labels if we have built the necessary access array */
+    return (ULabList != 0);
+}
+
+
+
+ExprNode* ULabResolve (unsigned Index)
+/* Return a valid expression for the unnamed label with the given index. This
+ * is used to resolve unnamed labels when assembly is done, so it is an error
+ * if a label is still undefined in this phase.
+ */
+{
+    ULabel* L;
+
+    /* Must be in resolve phase and the index must be valid */
+    CHECK (ULabList != 0 && Index < ULabCount);
+
+    /* Get the label */
+    L = ULabList [Index];
+
+    /* If the label is open (not defined), return some valid value */
+    if (L->Val == 0) {
+       return LiteralExpr (0);
+    } else {
+       return CloneExpr (L->Val);
+    }
+}
+
+
+
+void ULabCheck (void)
+/* Run through all unnamed labels and check for anomalies and errors */
+{
+    ULabel* L;
+
+    /* Check if there are undefined labels */
+    if (ULabLastDef) {
+       L = ULabLastDef->Next;
+       while (L) {
+           PError (&L->Pos, ERR_UNDEFINED_LABEL);
+           L = L->Next;
+       }
+    }
+
+    /* Create an array that holds pointers to all labels. This allows us to
+     * access the labels quickly by index in the resolver phase at the end of
+     * the assembly.
+     */
+    if (ULabCount) {
+       unsigned I = 0;
+       ULabList = Xmalloc (ULabCount * sizeof (ULabel*));
+       L = ULabRoot;
+       while (L) {
+           ULabList[I] = L;
+           ++I;
+           L = L->Next;
+       }
+       CHECK (I == ULabCount);
+    }
+}
+
+
+
diff --git a/src/ca65/ulabel.h b/src/ca65/ulabel.h
new file mode 100644 (file)
index 0000000..ea2e467
--- /dev/null
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                ulabel.h                                  */
+/*                                                                           */
+/*               Unnamed labels for the ca65 macroassembler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ULABEL_H
+#define ULABEL_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ExprNode* ULabRef (int Which);
+/* Get an unnamed label. If Which is negative, it is a backreference (a
+ * reference to an already defined label), and the function will return a
+ * segment relative expression. If Which is positive, it is a forward ref,
+ * and the function will return a expression node for an unnamed label that
+ * must be resolved later.
+ */
+
+void ULabDef (void);
+/* Define an unnamed label at the current PC */
+
+int ULabCanResolve (void);
+/* Return true if we can resolve arbitrary ULabels. */
+
+ExprNode* ULabResolve (unsigned Index);
+/* Return a valid expression for the unnamed label with the given index. This
+ * is used to resolve unnamed labels when assembly is done, so it is an error
+ * if a label is still undefined in this phase.
+ */
+
+void ULabCheck (void);
+/* Run through all unnamed labels and check for anomalies and errors */
+
+
+
+/* End of ulabel.h */
+
+#endif
+
+
+
diff --git a/src/cc65/.cvsignore b/src/cc65/.cvsignore
new file mode 100644 (file)
index 0000000..a1b64fa
--- /dev/null
@@ -0,0 +1,29 @@
+.depend
+.kdbgrc.cc65
+cc65
+*.com
+*.map
+xopt
+predent
+postdent
+code-gen.m65
+glb.m65
+cc64
+error.m65
+expr1.m65
+expr2.m65
+save
+expr3.m65
+function.m65
+globlvar.m65
+io.m65
+lexer.m65
+main.m65
+optab1.m65
+optab2.m65
+optimize.m65
+preproc.m65
+rwords.m65
+stmt1.m65
+stmt2.m65
+symtab.m65
diff --git a/src/cc65/anonname.c b/src/cc65/anonname.c
new file mode 100644 (file)
index 0000000..1a52147
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               anonname.c                                 */
+/*                                                                           */
+/*               Create names for anonymous variables/types                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "anonname.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+char* AnonName (char* Buf, const char* Spec)
+/* Get a name for an anonymous variable or type. The given buffer is expected
+ * to be IDENTSIZE characters long. A pointer to the buffer is returned.
+ */
+{
+    static unsigned ACount = 0;
+    sprintf (Buf, "$anon-%s-%04X", Spec, ++ACount);
+    return Buf;
+}
+
+
+
diff --git a/src/cc65/anonname.h b/src/cc65/anonname.h
new file mode 100644 (file)
index 0000000..3f833f0
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               anonname.h                                 */
+/*                                                                           */
+/*               Create names for anonymous variables/types                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ANONNAME_H
+#define ANONNAME_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+char* AnonName (char* Buf, const char* Spec);
+/* Get a name for an anonymous variable or type. The given buffer is expected
+ * to be IDENTSIZE characters long. A pointer to the buffer is returned.
+ */
+
+
+
+/* End of anonname.h */
+#endif
+
+
+
diff --git a/src/cc65/asmcode.c b/src/cc65/asmcode.c
new file mode 100644 (file)
index 0000000..b62d36d
--- /dev/null
@@ -0,0 +1,115 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                asmcode.c                                 */
+/*                                                                           */
+/*         Assembler output code handling for the cc65 C compiler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "asmline.h"
+#include "check.h"
+#include "global.h"
+#include "asmcode.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void AddCodeLine (const char* Format, ...)
+/* Add a new line of code to the output */
+{
+    va_list ap;
+    va_start (ap, Format);
+    NewCodeLine (Format, ap);
+    va_end (ap);
+}
+
+
+
+void AddCodeHint (const char* Hint)
+/* Add an optimizer hint */
+{
+    AddCodeLine ("+%s", Hint);
+}
+
+
+
+void AddEmptyLine (void)
+/* Add an empty line for formatting purposes */
+{
+    AddCodeLine ("");
+}
+
+
+
+CodeMark GetCodePos (void)
+/* Get a marker pointing to the current output position */
+{
+    /* This function should never be called without any code output */
+    CHECK (LastLine != 0);
+
+    return LastLine;
+}
+
+
+
+void RemoveCode (CodeMark M)
+/* Remove all code after the given code marker */
+{
+    while (LastLine != M) {
+       FreeCodeLine (LastLine);
+    }
+}
+
+
+
+void WriteOutput (FILE* F)
+/* Write the final output to a file */
+{
+    Line* L = FirstLine;
+    while (L) {
+       /* Don't write optimizer hints if not requested to do so */
+       if (L->Line[0] == '+') {
+           if (Debug) {
+               fprintf (F, ";%s\n", L->Line);
+           }
+       } else {
+           fprintf (F, "%s\n", L->Line);
+       }
+       L = L->Next;
+    }
+}
+
+
+
diff --git a/src/cc65/asmcode.h b/src/cc65/asmcode.h
new file mode 100644 (file)
index 0000000..69652c2
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                asmcode.h                                 */
+/*                                                                           */
+/*         Assembler output code handling for the cc65 C compiler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ASMCODE_H
+#define ASMCODE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Marker for an assembler code position */
+typedef struct Line_* CodeMark;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void AddCodeLine (const char* Format, ...);
+/* Add a new line of code to the output */
+
+void AddCodeHint (const char* Hint);
+/* Add an optimizer hint */
+
+void AddEmptyLine (void);
+/* Add an empty line for formatting purposes */
+
+CodeMark GetCodePos (void);
+/* Get a marker pointing to the current output position */
+
+void RemoveCode (CodeMark M);
+/* Remove all code after the given code marker */
+
+void WriteOutput (FILE* F);
+/* Write the final output to a file */
+
+
+
+/* End of asmcode.h */
+#endif
+
+
+
diff --git a/src/cc65/asmlabel.c b/src/cc65/asmlabel.c
new file mode 100644 (file)
index 0000000..a18cf1c
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               asmlabel.c                                 */
+/*                                                                           */
+/*                     Generate assembler code labels                       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "asmlabel.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned GetLabel (void)
+/* Get an unused label. Will never return zero. */
+{
+    /* Number to generate unique labels */
+    static unsigned NextLabel = 0;
+    return ++NextLabel;
+}
+
+
+
diff --git a/src/cc65/asmlabel.h b/src/cc65/asmlabel.h
new file mode 100644 (file)
index 0000000..9dbc6f9
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               asmlabel.h                                 */
+/*                                                                           */
+/*                     Generate assembler code labels                       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ASMLABEL_H
+#define ASMLABEL_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned GetLabel (void);
+/* Get an unused assembler label. Will never return zero. */
+
+
+
+/* End of asmlabel.h */
+#endif
+
+
+
diff --git a/src/cc65/asmline.c b/src/cc65/asmline.c
new file mode 100644 (file)
index 0000000..5559e88
--- /dev/null
@@ -0,0 +1,184 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                asmline.h                                 */
+/*                                                                           */
+/*                    Internal assembler line structure                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "error.h"
+#include "mem.h"
+#include "asmline.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Number used to index lines */
+static unsigned long LineIndex = 0;
+
+/* The line list */
+Line*  FirstLine = 0;          /* Pointer to first line */
+Line*  LastLine  = 0;          /* Pointer to last line */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static Line* NewLine (const char* Format, va_list ap)
+/* Interal routine to create a new line from the given text */
+{
+    char       Buf [8192];
+    int        OVF;
+    unsigned   Len;
+    Line*      L;
+
+
+    /* Make a string from the given format and arguments */
+#if defined(__WATCOMC__)
+    OVF = (_vbprintf (Buf, sizeof (Buf), Format, ap) >= sizeof (S));
+#else
+    /* Assume gcc running on a Unix OS */
+    OVF = (vsnprintf (Buf, sizeof (Buf), Format, ap) < 0);
+#endif
+    if (OVF) {
+       Internal ("String size overflow");
+    }
+
+    /* Get the length of the line */
+    Len = strlen (Buf);
+
+    /* Allocate memory */
+    L = xmalloc (sizeof (Line) + Len);
+
+    /* Partially initialize the struct (the remaining fields are initialized
+     * by the caller).
+     */
+    L->Flags   = 0;
+    L->Size    = 0;
+    L->Len     = Len;
+    memcpy (L->Line, Buf, Len+1);
+
+    /* Return the new line */
+    return L;
+}
+
+
+
+Line* NewCodeLine (const char* Format, va_list ap)
+/* Create a new code line and return it */
+{
+    /* Create a new line struct */
+    Line* L = NewLine (Format, ap);
+
+    /* Initialize struct fields */
+    L->Index   = LineIndex++;
+
+    /* Insert the line into the list */
+    if (FirstLine == 0) {
+               /* The list is empty */
+               L->Next = L->Prev = 0;
+               FirstLine = LastLine = L;
+    } else {
+               /* There are entries in the list, add the new one at the end */
+               LastLine->Next = L;
+               L->Prev = LastLine;
+               L->Next = 0;
+               LastLine = L;
+    }
+
+    /* Return the new line */
+    return L;
+}
+
+
+
+Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap)
+/* Create a new line, insert it after L and return it. */
+{
+    /* Create a new line struct */
+    Line* L = NewLine (Format, ap);
+
+    /* Initialize struct fields. We use the same index for the inserted line
+     * as for its predecessor, since we cannot create new numbers on the
+     * fly and the index is only used to determine sort order.
+     */
+    L->Index           = LineBefore->Index;
+
+    /* Insert the line after its predecessor */
+    L->Next = LineBefore->Next;
+    LineBefore->Next = L;
+    L->Prev = LineBefore;
+    if (L->Next) {
+       L->Next->Prev = L;
+    } else {
+       /* This is the last line */
+       LastLine = L;
+    }
+
+    /* Return the new line */
+    return L;
+}
+
+
+
+void FreeCodeLine (Line* L)
+/* Remove a line from the list and free it */
+{
+    /* Unlink the line */
+    if (L->Prev == 0) {
+               /* No line before this one */
+               FirstLine = L->Next;
+    } else {
+               L->Prev->Next = L->Next;
+    }
+    if (L->Next == 0) {
+               /* No line after this one */
+               LastLine = L->Prev;
+    } else {
+               L->Next->Prev = L->Prev;
+    }
+
+    /* Free the struct */
+    xfree (L);
+}
+
+
+
diff --git a/src/cc65/asmline.h b/src/cc65/asmline.h
new file mode 100644 (file)
index 0000000..bfec110
--- /dev/null
@@ -0,0 +1,90 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                asmline.h                                 */
+/*                                                                           */
+/*                    Internal assembler line structure                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ASMLINE_H
+#define ASMLINE_H
+
+
+
+#include <stdarg.h>
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure that contains one line */
+typedef struct Line_ Line;
+struct Line_ {
+    Line*              Next;           /* Next line on double linked list */
+    Line*              Prev;           /* Revious line in list */
+    unsigned                   Flags;          /* Flags for this line */
+    unsigned long      Index;          /* Index of this line */
+    unsigned                   Size;           /* Size of this code */
+    unsigned                   Len;            /* Length of the line */
+    char                       Line [1];       /* The line itself */
+};
+
+/* The line list */
+extern Line*           FirstLine;      /* Pointer to first line */
+extern Line*                   LastLine;       /* Pointer to last line */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+Line* NewCodeLine (const char* Format, va_list ap);
+/* Create a new code line and return it */
+
+Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap);
+/* Create a new line, insert it after L and return it. */
+
+void FreeCodeLine (Line* L);
+/* Remove a line from the list and free it */
+
+
+
+/* End of asmline.h */
+#endif
+
+
+
diff --git a/src/cc65/check.c b/src/cc65/check.c
new file mode 100644 (file)
index 0000000..596eb79
--- /dev/null
@@ -0,0 +1,102 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 check.c                                  */
+/*                                                                           */
+/*                  Assert macros for the cc65 C compiler                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "check.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Predefined messages */
+const char* _MsgInternalError  = "Internal error: ";
+const char* _MsgAbstractCall   = "Call to abstract method";
+const char* _MsgPrecondition   = "Precondition violated: ";
+const char* _MsgCheckFailed    = "Check failed: ";
+const char* _MsgProgramAborted = "Program aborted: ";
+
+
+
+static void _CheckFailed (const char* msg, const char* cond,
+                                 int code, const char* file, unsigned line);
+
+void (*CheckFailed) (const char* Msg, const char* Cond, int Code,
+                            const char* File, unsigned Line) = _CheckFailed;
+/* Function pointer that is called from check if the condition code is true. */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void _CheckFailed (const char* Msg, const char* Cond,
+                         int Code, const char* File, unsigned Line)
+{
+    /* Log the error */
+    if (Code) {
+       Internal ("%s%s (= %d), file `%s', line %u", Msg, Cond, Code, File, Line);
+    } else {
+               Internal ("%s%s, file `%s', line %u", Msg, Cond, File, Line);
+    }
+
+    /* Use abort() to create a core for debugging */
+    abort ();
+}
+
+
+
+void Check (const char* Msg, const char* Cond, int Code,
+           const char* File, unsigned Line)
+/* This function is called from all check macros (see below). It checks,
+ * wether the given Code is true (!= 0). If so, it calls the CheckFailed
+ * vector with the given strings. If not, it simply returns.
+ */
+{
+    if (Code != 0) {
+       CheckFailed (Msg, Cond, Code, File, Line);
+    }
+}
+
+
+
diff --git a/src/cc65/check.h b/src/cc65/check.h
new file mode 100644 (file)
index 0000000..e650092
--- /dev/null
@@ -0,0 +1,96 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 check.h                                  */
+/*                                                                           */
+/*                  Assert macros for the cc65 C compiler                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef CHECK_H
+#define CHECK_H
+
+
+
+/*****************************************************************************/
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+extern const char* _MsgInternalError;           /* "Internal error: "        */
+extern const char* _MsgPrecondition;            /* "Precondition violated: " */
+extern const char* _MsgCheckFailed;             /* "Check failed: "          */
+extern const char* _MsgProgramAborted;         /* "Program aborted: "       */
+
+
+
+extern void (*CheckFailed) (const char* Msg, const char* Cond,
+                                   int Code, const char* File, unsigned Line);
+/* Function pointer that is called from check if the condition code is true. */
+
+
+
+/*****************************************************************************/
+/*                                   Code                                    */
+/*****************************************************************************/
+
+
+
+void Check (const char* Msg, const char* Cond, int Code,
+            const char* File, unsigned Line);
+/* This function is called from all check macros (see below). It checks,
+ * wether the given Code is true (!= 0). If so, it calls the CheckFailed
+ * vector with the given strings. If not, it simply returns.
+ */
+
+
+
+#define FAIL(s) CheckFailed (_MsgInternalError, s, 0, __FILE__, __LINE__)
+/* Fail macro. Is used if something evil happens, calls checkfailed directly. */
+
+#define ABORT(s) CheckFailed (_MsgProgramAborted, s, 0, __FILE__, __LINE__)
+/* Use this one instead of FAIL if there is no internal program error but an
+ * error condition that is caused by the user or operating system (FAIL and
+ * ABORT are essentially the same but the message differs).
+ */
+
+#define PRECONDITION(c) Check (_MsgPrecondition, #c, !(c), __FILE__, __LINE__)
+
+#define CHECK(c)        Check (_MsgCheckFailed, #c, !(c), __FILE__, __LINE__)
+
+#define ZCHECK(c)       Check (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+
+
+/* End of check.h */
+#endif
+
+
+
diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c
new file mode 100644 (file)
index 0000000..b805898
--- /dev/null
@@ -0,0 +1,3712 @@
+/*
+ * codegen.c
+ *
+ * Ullrich von Bassewitz, 08.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../common/version.h"
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "error.h"
+#include "global.h"
+#include "io.h"
+#include "litpool.h"
+#include "mem.h"
+#include "optimize.h"
+#include "util.h"
+#include "codegen.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Compiler relative stk ptr */
+int oursp      = 0;
+
+/* Current segment */
+static enum { SEG_CODE, SEG_RODATA, SEG_DATA, SEG_BSS } CurSeg = SEG_CODE;
+
+/* Segment names */
+static char* SegmentNames [4];
+static char* SegmentHints [4] = {
+    "seg:code", "seg:rodata", "seg:data", "seg:bss"
+};
+
+
+/*****************************************************************************/
+/*                                 Helpers                                  */
+/*****************************************************************************/
+
+
+
+static void typeerror (unsigned type)
+/* Print an error message about an invalid operand type */
+{
+    Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
+}
+
+
+
+static void CheckLocalOffs (unsigned Offs)
+/* Check the offset into the stack for 8bit range */
+{
+    if (Offs >= 256) {
+       /* Too many local vars */
+               AddCodeLine (";*** Too many locals");
+       Error (ERR_TOO_MANY_LOCALS);
+    }
+}
+
+
+
+static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
+{
+    static char lbuf [128];            /* Label name */
+
+    /* Create the correct label name */
+    switch (flags & CF_ADDRMASK) {
+
+       case CF_STATIC:
+           /* Static memory cell */
+           sprintf (lbuf, "L%04X+%u", (unsigned)(label & 0xFFFF), offs);
+           break;
+
+       case CF_EXTERNAL:
+           /* External label */
+           sprintf (lbuf, "_%s+%u", (char*) label, offs);
+           break;
+
+       case CF_ABSOLUTE:
+           /* Absolute address */
+           sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
+           break;
+
+       case CF_REGVAR:
+           /* Variable in register bank */
+           sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
+           break;
+
+       default:
+           Internal ("Invalid address flags");
+    }
+
+    /* Return a pointer to the static buffer */
+    return lbuf;
+}
+
+
+
+/*****************************************************************************/
+/*                           Pre- and postamble                             */
+/*****************************************************************************/
+
+
+
+void g_preamble (void)
+/* Generate the assembler code preamble */
+{
+    AddCodeLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+    AddEmptyLine ();
+
+    /* Insert some object file options */
+    AddCodeLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH);
+    AddEmptyLine ();
+
+    /* Allow auto import for runtime library routines */
+    AddCodeLine (".autoimport\ton");
+
+    /* Switch the assembler into case sensible mode */
+    AddCodeLine (".case\t\ton");
+
+    /* Tell the assembler if we want to generate debug info */
+    AddCodeLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
+
+    /* Import the stack pointer for direct auto variable access */
+    AddCodeLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
+
+    /* Define long branch macros */
+    AddCodeLine (".macpack\tlongbranch");
+    AddEmptyLine ();
+
+    /* Define the ldax macro */
+    AddCodeLine (".macro  ldax    Value");
+    AddCodeLine ("        lda     #<(Value)");
+    AddCodeLine ("        ldx     #>(Value)");
+    AddCodeLine (".endmacro");
+    AddEmptyLine ();
+
+    /* Define the default names for the segments */
+    SegmentNames [SEG_CODE]    = xstrdup ("CODE");
+    SegmentNames [SEG_RODATA]  = xstrdup ("RODATA");
+    SegmentNames [SEG_DATA]    = xstrdup ("DATA");
+    SegmentNames [SEG_BSS]     = xstrdup ("BSS");
+
+    /* Tell the optimizer that this is the end of the preamble */
+    AddCodeHint ("end_of_preamble");
+}
+
+
+
+void g_postamble (void)
+/* Generate assembler code postamble */
+{
+    /* Tell the optimizer that this is the start of the postamble */
+    AddCodeHint ("start_of_postamble");
+}
+
+
+
+/*****************************************************************************/
+/*                             Segment support                              */
+/*****************************************************************************/
+
+
+
+static void UseSeg (unsigned NewSeg)
+/* Switch to a specific segment */
+{
+    if (CurSeg != NewSeg) {
+       CurSeg = NewSeg;
+       AddCodeLine (".segment\t\"%s\"", SegmentNames [CurSeg]);
+       AddCodeHint (SegmentHints [CurSeg]);
+    }
+}
+
+
+
+void g_usecode (void)
+/* Switch to the code segment */
+{
+    UseSeg (SEG_CODE);
+}
+
+
+
+void g_userodata (void)
+/* Switch to the read only data segment */
+{
+    UseSeg (SEG_RODATA);
+}
+
+
+
+void g_usedata (void)
+/* Switch to the data segment */
+{
+    UseSeg (SEG_DATA);
+}
+
+
+
+void g_usebss (void)
+/* Switch to the bss segment */
+{
+    UseSeg (SEG_BSS);
+}
+
+
+
+void SegName (unsigned Seg, const char* Name)
+/* Set the name of a segment */
+{
+    /* Free the old name and set a new one */
+    xfree (SegmentNames [Seg]);
+    SegmentNames [Seg] = xstrdup (Name);
+
+    /* If the new segment is the current segment, emit a segment directive
+     * with the new name.
+     */
+    if (Seg == CurSeg) {
+       CurSeg = -1;    /* Invalidate */
+       UseSeg (Seg);
+    }
+}
+
+
+
+void g_codename (const char* Name)
+/* Set the name of the CODE segment */
+{
+    SegName (SEG_CODE, Name);
+}
+
+
+
+void g_rodataname (const char* Name)
+/* Set the name of the RODATA segment */
+{
+    SegName (SEG_RODATA, Name);
+}
+
+
+
+void g_dataname (const char* Name)
+/* Set the name of the DATA segment */
+{
+    SegName (SEG_DATA, Name);
+}
+
+
+
+void g_bssname (const char* Name)
+/* Set the name of the BSS segment */
+{
+    SegName (SEG_BSS, Name);
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned sizeofarg (unsigned flags)
+/* Return the size of a function argument type that is encoded in flags */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           return (flags & CF_FORCECHAR)? 1 : 2;
+
+       case CF_INT:
+           return 2;
+
+       case CF_LONG:
+           return 4;
+
+       default:
+           typeerror (flags);
+           /* NOTREACHED */
+           return 2;
+    }
+}
+
+
+
+int pop (unsigned flags)
+/* Pop an argument of the given size */
+{
+    return oursp += sizeofarg (flags);
+}
+
+
+
+int push (unsigned flags)
+/* Push an argument of the given size */
+{
+    return oursp -= sizeofarg (flags);
+}
+
+
+
+static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
+/* The value in Offs is an offset to an address in a/x. Make sure, an object
+ * of the type given in Flags can be loaded or stored into this address by
+ * adding part of the offset to the address in ax, so that the remaining
+ * offset fits into an index register. Return the remaining offset.
+ */
+{
+    /* If the offset is too large for a byte register, add the high byte
+     * of the offset to the primary. Beware: We need a special correction
+     * if the offset in the low byte will overflow in the operation.
+     */
+    unsigned O = Offs & ~0xFFU;
+    if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
+       /* We need to add the low byte also */
+       O += Offs & 0xFF;
+    }
+
+    /* Do the correction if we need one */
+    if (O != 0) {
+       g_inc (CF_INT | CF_CONST, O);
+       Offs -= O;
+    }
+
+    /* Return the new offset */
+    return Offs;
+}
+
+
+
+/*****************************************************************************/
+/*                     Functions handling local labels                      */
+/*****************************************************************************/
+
+
+
+void g_defloclabel (unsigned label)
+/* Define a local label */
+{
+    AddCodeLine ("L%04X:", label & 0xFFFF);
+}
+
+
+
+/*****************************************************************************/
+/*                    Functions handling global labels                      */
+/*****************************************************************************/
+
+
+
+void g_defgloblabel (const char* Name)
+/* Define a global label with the given name */
+{
+    AddCodeLine ("_%s:", Name);
+}
+
+
+
+void g_defexport (const char* Name, int ZP)
+/* Export the given label */
+{
+    if (ZP) {
+       AddCodeLine ("\t.exportzp\t_%s", Name);
+    } else {
+       AddCodeLine ("\t.export\t\t_%s", Name);
+    }
+}
+
+
+
+void g_defimport (const char* Name, int ZP)
+/* Import the given label */
+{
+    if (ZP) {
+               AddCodeLine ("\t.importzp\t_%s", Name);
+    } else {
+       AddCodeLine ("\t.import\t\t_%s", Name);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                          Load functions for various registers                    */
+/*****************************************************************************/
+
+
+
+static void ldaconst (unsigned val)
+/* Load a with a constant */
+{
+    AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+}
+
+
+
+static void ldxconst (unsigned val)
+/* Load x with a constant */
+{
+    AddCodeLine ("\tldx\t#$%02X", val & 0xFF);
+}
+
+
+
+static void ldyconst (unsigned val)
+/* Load y with a constant */
+{
+    AddCodeLine ("\tldy\t#$%02X", val & 0xFF);
+}
+
+
+
+/*****************************************************************************/
+/*                                 Function entry and exit                          */
+/*****************************************************************************/
+
+
+
+/* Remember the argument size of a function. The variable is set by g_enter
+ * and used by g_leave. If the functions gets its argument size by the caller
+ * (variable param list or function without prototype), g_enter will set the
+ * value to -1.
+ */
+static int funcargs;
+
+
+void g_enter (unsigned flags, const char* Name, unsigned argsize)
+/* Function prologue */
+{
+    g_defgloblabel (Name);     /* Define function name as label */
+    if ((flags & CF_FIXARGC) != 0) {
+       /* Just remember the argument size for the leave */
+       funcargs = argsize;
+    } else {
+               funcargs = -1;
+               AddCodeLine ("\tjsr\tenter");
+    }
+}
+
+
+
+void g_leave (int flags, int val)
+/* Function epilogue */
+{
+    int k;
+    char buf [40];
+
+    /* How many bytes of locals do we have to drop? */
+    k = -oursp;
+
+    /* If we didn't have a variable argument list, don't call leave */
+    if (funcargs >= 0) {
+
+       /* Load a function return code if needed */
+       if ((flags & CF_CONST) != 0) {
+           g_getimmed (flags, val, 0);
+       }
+
+       /* Drop stackframe or leave with rts */
+       k += funcargs;
+       if (k == 0) {
+           AddCodeLine ("\trts");
+       } else if (k <= 8) {
+           AddCodeLine ("\tjmp\tincsp%d", k);
+       } else {
+           CheckLocalOffs (k);
+           ldyconst (k);
+           AddCodeLine ("\tjmp\taddysp");
+       }
+
+    } else {
+
+       strcpy (buf, "\tjmp\tleave");
+       if (k) {
+           /* We've a stack frame to drop */
+           ldyconst (k);
+           strcat (buf, "y");
+       }
+       if (flags & CF_CONST) {
+           if ((flags & CF_TYPE) != CF_LONG) {
+               /* Constant int sized value given for return code */
+               if (val == 0) {
+                   /* Special case: return 0 */
+                   strcat (buf, "00");
+                       } else if (((val >> 8) & 0xFF) == 0) {
+                   /* Special case: constant with high byte zero */
+                   ldaconst (val);             /* Load low byte */
+                   strcat (buf, "0");
+               } else {
+                   /* Others: arbitrary constant value */
+                   g_getimmed (flags, val, 0); /* Load value */
+               }
+           } else {
+               /* Constant long value: No shortcut possible */
+               g_getimmed (flags, val, 0);
+           }
+       }
+
+       /* Output the jump */
+       AddCodeLine (buf);
+    }
+
+    /* Add an empty line  after a function to make the code more readable */
+    AddEmptyLine ();
+}
+
+
+
+/*****************************************************************************/
+/*                           Register variables                             */
+/*****************************************************************************/
+
+
+
+void g_save_regvars (int RegOffs, unsigned Bytes)
+/* Save register variables */
+{
+    /* Don't loop for up to two bytes */
+    if (Bytes == 1) {
+
+       AddCodeLine ("\tlda\tregbank%+d", RegOffs);
+               AddCodeLine ("\tjsr\tpusha");
+
+    } else if (Bytes == 2) {
+
+               AddCodeLine ("\tlda\tregbank%+d", RegOffs);
+       AddCodeLine ("\tldx\tregbank%+d", RegOffs+1);
+               AddCodeLine ("\tjsr\tpushax");
+
+    } else {
+
+       /* More than two bytes - loop */
+       unsigned Label = GetLabel ();
+       g_space (Bytes);
+       ldyconst (Bytes - 1);
+       ldxconst (Bytes);
+       g_defloclabel (Label);
+       AddCodeLine ("\tlda\tregbank%+d,x", RegOffs-1);
+       AddCodeLine ("\tsta\t(sp),y");
+       AddCodeLine ("\tdey");
+       AddCodeLine ("\tdex");
+       AddCodeLine ("\tbne\tL%04X", Label);
+
+    }
+
+    /* We pushed stuff, correct the stack pointer */
+    oursp -= Bytes;
+}
+
+
+
+void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
+/* Restore register variables */
+{
+    /* Calculate the actual stack offset and check it */
+    StackOffs -= oursp;
+    CheckLocalOffs (StackOffs);
+
+    /* Don't loop for up to two bytes */
+    if (Bytes == 1) {
+
+       ldyconst (StackOffs);
+       AddCodeLine ("\tlda\t(sp),y");
+       AddCodeLine ("\tsta\tregbank%+d", RegOffs);
+
+    } else if (Bytes == 2) {
+
+       ldyconst (StackOffs);
+       AddCodeLine ("\tlda\t(sp),y");
+       AddCodeLine ("\tsta\tregbank%+d", RegOffs);
+       AddCodeLine ("\tiny");
+       AddCodeLine ("\tlda\t(sp),y");
+       AddCodeLine ("\tsta\tregbank%+d", RegOffs+1);
+
+    } else {
+
+       /* More than two bytes - loop */
+       unsigned Label = GetLabel ();
+       ldyconst (StackOffs+Bytes-1);
+       ldxconst (Bytes);
+       g_defloclabel (Label);
+       AddCodeLine ("\tlda\t(sp),y");
+       AddCodeLine ("\tsta\tregbank%+d,x", RegOffs-1);
+       AddCodeLine ("\tdey");
+       AddCodeLine ("\tdex");
+       AddCodeLine ("\tbne\tL%04X", Label);
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                          Fetching memory cells                           */
+/*****************************************************************************/
+
+
+
+void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
+/* Load a constant into the primary register */
+{
+    if ((flags & CF_CONST) != 0) {
+
+       /* Numeric constant */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if ((flags & CF_FORCECHAR) != 0) {
+                   ldaconst (val);
+                   break;
+               }
+               /* FALL THROUGH */
+           case CF_INT:
+               ldxconst ((val >> 8) & 0xFF);
+               ldaconst (val & 0xFF);
+               break;
+
+           case CF_LONG:
+               if (val < 0x100) {
+                   AddCodeLine ("\tldx\t#$00");
+                   AddCodeLine ("\tstx\tsreg+1");
+                   AddCodeLine ("\tstx\tsreg");
+                   AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+               } else if ((val & 0xFFFF00FF) == 0) {
+                   AddCodeLine ("\tlda\t#$00");
+                   AddCodeLine ("\tsta\tsreg+1");
+                   AddCodeLine ("\tsta\tsreg");
+                   AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+               } else if ((val & 0xFFFF0000) == 0 && FavourSize == 0) {
+                   AddCodeLine ("\tlda\t#$00");
+                   AddCodeLine ("\tsta\tsreg+1");
+                   AddCodeLine ("\tsta\tsreg");
+                   AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+                   AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+               } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
+                   AddCodeLine ("\tldx\t#$FF");
+                   AddCodeLine ("\tstx\tsreg+1");
+                   AddCodeLine ("\tstx\tsreg");
+                   if ((val & 0xFF) == 0xFF) {
+                       AddCodeLine ("\ttxa");
+                   } else {
+                       AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+                   }
+               } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
+                   AddCodeLine ("\tlda\t#$FF");
+                   AddCodeLine ("\tsta\tsreg+1");
+                   AddCodeLine ("\tsta\tsreg");
+                   AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+               } else {
+                   /* Call a subroutine that will load following value */
+                   AddCodeLine ("\tjsr\tldeax");
+                   AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
+               }
+               break;
+
+           default:
+               typeerror (flags);
+               break;
+
+       }
+
+    } else {
+
+       /* Some sort of label */
+       const char* Label = GetLabelName (flags, val, offs);
+
+       /* Load the address into the primary */
+       AddCodeLine ("\tldax\t%s", Label);
+
+    }
+}
+
+
+
+void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Fetch an static memory cell into the primary register */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    /* Check the size and generate the correct load operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
+               AddCodeLine ("\tlda\t%s", lbuf);        /* load A from the label */
+                   } else {
+               ldxconst (0);
+               AddCodeLine ("\tlda\t%s", lbuf);        /* load A from the label */
+               if (!(flags & CF_UNSIGNED)) {
+                   /* Must sign extend */
+                   AddCodeLine ("\tbpl\t*+3");
+                   AddCodeLine ("\tdex");
+                   AddCodeHint ("x:!");                /* X is invalid now */
+               }
+           }
+           break;
+
+       case CF_INT:
+           AddCodeLine ("\tlda\t%s", lbuf);
+           if (flags & CF_TEST) {
+               AddCodeLine ("\tora\t%s+1", lbuf);
+           } else {
+               AddCodeLine ("\tldx\t%s+1", lbuf);
+           }
+           break;
+
+       case CF_LONG:
+           if (flags & CF_TEST) {
+               AddCodeLine ("\tlda\t%s+3", lbuf);
+               AddCodeLine ("\tora\t%s+2", lbuf);
+               AddCodeLine ("\tora\t%s+1", lbuf);
+               AddCodeLine ("\tora\t%s+0", lbuf);
+           } else {
+               AddCodeLine ("\tlda\t%s+3", lbuf);
+               AddCodeLine ("\tsta\tsreg+1");
+               AddCodeLine ("\tlda\t%s+2", lbuf);
+               AddCodeLine ("\tsta\tsreg");
+               AddCodeLine ("\tldx\t%s+1", lbuf);
+               AddCodeLine ("\tlda\t%s", lbuf);
+           }
+           break;
+
+               default:
+                   typeerror (flags);
+
+    }
+}
+
+
+
+void g_getlocal (unsigned flags, int offs)
+/* Fetch specified local object (local var). */
+{
+    offs -= oursp;
+    CheckLocalOffs (offs);
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
+               ldyconst (offs);
+                       AddCodeLine ("\tlda\t(sp),y");
+           } else {
+               if (offs == 0) {
+                   AddCodeLine ("\tldx\t#$00");
+                   AddCodeLine ("\tlda\t(sp,x)");
+               } else {
+                   ldyconst (offs);
+                   AddCodeLine ("\tldx\t#$00");
+                   AddCodeLine ("\tlda\t(sp),y");
+               }
+               if ((flags & CF_UNSIGNED) == 0) {
+                   AddCodeLine ("\tbpl\t*+3");
+                   AddCodeLine ("\tdex");
+                   AddCodeHint ("x:!");        /* X is invalid now */
+               }
+           }
+           break;
+
+       case CF_INT:
+           CheckLocalOffs (offs + 1);
+                   if (flags & CF_TEST) {
+               ldyconst (offs + 1);
+               AddCodeLine ("\tlda\t(sp),y");
+               AddCodeLine ("\tdey");
+               AddCodeLine ("\tora\t(sp),y");
+           } else {
+               if (FavourSize) {
+                   if (offs) {
+                       ldyconst (offs+1);
+                               AddCodeLine ("\tjsr\tldaxysp");
+                   } else {
+                       AddCodeLine ("\tjsr\tldax0sp");
+                   }
+               } else {
+                   ldyconst (offs + 1);
+                   AddCodeLine ("\tlda\t(sp),y");
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tdey");
+                   AddCodeLine ("\tlda\t(sp),y");
+               }
+           }
+           break;
+
+       case CF_LONG:
+           if (offs) {
+               ldyconst (offs+3);
+               AddCodeLine ("\tjsr\tldeaxysp");
+           } else {
+               AddCodeLine ("\tjsr\tldeax0sp");
+           }
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_getind (unsigned flags, unsigned offs)
+/* Fetch the specified object type indirect through the primary register
+ * into the primary register
+ */
+{
+    /* If the offset is greater than 255, add the part that is > 255 to
+     * the primary. This way we get an easy addition and use the low byte
+     * as the offset
+     */
+    offs = MakeByteOffs (flags, offs);
+
+    /* Handle the indirect fetch */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+                   /* Character sized */
+           if (offs) {
+               ldyconst (offs);
+               if (flags & CF_UNSIGNED) {
+                   AddCodeLine ("\tjsr\tldauidx");
+                       } else {
+                   AddCodeLine ("\tjsr\tldaidx");
+               }
+           } else {
+               if (flags & CF_UNSIGNED) {
+                   if (FavourSize) {
+                       AddCodeLine ("\tjsr\tldaui");
+                   } else {
+                       AddCodeLine ("\tsta\tptr1");
+                       AddCodeLine ("\tstx\tptr1+1");
+                       AddCodeLine ("\tldx\t#$00");
+                       AddCodeLine ("\tlda\t(ptr1,x)");
+                   }
+               } else {
+                   AddCodeLine ("\tjsr\tldai");
+               }
+           }
+           break;
+
+       case CF_INT:
+           if (flags & CF_TEST) {
+               ldyconst (offs);
+               AddCodeLine ("\tsta\tptr1");
+               AddCodeLine ("\tstx\tptr1+1");
+               AddCodeLine ("\tlda\t(ptr1),y");
+               AddCodeLine ("\tiny");
+               AddCodeLine ("\tora\t(ptr1),y");
+           } else {
+               if (offs == 0) {
+                   AddCodeLine ("\tjsr\tldaxi");
+               } else {
+                   ldyconst (offs+1);
+                   AddCodeLine ("\tjsr\tldaxidx");
+               }
+           }
+           break;
+
+               case CF_LONG:
+           if (offs == 0) {
+               AddCodeLine ("\tjsr\tldeaxi");
+           } else {
+               ldyconst (offs+3);
+               AddCodeLine ("\tjsr\tldeaxidx");
+           }
+           if (flags & CF_TEST) {
+                       AddCodeLine ("\tjsr\ttsteax");
+           }
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_leasp (int offs)
+/* Fetch the address of the specified symbol into the primary register */
+{
+    /* Calculate the offset relative to sp */
+    offs -= oursp;
+
+    /* For value 0 we do direct code */
+    if (offs == 0) {
+       AddCodeLine ("\tlda\tsp");
+       AddCodeLine ("\tldx\tsp+1");
+    } else {
+       if (FavourSize) {
+           ldyconst (offs);                    /* Load Y with offset value */
+           AddCodeLine ("\tjsr\tleaysp");      /* Load effective address */
+       } else {
+           ldaconst (offs);
+           AddCodeLine ("\tclc");
+           AddCodeLine ("\tldx\tsp+1");
+           AddCodeLine ("\tadc\tsp");
+           AddCodeLine ("\tbcc\t*+3");
+           AddCodeLine ("\tinx");
+           AddCodeHint ("x:!");                /* Invalidate X */
+       }
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                    Store into memory                             */
+/*****************************************************************************/
+
+
+
+void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Store the primary register into the specified static memory cell */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    /* Check the size and generate the correct store operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           AddCodeLine ("\tsta\t%s", lbuf);
+           break;
+
+       case CF_INT:
+           AddCodeLine ("\tsta\t%s", lbuf);
+           AddCodeLine ("\tstx\t%s+1", lbuf);
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tsta\t%s", lbuf);
+           AddCodeLine ("\tstx\t%s+1", lbuf);
+           AddCodeLine ("\tldy\tsreg");
+           AddCodeLine ("\tsty\t%s+2", lbuf);
+           AddCodeLine ("\tldy\tsreg+1");
+           AddCodeLine ("\tsty\t%s+3", lbuf);
+           break;
+
+               default:
+                   typeerror (flags);
+
+    }
+}
+
+
+
+void g_putlocal (unsigned flags, int offs)
+/* Put data into local object. */
+{
+    offs -= oursp;
+    CheckLocalOffs (offs);
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+                   ldyconst (offs);
+           AddCodeLine ("\tsta\t(sp),y");
+           break;
+
+       case CF_INT:
+           if (offs) {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tstaxysp");
+           } else {
+               AddCodeLine ("\tjsr\tstax0sp");
+           }
+           break;
+
+       case CF_LONG:
+           if (offs) {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tsteaxysp");
+           } else {
+               AddCodeLine ("\tjsr\tsteax0sp");
+           }
+           break;
+
+               default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_putind (unsigned flags, unsigned offs)
+/* Store the specified object type in the primary register at the address
+ * on the top of the stack
+ */
+{
+    /* We cannot currently handle more than byte sized offsets */
+    if (offs > 256 - sizeofarg (flags)) {
+       Internal ("g_putind: Large offsets not implemented");
+    }
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (offs) {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tstaspidx");
+           } else {
+               AddCodeLine ("\tjsr\tstaspp");
+           }
+           break;
+
+       case CF_INT:
+           if (offs) {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tstaxspidx");
+           } else {
+               AddCodeLine ("\tjsr\tstaxspp");
+           }
+           break;
+
+       case CF_LONG:
+           if (offs) {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tsteaxspidx");
+           } else {
+               AddCodeLine ("\tjsr\tsteaxspp");
+           }
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+
+    /* Pop the argument which is always a pointer */
+    pop (CF_PTR);
+}
+
+
+
+/*****************************************************************************/
+/*                   type conversion and similiar stuff                     */
+/*****************************************************************************/
+
+
+
+void g_toslong (unsigned flags)
+/* Make sure, the value on TOS is a long. Convert if necessary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           if (flags & CF_UNSIGNED) {
+               AddCodeLine ("\tjsr\ttosulong");
+           } else {
+               AddCodeLine ("\tjsr\ttoslong");
+           }
+           push (CF_INT);
+           break;
+
+       case CF_LONG:
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_tosint (unsigned flags)
+/* Make sure, the value on TOS is an int. Convert if necessary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\ttosint");
+           pop (CF_INT);
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_reglong (unsigned flags)
+/* Make sure, the value in the primary register a long. Convert if necessary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           if (flags & CF_UNSIGNED) {
+               if (FavourSize) {
+                   AddCodeLine ("\tjsr\taxulong");
+               } else {
+                   ldyconst (0);
+                   AddCodeLine ("\tsty\tsreg");
+                   AddCodeLine ("\tsty\tsreg+1");
+               }
+           } else {
+               AddCodeLine ("\tjsr\taxlong");
+           }
+           break;
+
+       case CF_LONG:
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+unsigned g_typeadjust (unsigned lhs, unsigned rhs)
+/* Adjust the integer operands before doing a binary operation. lhs is a flags
+ * value, that corresponds to the value on TOS, rhs corresponds to the value
+ * in (e)ax. The return value is the the flags value for the resulting type.
+ */
+{
+    unsigned ltype, rtype;
+    unsigned result;
+
+    /* Get the type spec from the flags */
+    ltype = lhs & CF_TYPE;
+    rtype = rhs & CF_TYPE;
+
+    /* Check if a conversion is needed */
+    if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
+       /* We must promote the primary register to long */
+       g_reglong (rhs);
+       /* Get the new rhs type */
+       rhs = (rhs & ~CF_TYPE) | CF_LONG;
+       rtype = CF_LONG;
+    } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
+       /* We must promote the lhs to long */
+       if (lhs & CF_REG) {
+           g_reglong (lhs);
+       } else {
+           g_toslong (lhs);
+       }
+       /* Get the new rhs type */
+       lhs = (lhs & ~CF_TYPE) | CF_LONG;
+       ltype = CF_LONG;
+    }
+
+    /* Determine the result type for the operation:
+     * - The result is const if both operands are const.
+     * - The result is unsigned if one of the operands is unsigned.
+     * - The result is long if one of the operands is long.
+     * - Otherwise the result is int sized.
+     */
+    result = (lhs & CF_CONST) & (rhs & CF_CONST);
+    result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
+    if (rtype == CF_LONG || ltype == CF_LONG) {
+       result |= CF_LONG;
+    } else {
+       result |= CF_INT;
+    }
+    return result;
+}
+
+
+
+unsigned g_typecast (unsigned lhs, unsigned rhs)
+/* Cast the value in the primary register to the operand size that is flagged
+ * by the lhs value. Return the result value.
+ */
+{
+    unsigned ltype, rtype;
+
+    /* Get the type spec from the flags */
+    ltype = lhs & CF_TYPE;
+    rtype = rhs & CF_TYPE;
+
+    /* Check if a conversion is needed */
+    if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
+       /* We must promote the primary register to long */
+       g_reglong (rhs);
+    }
+
+    /* Do not need any other action. If the left type is int, and the primary
+     * register is long, it will be automagically truncated. If the right hand
+     * side is const, it is not located in the primary register and handled by
+     * the expression parser code.
+     */
+
+    /* Result is const if the right hand side was const */
+    lhs |= (rhs & CF_CONST);
+
+    /* The resulting type is that of the left hand side (that's why you called
+     * this function :-)
+     */
+    return lhs;
+}
+
+
+
+void g_scale (unsigned flags, long val)
+/* Scale the value in the primary register by the given value. If val is positive,
+ * scale up, is val is negative, scale down. This function is used to scale
+ * the operands or results of pointer arithmetic by the size of the type, the
+ * pointer points to.
+ */
+{
+    int p2;
+
+    /* Value may not be zero */
+    if (val == 0) {
+               Internal ("Data type has no size");
+    } else if (val > 0) {
+
+       /* Scale up */
+       if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+
+           /* Factor is 2, 4 or 8, use special function */
+           switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+                       while (p2--) {
+                           AddCodeLine ("\tasl\ta");
+                       }
+                       break;
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+                   if (FavourSize || p2 >= 3) {
+                       if (flags & CF_UNSIGNED) {
+                           AddCodeLine ("\tjsr\tshlax%d", p2);
+                       } else {
+                           AddCodeLine ("\tjsr\taslax%d", p2);
+                       }
+                   } else {
+                       AddCodeLine ("\tstx\ttmp1");
+                       while (p2--) {
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\trol\ttmp1");
+                       }
+                       AddCodeLine ("\tldx\ttmp1");
+                   }
+                   break;
+
+               case CF_LONG:
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tshleax%d", p2);
+                   } else {
+                       AddCodeLine ("\tjsr\tasleax%d", p2);
+                   }
+                   break;
+
+               default:
+                   typeerror (flags);
+
+           }
+
+       } else if (val != 1) {
+
+                   /* Use a multiplication instead */
+           g_mul (flags | CF_CONST, val);
+
+       }
+
+    } else {
+
+       /* Scale down */
+       val = -val;
+       if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+
+           /* Factor is 2, 4 or 8, use special function */
+           switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+                       if (flags & CF_UNSIGNED) {
+                           while (p2--) {
+                               AddCodeLine ("\tlsr\ta");
+                           }
+                           break;
+                       } else if (p2 <= 2) {
+                           AddCodeLine ("\tcmp\t#$80");
+                           AddCodeLine ("\tror\ta");
+                           break;
+                       }
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+                   if (flags & CF_UNSIGNED) {
+                       if (FavourSize || p2 >= 3) {
+                           AddCodeLine ("\tjsr\tlsrax%d", p2);
+                       } else {
+                           AddCodeLine ("\tstx\ttmp1");
+                           while (p2--) {
+                               AddCodeLine ("\tlsr\ttmp1");
+                               AddCodeLine ("\tror\ta");
+                           }
+                           AddCodeLine ("\tldx\ttmp1");
+                       }
+                   } else {
+                       if (FavourSize || p2 >= 3) {
+                           AddCodeLine ("\tjsr\tasrax%d", p2);
+                       } else {
+                           AddCodeLine ("\tstx\ttmp1");
+                           while (p2--) {
+                               AddCodeLine ("\tcpx\t#$80");
+                               AddCodeLine ("\tror\ttmp1");
+                               AddCodeLine ("\tror\ta");
+                           }
+                           AddCodeLine ("\tldx\ttmp1");
+                       }
+                   }
+                   break;
+
+               case CF_LONG:
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tlsreax%d", p2);
+                   } else {
+                       AddCodeLine ("\tjsr\tasreax%d", p2);
+                   }
+                   break;
+
+               default:
+                   typeerror (flags);
+
+           }
+
+       } else if (val != 1) {
+
+                   /* Use a division instead */
+           g_div (flags | CF_CONST, val);
+
+       }
+    }
+}
+
+
+
+/*****************************************************************************/
+/*             Adds and subs of variables fix a fixed address               */
+/*****************************************************************************/
+
+
+
+void g_addlocal (unsigned flags, int offs)
+/* Add a local variable to ax */
+{
+    /* Correct the offset and check it */
+    offs -= oursp;
+    CheckLocalOffs (offs);
+
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
+           AddCodeLine ("\tclc");
+           AddCodeLine ("\tadc\t(sp),y");
+           AddCodeLine ("\tbcc\t*+3");
+           AddCodeLine ("\tinx");
+           AddCodeHint ("x:!");
+           break;
+
+       case CF_INT:
+           AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
+           AddCodeLine ("\tclc");
+           AddCodeLine ("\tadc\t(sp),y");
+           AddCodeLine ("\tpha");
+           AddCodeLine ("\ttxa");
+           AddCodeLine ("\tiny");
+           AddCodeLine ("\tadc\t(sp),y");
+           AddCodeLine ("\ttax");
+           AddCodeLine ("\tpla");
+           break;
+
+       case CF_LONG:
+           /* Do it the old way */
+                   g_push (flags, 0);
+           g_getlocal (flags, offs);
+           g_add (flags, 0);
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Add a static variable to ax */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           AddCodeLine ("\tclc");
+           AddCodeLine ("\tadc\t%s", lbuf);
+           AddCodeLine ("\tbcc\t*+3");
+           AddCodeLine ("\tinx");
+           AddCodeHint ("x:!");
+           break;
+
+       case CF_INT:
+           AddCodeLine ("\tclc");
+           AddCodeLine ("\tadc\t%s", lbuf);
+           AddCodeLine ("\ttay");
+           AddCodeLine ("\ttxa");
+           AddCodeLine ("\tadc\t%s+1", lbuf);
+           AddCodeLine ("\ttax");
+           AddCodeLine ("\ttya");
+           break;
+
+       case CF_LONG:
+           /* Do it the old way */
+                   g_push (flags, 0);
+           g_getstatic (flags, label, offs);
+           g_add (flags, 0);
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*            Compares of ax with a variable with fixed address             */
+/*****************************************************************************/
+
+
+
+void g_cmplocal (unsigned flags, int offs)
+/* Compare a local variable to ax */
+{
+    Internal ("g_cmplocal not implemented");
+}
+
+
+
+void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
+/* Compare a static variable to ax */
+{
+    Internal ("g_cmpstatic not implemented");
+}
+
+
+
+/*****************************************************************************/
+/*                          Special op= functions                           */
+/*****************************************************************************/
+
+
+
+void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
+                           unsigned long val)
+/* Emit += for a static variable */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tldx\t#$00");
+                       if (flags & CF_CONST) {
+                   if (val == 1) {
+                       AddCodeLine ("\tinc\t%s", lbuf);
+                       AddCodeLine ("\tlda\t%s", lbuf);
+                   } else {
+                               AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                       AddCodeLine ("\tclc");
+                       AddCodeLine ("\tadc\t%s", lbuf);
+                       AddCodeLine ("\tsta\t%s", lbuf);
+                   }
+                       } else {
+                   AddCodeLine ("\tclc");
+                           AddCodeLine ("\tadc\t%s", lbuf);
+                   AddCodeLine ("\tsta\t%s", lbuf);
+                       }
+               if ((flags & CF_UNSIGNED) == 0) {
+                   AddCodeLine ("\tbpl\t*+3");
+                   AddCodeLine ("\tdex");
+                   AddCodeHint ("x:!");                /* Invalidate X */
+               }
+                       break;
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+                   if (flags & CF_CONST) {
+               if (val == 1) {
+                   label = GetLabel ();
+                   AddCodeLine ("\tinc\t%s", lbuf);
+                   AddCodeLine ("\tbne\tL%04X", label);
+                   AddCodeLine ("\tinc\t%s+1", lbuf);
+                   g_defloclabel (label);
+                   AddCodeLine ("\tlda\t%s", lbuf);            /* Hmmm... */
+                   AddCodeLine ("\tldx\t%s+1", lbuf);
+               } else {
+                           AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tclc");
+                   AddCodeLine ("\tadc\t%s", lbuf);
+                   AddCodeLine ("\tsta\t%s", lbuf);
+                   if (val < 0x100) {
+                       label = GetLabel ();
+                       AddCodeLine ("\tbcc\tL%04X", label);
+                       AddCodeLine ("\tinc\t%s+1", lbuf);
+                               g_defloclabel (label);
+                       AddCodeLine ("\tldx\t%s+1", lbuf);
+                   } else {
+                               AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
+                       AddCodeLine ("\tadc\t%s+1", lbuf);
+                       AddCodeLine ("\tsta\t%s+1", lbuf);
+                       AddCodeLine ("\ttax");
+                       AddCodeLine ("\tlda\t%s", lbuf);
+                   }
+               }
+                   } else {
+               AddCodeLine ("\tclc");
+                       AddCodeLine ("\tadc\t%s", lbuf);
+                       AddCodeLine ("\tsta\t%s", lbuf);
+                       AddCodeLine ("\ttxa");
+                       AddCodeLine ("\tadc\t%s+1", lbuf);
+                       AddCodeLine ("\tsta\t%s+1", lbuf);
+                       AddCodeLine ("\ttax");
+               AddCodeLine ("\tlda\t%s", lbuf);
+           }
+                   break;
+
+               case CF_LONG:
+           if (flags & CF_CONST) {
+               if (val < 0x100) {
+                   AddCodeLine ("\tldy\t#<(%s)", lbuf);
+                   AddCodeLine ("\tsty\tptr1");
+                   AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+                   if (val == 1) {
+                       AddCodeLine ("\tjsr\tladdeq1");
+                   } else {
+                       AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                       AddCodeLine ("\tjsr\tladdeqa");
+                   }
+               } else {
+                   g_getstatic (flags, label, offs);
+                   g_inc (flags, val);
+                   g_putstatic (flags, label, offs);
+               }
+           } else {
+               AddCodeLine ("\tldy\t#<(%s)", lbuf);
+               AddCodeLine ("\tsty\tptr1");
+               AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+               AddCodeLine ("\tjsr\tladdeq");
+           }
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+void g_addeqlocal (unsigned flags, int offs, unsigned long val)
+/* Emit += for a local variable */
+{
+    /* Calculate the true offset, check it, load it into Y */
+    offs -= oursp;
+    CheckLocalOffs (offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+                       if (offs == 0) {
+                           AddCodeLine ("\tldx\t#$00");
+                           if (flags & CF_CONST) {
+                               AddCodeLine ("\tclc");
+                               AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                               AddCodeLine ("\tadc\t(sp,x)");
+                               AddCodeLine ("\tsta\t(sp,x)");
+                           } else {
+                               AddCodeLine ("\tclc");
+                               AddCodeLine ("\tadc\t(sp,x)");
+                               AddCodeLine ("\tsta\t(sp,x)");
+                           }
+                       } else {
+                           ldyconst (offs);
+                   AddCodeLine ("\tldx\t#$00");
+                   if (flags & CF_CONST) {
+                       AddCodeLine ("\tclc");
+                               AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                       AddCodeLine ("\tadc\t(sp),y");
+                       AddCodeLine ("\tsta\t(sp),y");
+                   } else {
+                       AddCodeLine ("\tclc");
+                       AddCodeLine ("\tadc\t(sp),y");
+                       AddCodeLine ("\tsta\t(sp),y");
+                   }
+               }
+               if ((flags & CF_UNSIGNED) == 0) {
+                   AddCodeLine ("\tbpl\t*+3");
+                   AddCodeLine ("\tdex");
+                   AddCodeHint ("x:!");        /* Invalidate X */
+               }
+                       break;
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+           if (flags & CF_CONST) {
+               g_getimmed (flags, val, 0);
+           }
+           if (offs == 0) {
+               AddCodeLine ("\tjsr\taddeq0sp");
+           } else {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\taddeqysp");
+           }
+                   break;
+
+               case CF_LONG:
+           if (flags & CF_CONST) {
+               g_getimmed (flags, val, 0);
+           }
+           if (offs == 0) {
+               AddCodeLine ("\tjsr\tladdeq0sp");
+           } else {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tladdeqysp");
+           }
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
+/* Emit += for the location with address in ax */
+{
+    /* If the offset is too large for a byte register, add the high byte
+     * of the offset to the primary. Beware: We need a special correction
+     * if the offset in the low byte will overflow in the operation.
+     */
+    offs = MakeByteOffs (flags, offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+           AddCodeLine ("\tsta\tptr1");
+           AddCodeLine ("\tstx\tptr1+1");
+           if (offs == 0) {
+               AddCodeLine ("\tldx\t#$00");
+               AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tclc");
+               AddCodeLine ("\tadc\t(ptr1,x)");
+               AddCodeLine ("\tsta\t(ptr1,x)");
+           } else {
+               AddCodeLine ("\tldy\t#$%02X", offs);
+                       AddCodeLine ("\tldx\t#$00");
+                       AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                       AddCodeLine ("\tclc");
+                       AddCodeLine ("\tadc\t(ptr1),y");
+                       AddCodeLine ("\tsta\t(ptr1),y");
+           }
+           break;
+
+               case CF_INT:
+           if (!FavourSize) {
+               /* Lots of code, use only if size is not important */
+                       AddCodeLine ("\tsta\tptr1");
+               AddCodeLine ("\tstx\tptr1+1");
+               AddCodeLine ("\tldy\t#$%02X", offs);
+               AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tclc");
+               AddCodeLine ("\tadc\t(ptr1),y");
+               AddCodeLine ("\tsta\t(ptr1),y");
+               AddCodeLine ("\tpha");
+               AddCodeLine ("\tiny");
+               AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
+               AddCodeLine ("\tadc\t(ptr1),y");
+               AddCodeLine ("\tsta\t(ptr1),y");
+               AddCodeLine ("\ttax");
+               AddCodeLine ("\tpla");
+               break;
+           }
+           /* FALL THROUGH */
+
+               case CF_LONG:
+                   AddCodeLine ("\tjsr\tpushax");      /* Push the address */
+           push (flags);                       /* Correct the internal sp */
+           g_getind (flags, offs);             /* Fetch the value */
+           g_inc (flags, val);                 /* Increment value in primary */
+           g_putind (flags, offs);             /* Store the value back */
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
+                           unsigned long val)
+/* Emit -= for a static variable */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+                       AddCodeLine ("\tldx\t#$00");
+                       if (flags & CF_CONST) {
+                           if (val == 1) {
+                               AddCodeLine ("\tdec\t%s", lbuf);
+                               AddCodeLine ("\tlda\t%s", lbuf);
+                           } else {
+                               AddCodeLine ("\tsec");
+                               AddCodeLine ("\tlda\t%s", lbuf);
+                               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+                               AddCodeLine ("\tsta\t%s", lbuf);
+                           }
+                       } else {
+                           AddCodeLine ("\tsec");
+                           AddCodeLine ("\tsta\ttmp1");
+                           AddCodeLine ("\tlda\t%s", lbuf);
+                           AddCodeLine ("\tsbc\ttmp1");
+                           AddCodeLine ("\tsta\t%s", lbuf);
+                       }
+                       if ((flags & CF_UNSIGNED) == 0) {
+                           AddCodeLine ("\tbpl\t*+3");
+                           AddCodeLine ("\tdex");
+                           AddCodeHint ("x:!");                /* Invalidate X */
+                       }
+                       break;
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+           AddCodeLine ("\tsec");
+           if (flags & CF_CONST) {
+               AddCodeLine ("\tlda\t%s", lbuf);
+               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tsta\t%s", lbuf);
+               if (val < 0x100) {
+                   label = GetLabel ();
+                   AddCodeLine ("\tbcs\tL%04X", label);
+                   AddCodeLine ("\tdec\t%s+1", lbuf);
+                   g_defloclabel (label);
+                   AddCodeLine ("\tldx\t%s+1", lbuf);
+               } else {
+                   AddCodeLine ("\tlda\t%s+1", lbuf);
+                   AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
+                   AddCodeLine ("\tsta\t%s+1", lbuf);
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tlda\t%s", lbuf);
+               }
+           } else {
+               AddCodeLine ("\tsta\ttmp1");
+               AddCodeLine ("\tlda\t%s", lbuf);
+               AddCodeLine ("\tsbc\ttmp1");
+               AddCodeLine ("\tsta\t%s", lbuf);
+                       AddCodeLine ("\tstx\ttmp1");
+               AddCodeLine ("\tlda\t%s+1", lbuf);
+               AddCodeLine ("\tsbc\ttmp1");
+               AddCodeLine ("\tsta\t%s+1", lbuf);
+               AddCodeLine ("\ttax");
+               AddCodeLine ("\tlda\t%s", lbuf);
+           }
+                   break;
+
+               case CF_LONG:
+           if (flags & CF_CONST) {
+               if (val < 0x100) {
+                   AddCodeLine ("\tldy\t#<(%s)", lbuf);
+                   AddCodeLine ("\tsty\tptr1");
+                   AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+                   if (val == 1) {
+                       AddCodeLine ("\tjsr\tlsubeq1");
+                   } else {
+                       AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+                       AddCodeLine ("\tjsr\tlsubeqa");
+                   }
+               } else {
+                   g_getstatic (flags, label, offs);
+                   g_dec (flags, val);
+                   g_putstatic (flags, label, offs);
+               }
+           } else {
+               AddCodeLine ("\tldy\t#<(%s)", lbuf);
+               AddCodeLine ("\tsty\tptr1");
+               AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+               AddCodeLine ("\tjsr\tlsubeq");
+                   }
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+void g_subeqlocal (unsigned flags, int offs, unsigned long val)
+/* Emit -= for a local variable */
+{
+    /* Calculate the true offset, check it, load it into Y */
+    offs -= oursp;
+    CheckLocalOffs (offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+                   if (flags & CF_FORCECHAR) {
+               ldyconst (offs);
+               AddCodeLine ("\tldx\t#$00");
+                       AddCodeLine ("\tsec");
+               if (flags & CF_CONST) {
+                   AddCodeLine ("\tlda\t(sp),y");
+                   AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               } else {
+                   AddCodeLine ("\tsta\ttmp1");
+                   AddCodeLine ("\tlda\t(sp),y");
+                   AddCodeLine ("\tsbc\ttmp1");
+               }
+                       AddCodeLine ("\tsta\t(sp),y");
+               if ((flags & CF_UNSIGNED) == 0) {
+                   AddCodeLine ("\tbpl\t*+3");
+                   AddCodeLine ("\tdex");
+                   AddCodeHint ("x:!");                /* Invalidate X */
+               }
+                       break;
+                   }
+                   /* FALLTHROUGH */
+
+               case CF_INT:
+           if (flags & CF_CONST) {
+               g_getimmed (flags, val, 0);
+           }
+           if (offs == 0) {
+               AddCodeLine ("\tjsr\tsubeq0sp");
+           } else {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tsubeqysp");
+           }
+                   break;
+
+               case CF_LONG:
+           if (flags & CF_CONST) {
+               g_getimmed (flags, val, 0);
+           }
+           if (offs == 0) {
+               AddCodeLine ("\tjsr\tlsubeq0sp");
+           } else {
+               ldyconst (offs);
+               AddCodeLine ("\tjsr\tlsubeqysp");
+           }
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
+/* Emit -= for the location with address in ax */
+{
+    /* If the offset is too large for a byte register, add the high byte
+     * of the offset to the primary. Beware: We need a special correction
+     * if the offset in the low byte will overflow in the operation.
+     */
+    offs = MakeByteOffs (flags, offs);
+
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+               case CF_CHAR:
+           AddCodeLine ("\tsta\tptr1");
+           AddCodeLine ("\tstx\tptr1+1");
+           if (offs == 0) {
+               AddCodeLine ("\tldx\t#$00");
+               AddCodeLine ("\tlda\t(ptr1,x)");
+                       AddCodeLine ("\tsec");
+               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tsta\t(ptr1,x)");
+           } else {
+                       AddCodeLine ("\tldy\t#$%02X", offs);
+               AddCodeLine ("\tldx\t#$00");
+               AddCodeLine ("\tlda\t(ptr1),y");
+               AddCodeLine ("\tsec");
+               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tsta\t(ptr1),y");
+           }
+           break;
+
+               case CF_INT:
+           if (!FavourSize) {
+               /* Lots of code, use only if size is not important */
+               AddCodeLine ("\tsta\tptr1");
+                       AddCodeLine ("\tstx\tptr1+1");
+               AddCodeLine ("\tldy\t#$%02X", offs);
+               AddCodeLine ("\tlda\t(ptr1),y");
+               AddCodeLine ("\tsec");
+               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tsta\t(ptr1),y");
+               AddCodeLine ("\tpha");
+               AddCodeLine ("\tiny");
+               AddCodeLine ("\tlda\t(ptr1),y");
+               AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
+               AddCodeLine ("\tsta\t(ptr1),y");
+               AddCodeLine ("\ttax");
+               AddCodeLine ("\tpla");
+               break;
+           }
+           /* FALL THROUGH */
+
+               case CF_LONG:
+                   AddCodeLine ("\tjsr\tpushax");      /* Push the address */
+           push (flags);                       /* Correct the internal sp */
+           g_getind (flags, offs);             /* Fetch the value */
+           g_dec (flags, val);                 /* Increment value in primary */
+           g_putind (flags, offs);             /* Store the value back */
+                   break;
+
+               default:
+                   typeerror (flags);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                Add a variable address to the value in ax                 */
+/*****************************************************************************/
+
+
+
+void g_addaddr_local (unsigned flags, int offs)
+/* Add the address of a local variable to ax */
+{
+    /* Add the offset */
+    offs -= oursp;
+    if (offs != 0) {
+       /* We cannot address more then 256 bytes of locals anyway */
+       CheckLocalOffs (offs);
+       AddCodeLine ("\tclc");
+       AddCodeLine ("\tadc\t#$%02X", offs & 0xFF);
+               AddCodeLine ("\tbcc\t*+4");     /* Do also skip the CLC insn below */
+       AddCodeLine ("\tinx");
+       AddCodeHint ("x:!");                    /* Invalidate X */
+    }
+
+    /* Add the current stackpointer value */
+    AddCodeLine ("\tclc");
+    AddCodeLine ("\tadc\tsp");
+    AddCodeLine ("\ttay");
+    AddCodeLine ("\ttxa");
+    AddCodeLine ("\tadc\tsp+1");
+    AddCodeLine ("\ttax");
+    AddCodeLine ("\ttya");
+}
+
+
+
+void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
+/* Add the address of a static variable to ax */
+{
+    /* Create the correct label name */
+    char* lbuf = GetLabelName (flags, label, offs);
+
+    /* Add the address to the current ax value */
+    AddCodeLine ("\tclc");
+    AddCodeLine ("\tadc\t#<(%s)", lbuf);
+    AddCodeLine ("\ttay");
+    AddCodeLine ("\ttxa");
+    AddCodeLine ("\tadc\t#>(%s)", lbuf);
+    AddCodeLine ("\ttax");
+    AddCodeLine ("\ttya");
+}
+
+
+
+/*****************************************************************************/
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+void g_save (unsigned flags)
+/* Copy primary register to hold register. */
+{
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tpha");
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           AddCodeLine ("\tsta\tregsave");
+           AddCodeLine ("\tstx\tregsave+1");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tsaveeax");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_restore (unsigned flags)
+/* Copy hold register to P. */
+{
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tpla");
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           AddCodeLine ("\tlda\tregsave");
+           AddCodeLine ("\tldx\tregsave+1");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tresteax");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_cmp (unsigned flags, unsigned long val)
+/* Immidiate compare. The primary register will not be changed, Z flag
+ * will be set.
+ */
+{
+    /* Check the size and determine operation */
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tbne\t*+4");
+           AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+           break;
+
+        case CF_LONG:
+           Internal ("g_cmp: Long compares not implemented");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+static void oper (unsigned flags, unsigned long val, char** subs)
+/* Encode a binary operation. subs is a pointer to four groups of three
+ * strings:
+ *     0-2     --> Operate on ints
+ *     3-5     --> Operate on unsigneds
+ *     6-8     --> Operate on longs
+ *     9-11    --> Operate on unsigned longs
+ *
+ * The first subroutine names in each string group is used to encode an
+ * operation with a zero constant, the second to encode an operation with
+ * a 8 bit constant, and the third is used in all other cases.
+ */
+{
+    unsigned offs;
+
+    /* Determine the offset into the array */
+    offs = (flags & CF_UNSIGNED)? 3 : 0;
+    switch (flags & CF_TYPE) {
+       case CF_CHAR:
+       case CF_INT:
+           break;
+
+       case CF_LONG:
+           offs += 6;
+           break;
+
+       default:
+           typeerror (flags);
+    }
+
+    /* Encode the operation */
+    if (flags & CF_CONST) {
+       /* Constant value given */
+       if (val == 0 && subs [offs+0]) {
+           /* Special case: constant with value zero */
+           AddCodeLine ("\tjsr\t%s", subs [offs+0]);
+       } else if (val < 0x100 && subs [offs+1]) {
+           /* Special case: constant with high byte zero */
+           ldaconst (val);             /* Load low byte */
+           AddCodeLine ("\tjsr\t%s", subs [offs+1]);
+       } else {
+           /* Others: arbitrary constant value */
+           g_getimmed (flags, val, 0);                 /* Load value */
+           AddCodeLine ("\tjsr\t%s", subs [offs+2]);
+       }
+    } else {
+       /* Value not constant (is already in (e)ax) */
+       AddCodeLine ("\tjsr\t%s", subs [offs+2]);
+    }
+
+    /* The operation will pop it's argument */
+    pop (flags);
+}
+
+
+
+void g_test (unsigned flags)
+/* Force a test to set cond codes right */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\ttax");
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           AddCodeLine ("\tstx\ttmp1");
+           AddCodeLine ("\tora\ttmp1");
+           break;
+
+       case CF_LONG:
+           if (flags & CF_UNSIGNED) {
+               AddCodeLine ("\tjsr\tutsteax");
+           } else {
+               AddCodeLine ("\tjsr\ttsteax");
+           }
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_push (unsigned flags, unsigned long val)
+/* Push the primary register or a constant value onto the stack */
+{
+    unsigned char hi;
+
+    if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
+
+       /* We have a constant 8 or 16 bit value */
+       if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
+
+           /* Handle as 8 bit value */
+           if (FavourSize && val <= 2) {
+               AddCodeLine ("\tjsr\tpushc%d", (int) val);
+           } else {
+               ldaconst (val);
+               AddCodeLine ("\tjsr\tpusha");
+           }
+
+       } else {
+
+           /* Handle as 16 bit value */
+           hi = val >> 8;
+           if (val <= 7) {
+               AddCodeLine ("\tjsr\tpush%u", val);
+           } else if (hi == 0 || hi == 0xFF) {
+               /* Use special function */
+               ldaconst (val);
+                       AddCodeLine ("\tjsr\t%s", (hi == 0)? "pusha0" : "pushaFF");
+           } else {
+               /* Long way ... */
+               g_getimmed (flags, val, 0);
+               AddCodeLine ("\tjsr\tpushax");
+           }
+       }
+
+    } else {
+
+       /* Value is not 16 bit or not constant */
+       if (flags & CF_CONST) {
+           /* Constant 32 bit value, load into eax */
+           g_getimmed (flags, val, 0);
+       }
+
+       /* Push the primary register */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   /* Handle as char */
+                   AddCodeLine ("\tjsr\tpusha");
+                   break;
+               }
+               /* FALL THROUGH */
+           case CF_INT:
+               AddCodeLine ("\tjsr\tpushax");
+               break;
+
+           case CF_LONG:
+               AddCodeLine ("\tjsr\tpusheax");
+               break;
+
+           default:
+               typeerror (flags);
+
+       }
+
+    }
+
+    /* Adjust the stack offset */
+    push (flags);
+}
+
+
+
+void g_swap (unsigned flags)
+/* Swap the primary register and the top of the stack. flags give the type
+ * of *both* values (must have same size).
+ */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           AddCodeLine ("\tjsr\tswapstk");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tswapestk");
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_call (unsigned flags, char* lbl, unsigned argsize)
+/* Call the specified subroutine name */
+{
+    if ((flags & CF_FIXARGC) == 0) {
+       /* Pass arg count */
+       ldyconst (argsize);
+    }
+    AddCodeLine ("\tjsr\t_%s", lbl);
+    oursp += argsize;                  /* callee pops args */
+}
+
+
+
+void g_callind (unsigned flags, unsigned argsize)
+/* Call subroutine with address in AX */
+{
+    if ((flags & CF_FIXARGC) == 0) {
+       /* Pass arg count */
+       ldyconst (argsize);
+    }
+    AddCodeLine ("\tjsr\tcallax");     /* do the call */
+    oursp += argsize;                  /* callee pops args */
+}
+
+
+
+void g_jump (unsigned label)
+/* Jump to specified internal label number */
+{
+    AddCodeLine ("\tjmp\tL%04X", label);
+}
+
+
+
+void g_switch (unsigned flags)
+/* Output switch statement preample */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           AddCodeLine ("\tjsr\tswitch");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tlswitch");
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_case (unsigned flags, unsigned label, unsigned long val)
+/* Create table code for one case selector */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           AddCodeLine ("\t.word\t$%04X, L%04X", val & 0xFFFF, label & 0xFFFF);
+                   break;
+
+       case CF_LONG:
+           AddCodeLine ("\t.dword\t$%08X", val);
+           AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_truejump (unsigned flags, unsigned label)
+/* Jump to label if zero flag clear */
+{
+    if (flags & CF_SHORT) {
+       AddCodeLine ("\tbne\tL%04X", label);
+    } else {
+        AddCodeLine ("\tjne\tL%04X", label);
+    }
+}
+
+
+
+void g_falsejump (unsigned flags, unsigned label)
+/* Jump to label if zero flag set */
+{
+    if (flags & CF_SHORT) {
+       AddCodeLine ("\tbeq\tL%04X", label);
+    } else {
+               AddCodeLine ("\tjeq\tL%04X", label);
+    }
+}
+
+
+
+static void mod_internal (int k, char* verb1, char* verb2)
+{
+    if (k <= 8) {
+       AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
+    } else {
+       CheckLocalOffs (k);
+       ldyconst (k);
+       AddCodeLine ("\tjsr\t%ssp", verb2);
+    }
+}
+
+
+
+void g_space (int space)
+/* Create or drop space on the stack */
+{
+    if (space < 0) {
+       mod_internal (-space, "inc", "addy");
+    } else if (space > 0) {
+       mod_internal (space, "dec", "suby");
+    }
+}
+
+
+
+void g_add (unsigned flags, unsigned long val)
+/* Primary = TOS + Primary */
+{
+    static char* ops [12] = {
+       0,              "tosadda0",     "tosaddax",
+       0,              "tosadda0",     "tosaddax",
+       0,              0,              "tosaddeax",
+       0,              0,              "tosaddeax",
+    };
+
+    if (flags & CF_CONST) {
+       flags &= ~CF_FORCECHAR; // Handle chars as ints
+       g_push (flags & ~CF_CONST, 0);
+    }
+    oper (flags, val, ops);
+}
+
+
+
+void g_sub (unsigned flags, unsigned long val)
+/* Primary = TOS - Primary */
+{
+    static char* ops [12] = {
+       0,              "tossuba0",     "tossubax",
+       0,              "tossuba0",     "tossubax",
+       0,              0,              "tossubeax",
+       0,              0,              "tossubeax",
+    };
+
+    if (flags & CF_CONST) {
+       flags &= ~CF_FORCECHAR; // Handle chars as ints
+       g_push (flags & ~CF_CONST, 0);
+    }
+    oper (flags, val, ops);
+}
+
+
+
+void g_rsub (unsigned flags, unsigned long val)
+/* Primary = Primary - TOS */
+{
+    static char* ops [12] = {
+       0,              "tosrsuba0",    "tosrsubax",
+       0,              "tosrsuba0",    "tosrsubax",
+       0,              0,              "tosrsubeax",
+       0,              0,              "tosrsubeax",
+    };
+    oper (flags, val, ops);
+}
+
+
+
+void g_mul (unsigned flags, unsigned long val)
+/* Primary = TOS * Primary */
+{
+    static char* ops [12] = {
+       0,              "tosmula0",     "tosmulax",
+       0,              "tosumula0",    "tosumulax",
+       0,              0,              "tosmuleax",
+       0,              0,              "tosumuleax",
+    };
+
+    int p2;
+
+    /* Do strength reduction if the value is constant and a power of two */
+    if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
+       /* Generate a shift instead */
+       g_asl (flags, p2);
+       return;
+    }
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   /* Handle some special cases */
+                   switch (val) {
+
+                       case 3:
+                           AddCodeLine ("\tsta\ttmp1");
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\tclc");
+                           AddCodeLine ("\tadc\ttmp1");
+                           return;
+
+                       case 5:
+                           AddCodeLine ("\tsta\ttmp1");
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\tclc");
+                           AddCodeLine ("\tadc\ttmp1");
+                           return;
+
+                       case 10:
+                           AddCodeLine ("\tsta\ttmp1");
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\tasl\ta");
+                           AddCodeLine ("\tclc");
+                           AddCodeLine ("\tadc\ttmp1");
+                           AddCodeLine ("\tasl\ta");
+                           return;
+                   }
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               break;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       flags &= ~CF_FORCECHAR; // Handle chars as ints
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_div (unsigned flags, unsigned long val)
+/* Primary = TOS / Primary */
+{
+    static char* ops [12] = {
+       0,              "tosdiva0",     "tosdivax",
+       0,              "tosudiva0",    "tosudivax",
+       0,              0,              "tosdiveax",
+       0,              0,              "tosudiveax",
+    };
+
+    /* Do strength reduction if the value is constant and a power of two */
+    int p2;
+    if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
+       /* Generate a shift instead */
+       g_asr (flags, p2);
+    } else {
+       /* Generate a division */
+       if (flags & CF_CONST) {
+           /* lhs is not on stack */
+           flags &= ~CF_FORCECHAR;     // Handle chars as ints
+           g_push (flags & ~CF_CONST, 0);
+       }
+       oper (flags, val, ops);
+    }
+}
+
+
+
+void g_mod (unsigned flags, unsigned long val)
+/* Primary = TOS % Primary */
+{
+    static char* ops [12] = {
+       0,              "tosmoda0",     "tosmodax",
+       0,              "tosumoda0",    "tosumodax",
+       0,              0,              "tosmodeax",
+       0,              0,              "tosumodeax",
+    };
+    int p2;
+
+    /* Check if we can do some cost reduction */
+    if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
+       /* We can do that with an AND operation */
+       g_and (flags, val - 1);
+    } else {
+       /* Do it the hard way... */
+       if (flags & CF_CONST) {
+           /* lhs is not on stack */
+           flags &= ~CF_FORCECHAR;     // Handle chars as ints
+           g_push (flags & ~CF_CONST, 0);
+       }
+       oper (flags, val, ops);
+    }
+}
+
+
+
+void g_or (unsigned flags, unsigned long val)
+/* Primary = TOS | Primary */
+{
+    static char* ops [12] = {
+       0,              "tosora0",      "tosorax",
+       0,              "tosora0",      "tosorax",
+       0,              0,              "tosoreax",
+       0,              0,              "tosoreax",
+    };
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   if ((val & 0xFF) != 0xFF) {
+                               AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if (val <= 0xFF) {
+                   AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               if (val <= 0xFF) {
+                   AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+                   return;
+               }
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_xor (unsigned flags, unsigned long val)
+/* Primary = TOS ^ Primary */
+{
+    static char* ops [12] = {
+       0,              "tosxora0",     "tosxorax",
+       0,              "tosxora0",     "tosxorax",
+       0,              0,              "tosxoreax",
+       0,              0,              "tosxoreax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   if ((val & 0xFF) != 0) {
+                               AddCodeLine ("\teor\t#$%02X", val & 0xFF);
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if (val <= 0xFF) {
+                   if (val != 0) {
+                       AddCodeLine ("\teor\t#$%02X", val);
+                   }
+                   return;
+               } else if ((val & 0xFF) == 0) {
+                   AddCodeLine ("\tpha");
+                   AddCodeLine ("\ttxa");
+                   AddCodeLine ("\teor\t#$%02X", (val >> 8) & 0xFF);
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tpla");
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               if (val <= 0xFF) {
+                   if (val != 0) {
+                               AddCodeLine ("\teor\t#$%02X", val & 0xFF);
+                   }
+                   return;
+               }
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_and (unsigned flags, unsigned long val)
+/* Primary = TOS & Primary */
+{
+    static char* ops [12] = {
+       0,              "tosanda0",     "tosandax",
+       0,              "tosanda0",     "tosandax",
+       0,              0,              "tosandeax",
+       0,              0,              "tosandeax",
+    };
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+                   return;
+               }
+               /* FALLTHROUGH */
+           case CF_INT:
+               if ((val & 0xFFFF) != 0xFFFF) {
+                           if (val <= 0xFF) {
+                       ldxconst (0);
+                       if (val == 0) {
+                           ldaconst (0);
+                       } else if (val != 0xFF) {
+                           AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+                       }
+                   } else if ((val & 0xFF00) == 0xFF00) {
+                       AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+                   } else if ((val & 0x00FF) == 0x0000) {
+                       AddCodeLine ("\ttxa");
+                       AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
+                       AddCodeLine ("\ttax");
+                       ldaconst (0);
+                   } else {
+                       AddCodeLine ("\ttay");
+                       AddCodeLine ("\ttxa");
+                       AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
+                       AddCodeLine ("\ttax");
+                       AddCodeLine ("\ttya");
+                       if ((val & 0x00FF) != 0x00FF) {
+                           AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+                       }
+                   }
+               }
+               return;
+
+           case CF_LONG:
+               if (val <= 0xFF) {
+                   ldxconst (0);
+                   AddCodeLine ("\tstx\tsreg+1");
+                   AddCodeLine ("\tstx\tsreg");
+                   if ((val & 0xFF) != 0xFF) {
+                        AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+                   }
+                   return;
+               } else if (val == 0xFF00) {
+                   ldaconst (0);
+                   AddCodeLine ("\tsta\tsreg+1");
+                   AddCodeLine ("\tsta\tsreg");
+                   return;
+               }
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_asr (unsigned flags, unsigned long val)
+/* Primary = TOS >> Primary */
+{
+    static char* ops [12] = {
+       0,              "tosasra0",     "tosasrax",
+       0,              "tosshra0",     "tosshrax",
+       0,              0,              "tosasreax",
+       0,              0,              "tosshreax",
+    };
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+           case CF_INT:
+               if (val >= 1 && val <= 3) {
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tshrax%ld", val);
+                   } else {
+                       AddCodeLine ("\tjsr\tasrax%ld", val);
+                   }
+                   return;
+               } else if (val == 8 && (flags & CF_UNSIGNED)) {
+                   AddCodeLine ("\ttxa");
+                   ldxconst (0);
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               if (val >= 1 && val <= 3) {
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tshreax%ld", val);
+                   } else {
+                       AddCodeLine ("\tjsr\tasreax%ld", val);
+                   }
+                   return;
+               } else if (val == 8 && (flags & CF_UNSIGNED)) {
+                   AddCodeLine ("\ttxa");
+                   AddCodeLine ("\tldx\tsreg");
+                   AddCodeLine ("\tldy\tsreg+1");
+                   AddCodeLine ("\tsty\tsreg");
+                   AddCodeLine ("\tldy\t#$00");
+                   AddCodeLine ("\tsty\tsreg+1");
+                   return;
+               } else if (val == 16) {
+                   AddCodeLine ("\tldy\t#$00");
+                   AddCodeLine ("\tldx\tsreg+1");
+                   if ((flags & CF_UNSIGNED) == 0) {
+                       AddCodeLine ("\tbpl\t*+3");
+                       AddCodeLine ("\tdey");
+                       AddCodeHint ("y:!");
+                   }
+                   AddCodeLine ("\tlda\tsreg");
+                   AddCodeLine ("\tsty\tsreg+1");
+                   AddCodeLine ("\tsty\tsreg");
+                   return;
+               }
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_asl (unsigned flags, unsigned long val)
+/* Primary = TOS << Primary */
+{
+    static char* ops [12] = {
+       0,              "tosasla0",     "tosaslax",
+       0,              "tosshla0",     "tosshlax",
+       0,              0,              "tosasleax",
+       0,              0,              "tosshleax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+           case CF_INT:
+               if (val >= 1 && val <= 3) {
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tshlax%ld", val);
+                   } else {
+                       AddCodeLine ("\tjsr\taslax%ld", val);
+                   }
+                   return;
+               } else if (val == 8) {
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tlda\t#$00");
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               if (val >= 1 && val <= 3) {
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tshleax%ld", val);
+                   } else {
+                       AddCodeLine ("\tjsr\tasleax%ld", val);
+                   }
+                   return;
+               } else if (val == 8) {
+                   AddCodeLine ("\tldy\tsreg");
+                   AddCodeLine ("\tsty\tsreg+1");
+                   AddCodeLine ("\tstx\tsreg");
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tlda\t#$00");
+                   return;
+               } else if (val == 16) {
+                   AddCodeLine ("\tstx\tsreg+1");
+                   AddCodeLine ("\tsta\tsreg");
+                   AddCodeLine ("\tlda\t#$00");
+                   AddCodeLine ("\ttax");
+                   return;
+               }
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_neg (unsigned flags)
+/* Primary = -Primary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           AddCodeLine ("\tjsr\tnegax");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tnegeax");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_bneg (unsigned flags)
+/* Primary = !Primary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           AddCodeLine ("\tjsr\tbnega");
+           break;
+
+       case CF_INT:
+           AddCodeLine ("\tjsr\tbnegax");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tbnegeax");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_com (unsigned flags)
+/* Primary = ~Primary */
+{
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+       case CF_INT:
+           AddCodeLine ("\tjsr\tcomplax");
+           break;
+
+       case CF_LONG:
+           AddCodeLine ("\tjsr\tcompleax");
+           break;
+
+       default:
+           typeerror (flags);
+    }
+}
+
+
+
+void g_inc (unsigned flags, unsigned long val)
+/* Increment the primary register by a given number */
+{
+    /* Don't inc by zero */
+    if (val == 0) {
+       return;
+    }
+
+    /* Generate code for the supported types */
+    flags &= ~CF_CONST;
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tclc");
+               AddCodeLine ("\tadc\t#$%02X", val & 0xFF);
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           if (FavourSize) {
+               /* Use jsr calls */
+               if (val <= 8) {
+                   AddCodeLine ("\tjsr\tincax%u", val);
+               } else if (val <= 255) {
+                   ldyconst (val);
+                   AddCodeLine ("\tjsr\tincaxy");
+               } else {
+                   g_add (flags | CF_CONST, val);
+               }
+           } else {
+               /* Inline the code */
+               if (val < 0x300) {
+                   if ((val & 0xFF) != 0) {
+                       AddCodeLine ("\tclc");
+                       AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
+                       AddCodeLine ("\tbcc\t*+3");
+                       AddCodeLine ("\tinx");
+                       /* Tell the optimizer that the X register may be invalid */
+                               AddCodeHint ("x:!");
+                   }
+                   if (val >= 0x100) {
+                       AddCodeLine ("\tinx");
+                   }
+                   if (val >= 0x200) {
+                       AddCodeLine ("\tinx");
+                   }
+               } else {
+                   AddCodeLine ("\tclc");
+                   if ((val & 0xFF) != 0) {
+                       AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
+                       /* Tell the optimizer that the X register may be invalid */
+                       AddCodeHint ("x:!");
+                   }
+                   AddCodeLine ("\tpha");
+                   AddCodeLine ("\ttxa");
+                   AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
+                   AddCodeLine ("\ttax");
+                   AddCodeLine ("\tpla");
+               }
+           }
+           break;
+
+               case CF_LONG:
+           if (val <= 255) {
+               ldyconst (val);
+               AddCodeLine ("\tjsr\tinceaxy");
+           } else {
+               g_add (flags | CF_CONST, val);
+           }
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+void g_dec (unsigned flags, unsigned long val)
+/* Decrement the primary register by a given number */
+{
+    /* Generate code for the supported types */
+    flags &= ~CF_CONST;
+    switch (flags & CF_TYPE) {
+
+       case CF_CHAR:
+           if (flags & CF_FORCECHAR) {
+               AddCodeLine ("\tsec");
+               AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+               break;
+           }
+           /* FALLTHROUGH */
+
+       case CF_INT:
+           if (val <= 2) {
+               AddCodeLine ("\tjsr\tdecax%d", (int) val);
+           } else if (val <= 255) {
+               ldyconst (val);
+               AddCodeLine ("\tjsr\tdecaxy");
+           } else {
+               g_sub (flags | CF_CONST, val);
+           }
+           break;
+
+       case CF_LONG:
+           if (val <= 255) {
+               ldyconst (val);
+               AddCodeLine ("\tjsr\tdeceaxy");
+           } else {
+               g_sub (flags | CF_CONST, val);
+           }
+           break;
+
+       default:
+           typeerror (flags);
+
+    }
+}
+
+
+
+/*
+ * Following are the conditional operators. They compare the TOS against
+ * the primary and put a literal 1 in the primary if the condition is
+ * true, otherwise they clear the primary register
+ */
+
+
+
+void g_eq (unsigned flags, unsigned long val)
+/* Test for equal */
+{
+    static char* ops [12] = {
+       "toseq00",      "toseqa0",      "toseqax",
+       "toseq00",      "toseqa0",      "toseqax",
+       0,              0,              "toseqeax",
+       0,              0,              "toseqeax",
+    };
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tjsr\tbooleq");
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+                       AddCodeLine ("\tbne\t*+4");
+               AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tjsr\tbooleq");
+               return;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_ne (unsigned flags, unsigned long val)
+/* Test for not equal */
+{
+    static char* ops [12] = {
+       "tosne00",      "tosnea0",      "tosneax",
+       "tosne00",      "tosnea0",      "tosneax",
+       0,              0,              "tosneeax",
+       0,              0,              "tosneeax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tjsr\tboolne");
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+               AddCodeLine ("\tbne\t*+4");
+               AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+               AddCodeLine ("\tjsr\tboolne");
+               return;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_lt (unsigned flags, unsigned long val)
+/* Test for less than */
+{
+    static char* ops [12] = {
+       "toslt00",      "toslta0",      "tosltax",
+       "tosult00",     "tosulta0",     "tosultax",
+       0,              0,              "toslteax",
+       0,              0,              "tosulteax",
+    };
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       /* Give a warning in some special cases */
+       if ((flags & CF_UNSIGNED) && val == 0) {
+           Warning (WARN_COND_NEVER_TRUE);
+       }
+
+       /* Look at the type */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tboolult");
+                   } else {
+                       AddCodeLine ("\tjsr\tboollt");
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if ((flags & CF_UNSIGNED) == 0 && val == 0) {
+                   /* If we have a signed compare against zero, we only need to
+                    * test the high byte.
+                    */
+                   AddCodeLine ("\ttxa");
+                   AddCodeLine ("\tjsr\tboollt");
+                   return;
+               }
+               /* Direct code only for unsigned data types */
+               if (flags & CF_UNSIGNED) {
+                   AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+                           AddCodeLine ("\tbne\t*+4");
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tjsr\tboolult");
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_le (unsigned flags, unsigned long val)
+/* Test for less than or equal to */
+{
+    static char* ops [12] = {
+       "tosle00",      "toslea0",      "tosleax",
+       "tosule00",     "tosulea0",     "tosuleax",
+       0,              0,              "tosleeax",
+       0,              0,              "tosuleeax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       /* Look at the type */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tboolule");
+                   } else {
+                       AddCodeLine ("\tjsr\tboolle");
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if (flags & CF_UNSIGNED) {
+                   AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+                           AddCodeLine ("\tbne\t*+4");
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tjsr\tboolule");
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_gt (unsigned flags, unsigned long val)
+/* Test for greater than */
+{
+    static char* ops [12] = {
+       "tosgt00",      "tosgta0",      "tosgtax",
+       "tosugt00",     "tosugta0",     "tosugtax",
+       0,              0,              "tosgteax",
+       0,              0,              "tosugteax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       /* Look at the type */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   if (flags & CF_UNSIGNED) {
+                       /* If we have a compare > 0, we will replace it by
+                        * != 0 here, since both are identical but the latter
+                        * is easier to optimize.
+                        */
+                       if (val & 0xFF) {
+                           AddCodeLine ("\tjsr\tboolugt");
+                       } else {
+                           AddCodeLine ("\tjsr\tboolne");
+                       }
+                   } else {
+                       AddCodeLine ("\tjsr\tboolgt");
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if (flags & CF_UNSIGNED) {
+                   /* If we have a compare > 0, we will replace it by
+                    * != 0 here, since both are identical but the latter
+                    * is easier to optimize.
+                    */
+                   if ((val & 0xFFFF) == 0) {
+                       AddCodeLine ("\tstx\ttmp1");
+                       AddCodeLine ("\tora\ttmp1");
+                       AddCodeLine ("\tjsr\tboolne");
+                   } else {
+                               AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+                       AddCodeLine ("\tbne\t*+4");
+                       AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                               AddCodeLine ("\tjsr\tboolugt");
+                   }
+                   return;
+                       }
+               break;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+void g_ge (unsigned flags, unsigned long val)
+/* Test for greater than or equal to */
+{
+    static char* ops [12] = {
+       "tosge00",      "tosgea0",      "tosgeax",
+       "tosuge00",     "tosugea0",     "tosugeax",
+       0,              0,              "tosgeeax",
+       0,              0,              "tosugeeax",
+    };
+
+
+    /* If the right hand side is const, the lhs is not on stack but still
+     * in the primary register.
+     */
+    if (flags & CF_CONST) {
+
+       /* Give a warning in some special cases */
+       if ((flags & CF_UNSIGNED) && val == 0) {
+           Warning (WARN_COND_ALWAYS_TRUE);
+       }
+
+       /* Look at the type */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               if (flags & CF_FORCECHAR) {
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   if (flags & CF_UNSIGNED) {
+                       AddCodeLine ("\tjsr\tbooluge");
+                   } else {
+                       AddCodeLine ("\tjsr\tboolge");
+                   }
+                   return;
+               }
+               /* FALLTHROUGH */
+
+           case CF_INT:
+               if (flags & CF_UNSIGNED) {
+                           AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+                           AddCodeLine ("\tbne\t*+4");
+                   AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+                   AddCodeLine ("\tjsr\tbooluge");
+                   return;
+               }
+               break;
+
+           case CF_LONG:
+               break;
+
+           default:
+               typeerror (flags);
+       }
+
+       /* If we go here, we didn't emit code. Push the lhs on stack and fall
+        * into the normal, non-optimized stuff.
+        */
+       g_push (flags & ~CF_CONST, 0);
+
+    }
+
+    /* Use long way over the stack */
+    oper (flags, val, ops);
+}
+
+
+
+/*****************************************************************************/
+/*                        Allocating static storage                         */
+/*****************************************************************************/
+
+
+
+void g_res (unsigned n)
+/* reserve static storage, n bytes */
+{
+    AddCodeLine ("\t.res\t%u", n);
+}
+
+
+
+void g_defdata (unsigned flags, unsigned long val, unsigned offs)
+/* Define data with the size given in flags */
+{
+    if (flags & CF_CONST) {
+
+       /* Numeric constant */
+       switch (flags & CF_TYPE) {
+
+           case CF_CHAR:
+               AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
+               break;
+
+           case CF_INT:
+               AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
+               break;
+
+           case CF_LONG:
+               AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
+               break;
+
+           default:
+               typeerror (flags);
+               break;
+
+       }
+
+    } else {
+
+       /* Create the correct label name */
+       const char* Label = GetLabelName (flags, val, offs);
+
+       /* Labels are always 16 bit */
+       AddCodeLine ("\t.word\t%s", Label);
+
+    }
+}
+
+
+
+void g_defbytes (const unsigned char* Bytes, unsigned Count)
+/* output a row of bytes as a constant */
+{
+    unsigned Chunk;
+    char Buf [128];
+    char* B;
+
+    /* Output the stuff */
+    while (Count) {
+
+       /* How many go into this line? */
+       if ((Chunk = Count) > 16) {
+           Chunk = 16;
+       }
+       Count -= Chunk;
+
+       /* Output one line */
+       strcpy (Buf, "\t.byte\t");
+               B = Buf + 7;
+       do {
+           B += sprintf (B, "$%02X", *Bytes++ & 0xFF);
+           if (--Chunk) {
+               *B++ = ',';
+           }
+       } while (Chunk);
+
+       /* Output the line */
+       AddCodeLine (Buf);
+    }
+}
+
+
+
+void g_zerobytes (unsigned n)
+/* Output n bytes of data initialized with zero */
+{
+    AddCodeLine ("\t.res\t%u", n);
+}
+
+
+
+/*****************************************************************************/
+/*                         Inlined known functions                          */
+/*****************************************************************************/
+
+
+
+void g_strlen (unsigned flags, unsigned long val, unsigned offs)
+/* Inline the strlen() function */
+{
+    /* We need a label in both cases */
+    unsigned label = GetLabel ();
+
+    /* Two different encodings */
+    if (flags & CF_CONST) {
+
+       /* The address of the string is constant. Create the correct label name */
+       char* lbuf = GetLabelName (flags, val, offs);
+
+       /* Generate the strlen code */
+       AddCodeLine ("\tldy\t#$FF");
+       g_defloclabel (label);
+       AddCodeLine ("\tiny");
+       AddCodeLine ("\tlda\t%s,y", lbuf);
+       AddCodeLine ("\tbne\tL%04X", label);
+       AddCodeLine ("\ttya");
+       AddCodeLine ("\tldx\t#$00");
+
+    } else {
+
+               /* Address not constant but in primary */
+       if (FavourSize) {
+           /* This is too much code, so call strlen instead of inlining */
+           AddCodeLine ("\tjsr\t_strlen");
+       } else {
+           /* Inline the function */
+           AddCodeLine ("\tsta\tptr1");
+           AddCodeLine ("\tstx\tptr1+1");
+           AddCodeLine ("\tldy\t#$FF");
+           g_defloclabel (label);
+           AddCodeLine ("\tiny");
+           AddCodeLine ("\tlda\t(ptr1),y");
+           AddCodeLine ("\tbne\tL%04X", label);
+           AddCodeLine ("\ttya");
+           AddCodeLine ("\tldx\t#$00");
+       }
+    }
+}
+
+
+
diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h
new file mode 100644 (file)
index 0000000..33bad1d
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * codegen.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ */
+
+
+
+#ifndef CODEGEN_H
+#define CODEGEN_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Code generator flags.
+ * Note: The type flags are designed so that a smaller type may override a
+ * larger one by or'ing it into the existing one.
+ */
+#define CF_NONE                0x0000  /* No special flags */
+
+#define CF_TYPE                0x000F  /* Mask for operand type */
+#define CF_CHAR                0x0003  /* Operation on characters */
+#define CF_INT         0x0001  /* Operation on ints */
+#define CF_PTR         CF_INT  /* Alias for readability */
+#define CF_LONG                0x0000  /* Operation on longs */
+
+#define CF_UNSIGNED            0x0010  /* Value is unsigned */
+#define CF_CONST       0x0020  /* Constant value available */
+#define CF_CONSTADDR   0x0040  /* Constant address value available */
+#define CF_TEST                0x0080  /* Test value */
+#define CF_FIXARGC             0x0100  /* Function has fixed arg count */
+#define CF_FORCECHAR   0x0200  /* Handle chars as chars, not ints */
+#define CF_SHORT       0x0400  /* Use short addressing */
+#define CF_REG         0x0800  /* Value is in primary register */
+
+/* Type of static address */
+#define CF_ADDRMASK            0xF000  /* Type of address */
+#define CF_STATIC      0x0000  /* Static local */
+#define CF_EXTERNAL    0x1000  /* Static external */
+#define CF_ABSOLUTE    0x2000  /* Numeric absolute address */
+#define CF_LOCAL               0x4000  /* Auto variable */
+#define CF_REGVAR      0x8000  /* Register variable */
+
+
+
+/* Compiler relative stackpointer */
+extern int oursp;
+
+
+
+/*****************************************************************************/
+/*                           Pre- and postamble                             */
+/*****************************************************************************/
+
+
+
+void g_preamble (void);
+/* Generate the assembler code preamble */
+
+void g_postamble (void);
+/* Generate assembler code postamble */
+
+
+
+/*****************************************************************************/
+/*                             Segment support                              */
+/*****************************************************************************/
+
+
+
+void g_usecode (void);
+/* Switch to the code segment */
+
+void g_userodata (void);
+/* Switch to the read only data segment */
+
+void g_usedata (void);
+/* Switch to the data segment */
+
+void g_usebss (void);
+/* Switch to the bss segment */
+
+void g_codename (const char* Name);
+/* Set the name of the CODE segment */
+
+void g_rodataname (const char* Name);
+/* Set the name of the RODATA segment */
+
+void g_dataname (const char* Name);
+/* Set the name of the DATA segment */
+
+void g_bssname (const char* Name);
+/* Set the name of the BSS segment */
+
+
+
+/*****************************************************************************/
+/*                     Functions handling local labels                      */
+/*****************************************************************************/
+
+
+
+void g_defloclabel (unsigned label);
+/* Define a local label */
+
+
+
+/*****************************************************************************/
+/*                    Functions handling global labels                      */
+/*****************************************************************************/
+
+
+
+void g_defgloblabel (const char* Name);
+/* Define a global label with the given name */
+
+void g_defexport (const char* Name, int ZP);
+/* Export the given label */
+
+void g_defimport (const char* Name, int ZP);
+/* Import the given label */
+
+
+
+/*****************************************************************************/
+/*                                  stack                                   */
+/*****************************************************************************/
+
+
+
+int pop (unsigned flags);
+/* Pop an argument of the given size */
+
+int push (unsigned flags);
+/* Push an argument of the given size */
+
+unsigned sizeofarg (unsigned flags);
+/* Return the size of a function argument type that is encoded in flags */
+
+
+
+/*****************************************************************************/
+/*                   type conversion and similiar stuff                     */
+/*****************************************************************************/
+
+
+
+void g_toslong (unsigned flags);
+/* Make sure, the value on TOS is a long. Convert if necessary */
+
+void g_tosint (unsigned flags);
+/* Make sure, the value on TOS is an int. Convert if necessary */
+
+void g_reglong (unsigned flags);
+/* Make sure, the value in the primary register a long. Convert if necessary */
+
+unsigned g_typeadjust (unsigned lhs, unsigned rhs);
+/* Adjust the integer operands before doing a binary operation. lhs is a flags
+ * value, that corresponds to the value on TOS, rhs corresponds to the value
+ *  in (e)ax. The return value is the the flags value for the resulting type.
+ */
+
+unsigned g_typecast (unsigned lhs, unsigned rhs);
+/* Cast the value in the primary register to the operand size that is flagged
+ * by the lhs value. Return the result value.
+ */
+
+void g_scale (unsigned flags, long val);
+/* Scale the value in the primary register by the given value. If val is positive,
+ * scale up, is val is negative, scale down. This function is used to scale
+ * the operands or results of pointer arithmetic by the size of the type, the
+ * pointer points to.
+ */
+
+
+
+/*****************************************************************************/
+/*                                 Function entry and exit                          */
+/*****************************************************************************/
+
+
+
+void g_enter (unsigned flags, const char* Name, unsigned argsize);
+/* Function prologue */
+
+void g_leave (int flags, int val);
+/* Function epilogue */
+
+
+
+/*****************************************************************************/
+/*                           Register variables                             */
+/*****************************************************************************/
+
+
+
+void g_save_regvars (int RegOffs, unsigned Bytes);
+/* Save register variables */
+
+void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes);
+/* Restore register variables */
+
+
+
+/*****************************************************************************/
+/*                          Fetching memory cells                           */
+/*****************************************************************************/
+
+
+
+void g_getimmed (unsigned flags, unsigned long val, unsigned offs);
+void g_getstatic (unsigned flags, unsigned long label, unsigned offs);
+void g_getlocal (unsigned flags, int offs);
+void g_getind (unsigned flags, unsigned offs);
+void g_leasp (int offs);
+
+
+
+/*****************************************************************************/
+/*                            Store into memory                             */
+/*****************************************************************************/
+
+
+
+void g_putstatic (unsigned flags, unsigned long label, unsigned offs);
+/* Store the primary register into the specified static memory cell */
+
+void g_putlocal (unsigned flags, int offs);
+/* Put data into local object. */
+
+void g_putind (unsigned flags, unsigned offs);
+/* Store the specified object type in the primary register at the address
+ * on the top of the stack
+ */
+
+
+
+/*****************************************************************************/
+/*             Adds and subs of variables fix a fixed address               */
+/*****************************************************************************/
+
+
+
+void g_addlocal (unsigned flags, int offs);
+/* Add a local variable to ax */
+
+void g_addstatic (unsigned flags, unsigned long label, unsigned offs);
+/* Add a static variable to ax */
+
+
+
+/*****************************************************************************/
+/*            Compares of ax with a variable with fixed address             */
+/*****************************************************************************/
+
+
+
+void g_cmplocal (unsigned flags, int offs);
+/* Compare a local variable to ax */
+
+void g_cmpstatic (unsigned flags, unsigned label, unsigned offs);
+/* Compare a static variable to ax */
+
+
+
+/*****************************************************************************/
+/*                          Special op= functions                           */
+/*****************************************************************************/
+
+
+
+void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
+                           unsigned long val);
+/* Emit += for a static variable */
+
+void g_addeqlocal (unsigned flags, int offs, unsigned long val);
+/* Emit += for a local variable */
+
+void g_addeqind (unsigned flags, unsigned offs, unsigned long val);
+/* Emit += for the location with address in ax */
+
+void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
+                           unsigned long val);
+/* Emit -= for a static variable */
+
+void g_subeqlocal (unsigned flags, int offs, unsigned long val);
+/* Emit -= for a local variable */
+
+void g_subeqind (unsigned flags, unsigned offs, unsigned long val);
+/* Emit -= for the location with address in ax */
+
+
+
+/*****************************************************************************/
+/*                        Add a variable address to the value in ax                 */
+/*****************************************************************************/
+
+
+
+void g_addaddr_local (unsigned flags, int offs);
+/* Add the address of a local variable to ax */
+
+void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs);
+/* Add the address of a static variable to ax */
+
+
+
+/*****************************************************************************/
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+void g_save (unsigned flags);
+void g_restore (unsigned flags);
+
+void g_cmp (unsigned flags, unsigned long val);
+/* Immidiate compare. The primary register will not be changed, Z flag
+ * will be set.
+ */
+
+void g_test (unsigned flags);
+void g_push (unsigned flags, unsigned long val);
+void g_swap (unsigned flags);
+void g_call (unsigned flags, char *lbl, unsigned argsize);
+void g_callind (unsigned flags, unsigned argsize);
+void g_jump (unsigned label);
+void g_switch (unsigned flags);
+
+void g_case (unsigned flags, unsigned label, unsigned long val);
+/* Create table code for one case selector */
+
+void g_truejump (unsigned flags, unsigned label);
+/* Jump to label if zero flag clear */
+
+void g_falsejump (unsigned flags, unsigned label);
+/* Jump to label if zero flag set */
+
+void g_space (int space);
+/* Create or drop space on the stack */
+
+void g_add (unsigned flags, unsigned long val);
+void g_sub (unsigned flags, unsigned long val);
+void g_rsub (unsigned flags, unsigned long val);
+void g_mul (unsigned flags, unsigned long val);
+void g_div (unsigned flags, unsigned long val);
+void g_mod (unsigned flags, unsigned long val);
+void g_or (unsigned flags, unsigned long val);
+void g_xor (unsigned flags, unsigned long val);
+void g_and (unsigned flags, unsigned long val);
+void g_asr (unsigned flags, unsigned long val);
+void g_asl (unsigned flags, unsigned long val);
+void g_neg (unsigned flags);
+void g_bneg (unsigned flags);
+void g_com (unsigned flags);
+void g_inc (unsigned flags, unsigned long n);
+void g_dec (unsigned flags, unsigned long n);
+void g_eq (unsigned flags, unsigned long val);
+void g_ne (unsigned flags, unsigned long val);
+void g_lt (unsigned flags, unsigned long val);
+void g_le (unsigned flags, unsigned long val);
+void g_gt (unsigned flags, unsigned long val);
+void g_ge (unsigned flags, unsigned long val);
+void g_makebool (unsigned flags);
+void outdat (int n);
+void g_res (unsigned n);
+
+void g_defdata (unsigned flags, unsigned long val, unsigned offs);
+/* Define data with the size given in flags */
+
+void g_defbytes (const unsigned char *bytes, unsigned count);
+void g_zerobytes (unsigned n);
+
+
+
+/*****************************************************************************/
+/*                         Inlined known functions                          */
+/*****************************************************************************/
+
+
+
+void g_strlen (unsigned flags, unsigned long val, unsigned offs);
+/* Inline the strlen() function */
+
+
+
+/* End of codegen.h */
+#endif
+
+
diff --git a/src/cc65/copyleft.jrd b/src/cc65/copyleft.jrd
new file mode 100644 (file)
index 0000000..f6d33c4
--- /dev/null
@@ -0,0 +1,32 @@
+-*- Mode: Text -*-
+
+   This is the copyright notice for RA65, LINK65, LIBR65, and other
+Atari 8-bit programs.  Said programs are Copyright 1989, by John R.
+Dunning.  All rights reserved, with the following exceptions:
+
+    Anyone may copy or redistribute these programs, provided that:
+
+1:  You don't charge anything for the copy.  It is permissable to 
+    charge a nominal fee for media, etc.
+
+2:  All source code and documentation for the programs is made
+    available as part of the distribution.
+
+3:  This copyright notice is preserved verbatim, and included in 
+    the distribution.
+
+    You are allowed to modify these programs, and redistribute the 
+modified versions, provided that the modifications are clearly noted.
+
+    There is NO WARRANTY with this software, it comes as is, and is
+distributed in the hope that it may be useful.
+
+    This copyright notice applies to any program which contains
+this text, or the refers to this file.
+
+    This copyright notice is based on the one published by the Free
+Software Foundation, sometimes known as the GNU project.  The idea
+is the same as theirs, ie the software is free, and is intended to
+stay that way.  Everybody has the right to copy, modify, and re-
+distribute this software.  Nobody has the right to prevent anyone
+else from copying, modifying or redistributing it.
diff --git a/src/cc65/ctrans.c b/src/cc65/ctrans.c
new file mode 100644 (file)
index 0000000..1c7f484
--- /dev/null
@@ -0,0 +1,137 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                ctrans.c                                  */
+/*                                                                           */
+/*            Character set translation for the cc65 C compiler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+#include "ctrans.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+static unsigned char CTNone [256] = {
+    /* No system - no translation */
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+    0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char CTAtari [256] = {
+    /* ASCII -> ATASCII */
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x7E,0x08,0x7F,0x9B,0x0B,0x7D,0x0D,0x0E,0x0F,
+    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+    0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char CTPET [256] = {
+    /* ASCII -> PETSCII */
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+    0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0x5C,0x5D,0x5E,0x5F,
+    0xC0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+    0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xDB,0xDC,0xDD,0xDE,0xDF,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char* CTab [TGT_COUNT] = {
+    CTNone,            /* No system */
+    CTAtari,           /* Atari */
+    CTPET,             /* C64 */
+    CTPET,             /* C128 */
+    CTPET,             /* ACE */
+    CTPET,             /* Plus/4 */
+    CTPET,             /* CBM610 */
+    CTPET,             /* PET */
+    CTNone,            /* NES */
+    CTNone,            /* Apple2 */
+    CTPET,             /* GEOS */
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int ctrans (unsigned char C)
+/* Translate a character from source charset into target charset */
+{
+    /* Translate for the given system */
+    return CTab [Target][C];
+}
+
+
+
diff --git a/src/cc65/ctrans.h b/src/cc65/ctrans.h
new file mode 100644 (file)
index 0000000..01ec289
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                ctrans.h                                  */
+/*                                                                           */
+/*            Character set translation for the cc65 C compiler             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef CTRANS_H
+#define CTRANS_H
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int ctrans (unsigned char c);
+/* Translate a character from source charset into target charset */
+
+
+
+/* End of ctrans.h */
+
+#endif
+
+
+
diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c
new file mode 100644 (file)
index 0000000..21d2320
--- /dev/null
@@ -0,0 +1,568 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               datatype.c                                 */
+/*                                                                           */
+/*              Type string handling for the cc65 C compiler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "global.h"
+#include "mem.h"
+#include "util.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Predefined type strings */
+type type_int []       = { T_INT,      T_END };
+type type_uint []      = { T_UINT,     T_END };
+type type_long []      = { T_LONG,     T_END };
+type type_ulong []     = { T_ULONG,    T_END };
+type type_void []      = { T_VOID,     T_END };
+type type_pschar []    = { T_PTR, T_CHAR, T_END };
+type type_puchar []    = { T_PTR, T_UCHAR, T_END };
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned TypeLen (const type* T)
+/* Return the length of the type string */
+{
+    const type* Start = T;
+    while (*T) {
+       ++T;
+    }
+    return T - Start;
+}
+
+
+
+int TypeCmp (const type* T1, const type* T2)
+/* Compare two type strings */
+{
+    int A, B, D;
+    do {
+       A = *T1++;
+       B = *T2++;
+       D = A - B;
+    } while (D == 0 && A != 0);
+    return D;
+}
+
+
+
+type* TypeCpy (type* Dest, const type* Src)
+/* Copy a type string */
+{
+    type T;
+    type* Orig = Dest;
+    do {
+       T = *Src++;
+       *Dest++ = T;
+    } while (T);
+    return Orig;
+}
+
+
+
+type* TypeCat (type* Dest, const type* Src)
+/* Append Src */
+{
+    TypeCpy (Dest + TypeLen (Dest), Src);
+    return Dest;
+}
+
+
+
+type* TypeDup (const type* T)
+/* Create a copy of the given type on the heap */
+{
+    unsigned Len = (TypeLen (T) + 1) * sizeof (type);
+    return memcpy (xmalloc (Len), T, Len);
+}
+
+
+
+type* TypeAlloc (unsigned Len)
+/* Allocate memory for a type string of length Len. Len *must* include the
+ * trailing T_END.
+ */
+{
+    return xmalloc (Len * sizeof (type));
+}
+
+
+
+void TypeFree (type* T)
+/* Free a type string */
+{
+    xfree (T);
+}
+
+
+
+type GetDefaultChar (void)
+/* Return the default char type (signed/unsigned) depending on the settings */
+{
+    return SignedChars? T_CHAR : T_UCHAR;
+}
+
+
+
+type* GetCharArrayType (unsigned Len)
+/* Return the type for a char array of the given length */
+{
+    /* Allocate memory for the type string */
+    type* T = TypeAlloc (1 + DECODE_SIZE + 2);
+
+    /* Fill the type string */
+    T [0]            = T_ARRAY;
+    T [DECODE_SIZE+1] = GetDefaultChar();
+    T [DECODE_SIZE+2] = T_END;
+
+    /* Encode the length in the type string */
+    Encode (T+1, Len);
+
+    /* Return the new type */
+    return T;
+}
+
+
+
+type* GetImplicitFuncType (void)
+/* Return a type string for an inplicitly declared function */
+{
+    /* Get a new function descriptor */
+    FuncDesc* F = NewFuncDesc ();
+
+    /* Allocate memory for the type string */
+    type* T = TypeAlloc (1 + DECODE_SIZE + 2);
+
+    /* Prepare the function descriptor */
+    F->Flags    = FD_IMPLICIT | FD_ELLIPSIS;
+    F->SymTab   = &EmptySymTab;
+    F->StructTab = &EmptySymTab;
+    F->EnumTab   = &EmptySymTab;
+
+    /* Fill the type string */
+    T [0]            = T_FUNC;
+    T [DECODE_SIZE+1] = T_INT;
+    T [DECODE_SIZE+2] = T_END;
+
+    /* Encode the function descriptor into the type string */
+    EncodePtr (T+1, F);
+
+    /* Return the new type */
+    return T;
+}
+
+
+
+void PrintType (FILE* F, const type* tarray)
+/* Output translation of type array. */
+{
+    const type* p;
+
+    for (p = tarray; *p != T_END; ++p) {
+       if (*p & T_UNSIGNED) {
+           fprintf (F, "unsigned ");
+       }
+       switch (*p) {
+           case T_VOID:
+               fprintf (F, "void\n");
+               break;
+           case T_CHAR:
+           case T_UCHAR:
+               fprintf (F, "char\n");
+               break;
+           case T_INT:
+           case T_UINT:
+               fprintf (F, "int\n");
+               break;
+           case T_SHORT:
+           case T_USHORT:
+               fprintf (F, "short\n");
+               break;
+           case T_LONG:
+           case T_ULONG:
+               fprintf (F, "long\n");
+               break;
+           case T_FLOAT:
+               fprintf (F, "float\n");
+               break;
+           case T_DOUBLE:
+               fprintf (F, "double\n");
+               break;
+           case T_PTR:
+               fprintf (F, "pointer to ");
+               break;
+           case T_ARRAY:
+                       fprintf (F, "array[%lu] of ", Decode (p + 1));
+               p += DECODE_SIZE;
+               break;
+           case T_STRUCT:
+               fprintf (F, "struct %s\n", ((SymEntry*) Decode (p + 1))->Name);
+               p += DECODE_SIZE;
+               break;
+           case T_UNION:
+               fprintf (F, "union %s\n", ((SymEntry*) Decode (p + 1))->Name);
+               p += DECODE_SIZE;
+               break;
+           case T_FUNC:
+               fprintf (F, "function returning ");
+               p += DECODE_SIZE;
+               break;
+           default:
+               fprintf (F, "unknown type: %04X\n", *p);
+       }
+    }
+}
+
+
+
+void PrintRawType (FILE* F, const type* Type)
+/* Print a type string in raw format (for debugging) */
+{
+    while (*Type != T_END) {
+               fprintf (F, "%04X ", *Type++);
+    }
+    fprintf (F, "\n");
+}
+
+
+
+void Encode (type* Type, unsigned long Val)
+/* Encode p[0] and p[1] so that neither p[0] nore p[1] is zero */
+{
+    int I;
+    for (I = 0; I < DECODE_SIZE; ++I) {
+       *Type++ = ((type) Val) | 0x8000;
+       Val >>= 15;
+    }
+}
+
+
+
+void EncodePtr (type* Type, void* P)
+/* Encode a pointer into a type array */
+{
+    Encode (Type, (unsigned long) P);
+}
+
+
+
+unsigned long Decode (const type* Type)
+/* Decode */
+{
+    int I;
+    unsigned long Val = 0;
+    for (I = DECODE_SIZE-1; I >= 0; I--) {
+       Val <<= 15;
+       Val |= (Type[I] & 0x7FFF);
+    }
+    return Val;
+}
+
+
+
+void* DecodePtr (const type* Type)
+/* Decode a pointer from a type array */
+{
+    return (void*) Decode (Type);
+}
+
+
+
+int HasEncode (const type* Type)
+/* Return true if the given type has encoded data */
+{
+    return IsStruct (Type) || IsArray (Type) || IsFunc (Type);
+}
+
+
+
+void CopyEncode (const type* Source, type* Target)
+/* Copy encoded data from Source to Target */
+{
+    memcpy (Target, Source, DECODE_SIZE * sizeof (type));
+}
+
+
+
+unsigned SizeOf (const type* tarray)
+/* Compute size of object represented by type array. */
+{
+    SymEntry* Entry;
+
+    switch (*tarray) {
+
+       case T_VOID:
+           return 0;
+
+       case T_CHAR:
+       case T_UCHAR:
+           return 1;
+
+       case T_INT:
+       case T_UINT:
+               case T_SHORT:
+       case T_USHORT:
+       case T_PTR:
+        case T_ENUM:
+           return 2;
+
+        case T_LONG:
+       case T_ULONG:
+           return 4;
+
+       case T_ARRAY:
+           return (Decode (tarray + 1) * SizeOf (tarray + DECODE_SIZE + 1));
+
+       case T_STRUCT:
+       case T_UNION:
+                   Entry = DecodePtr (tarray+1);
+                   return Entry->V.S.Size;
+
+       default:
+           Internal ("Unknown type: %04X", *tarray);
+           return 0;
+
+    }
+}
+
+
+
+unsigned PSizeOf (const type* tptr)
+/* Compute size of pointer object. */
+{
+    /* We are expecting a pointer expression */
+    CHECK (*tptr & T_POINTER);
+
+    /* Skip the pointer or array token itself */
+    if (*tptr == T_ARRAY) {
+               return SizeOf (tptr + DECODE_SIZE + 1);
+    } else {
+       return SizeOf (tptr + 1);
+    }
+}
+
+
+
+unsigned TypeOf (const type* Type)
+/* Get the code generator base type of the object */
+{
+    FuncDesc* F;
+
+    switch (*Type) {
+
+       case T_CHAR:
+           return CF_CHAR;
+
+       case T_UCHAR:
+           return CF_CHAR | CF_UNSIGNED;
+
+       case T_SHORT:
+       case T_INT:
+        case T_ENUM:
+           return CF_INT;
+
+       case T_USHORT:
+       case T_UINT:
+       case T_PTR:
+       case T_ARRAY:
+           return CF_INT | CF_UNSIGNED;
+
+        case T_LONG:
+           return CF_LONG;
+
+               case T_ULONG:
+                   return CF_LONG | CF_UNSIGNED;
+
+        case T_FUNC:
+           F = DecodePtr (Type+1);
+           return (F->Flags & FD_ELLIPSIS)? 0 : CF_FIXARGC;
+
+        case T_STRUCT:
+        case T_UNION:
+                   /* Address of ... */
+                   return CF_INT | CF_UNSIGNED;
+
+               default:
+                   Error (ERR_ILLEGAL_TYPE);
+                   return CF_INT;
+    }
+}
+
+
+
+type* Indirect (type* Type)
+/* Do one indirection for the given type, that is, return the type where the
+ * given type points to.
+ */
+{
+    /* We are expecting a pointer expression */
+    CHECK (Type[0] & T_POINTER);
+
+    /* Skip the pointer or array token itself */
+    if (Type[0] == T_ARRAY) {
+               return Type + DECODE_SIZE + 1;
+    } else {
+       return Type + 1;
+    }
+}
+
+
+
+int IsVoid (const type* Type)
+/* Return true if this is a void type */
+{
+    return (Type[0] == T_VOID && Type[1] == T_END);
+}
+
+
+
+int IsPtr (const type* Type)
+/* Return true if this is a pointer type */
+{
+    return (Type[0] & T_POINTER) != 0;
+}
+
+
+
+int IsChar (const type* Type)
+/* Return true if this is a character type */
+{
+    return (Type[0] == T_CHAR || Type[0] == T_UCHAR) && Type[1] == T_END;
+}
+
+
+
+int IsInt (const type* Type)
+/* Return true if this is an integer type */
+{
+    return (Type[0] & T_INTEGER) != 0;
+}
+
+
+
+int IsLong (const type* Type)
+/* Return true if this is a long type (signed or unsigned) */
+{
+    return (Type[0] & T_LONG) == T_LONG;
+}
+
+
+
+int IsUnsigned (const type* Type)
+/* Return true if this is an unsigned type */
+{
+    return (Type[0] & T_UNSIGNED) != 0;
+}
+
+
+
+int IsStruct (const type* Type)
+/* Return true if this is a struct type */
+{
+    return (Type[0] == T_STRUCT || Type[0] == T_UNION);
+}
+
+
+
+int IsFunc (const type* Type)
+/* Return true if this is a function type */
+{
+    return (Type[0] == T_FUNC);
+}
+
+
+
+int IsFastCallFunc (const type* Type)
+/* Return true if this is a function type with __fastcall__ calling conventions */
+{
+    FuncDesc* F;
+    CHECK (*Type == T_FUNC);
+    F = DecodePtr (Type+1);
+    return (F->Flags & FD_FASTCALL) != 0;
+}
+
+
+
+int IsFuncPtr (const type* Type)
+/* Return true if this is a function pointer */
+{
+    return (Type[0] == T_PTR && Type[1] == T_FUNC);
+}
+
+
+
+int IsArray (const type* Type)
+/* Return true if this is an array type */
+{
+    return (Type[0] == T_ARRAY);
+}
+
+
+
+struct FuncDesc* GetFuncDesc (const type* Type)
+/* Get the FuncDesc pointer from a function or pointer-to-function type */
+{
+    if (Type[0] == T_PTR) {
+       /* Pointer to function */
+       ++Type;
+    }
+
+    /* Be sure it's a function type */
+    CHECK (Type[0] == T_FUNC);
+
+    /* Decode the function descriptor and return it */
+    return DecodePtr (Type+1);
+}
+
+
+
diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h
new file mode 100644 (file)
index 0000000..60e618f
--- /dev/null
@@ -0,0 +1,223 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               datatype.h                                 */
+/*                                                                           */
+/*              Type string handling for the cc65 C compiler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef DATATYPE_H
+#define DATATYPE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Data types */
+#define        T_END           0x0000
+#define T_CHAR                 0x0011
+#define T_INT                  0x0012
+#define        T_SHORT         0x0013
+#define T_LONG                 0x0014
+#define T_ENUM                 0x0015
+#define T_UCHAR                0x0019
+#define T_UINT                 0x001A
+#define T_USHORT               0x001B
+#define T_ULONG                0x001C
+
+#define T_FLOAT                0x0025
+#define T_DOUBLE               0x0026
+
+#define T_VOID                 0x0001          /* void parameter list */
+#define T_FUNC                 0x0002          /* Function */
+
+#define T_UNSIGNED             0x0008          /* Class */
+#define T_INTEGER              0x0010          /* Class */
+#define T_REAL                 0x0020          /* Class */
+#define T_POINTER              0x0040          /* Class */
+#define T_PTR                  0x0049
+#define T_ARRAY                0x004A
+#define T_STRUCT               0x0080
+#define T_UNION                0x0081
+#define T_SMASK                0x003F
+
+
+
+/* Forward for a symbol entry */
+struct SymEntry;
+
+/* Type entry */
+typedef unsigned short type;
+
+/* Maximum length of a type string */
+#define MAXTYPELEN     30
+
+/* type elements needed for Encode/Decode */
+#define DECODE_SIZE            5
+
+/* Predefined type strings */
+extern type type_int [];
+extern type type_uint [];
+extern type type_long [];
+extern type type_ulong [];
+extern type type_void [];
+extern type type_pschar [];
+extern type type_puchar [];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned TypeLen (const type* Type);
+/* Return the length of the type string */
+
+int TypeCmp (const type* T1, const type* T2);
+/* Compare two type strings */
+
+type* TypeCpy (type* Dest, const type* Src);
+/* Copy a type string */
+
+type* TypeCat (type* Dest, const type* Src);
+/* Append Src */
+
+type* TypeDup (const type* Type);
+/* Create a copy of the given type on the heap */
+
+type* TypeAlloc (unsigned Len);
+/* Allocate memory for a type string of length Len. Len *must* include the
+ * trailing T_END.
+ */
+
+void TypeFree (type* Type);
+/* Free a type string */
+
+type GetDefaultChar (void);
+/* Return the default char type (signed/unsigned) depending on the settings */
+
+type* GetCharArrayType (unsigned Len);
+/* Return the type for a char array of the given length */
+
+type* GetImplicitFuncType (void);
+/* Return a type string for an inplicitly declared function */
+
+void PrintType (FILE* F, const type* Type);
+/* Output translation of type array. */
+
+void PrintRawType (FILE* F, const type* Type);
+/* Print a type string in raw format (for debugging) */
+
+void Encode (type* Type, unsigned long Val);
+/* Encode an unsigned long into a type array */
+
+void EncodePtr (type* Type, void* P);
+/* Encode a pointer into a type array */
+
+unsigned long Decode (const type* Type);
+/* Decode an unsigned long from a type array */
+
+void* DecodePtr (const type* Type);
+/* Decode a pointer from a type array */
+
+int HasEncode (const type* Type);
+/* Return true if the given type has encoded data */
+    
+void CopyEncode (const type* Source, type* Target);
+/* Copy encoded data from Source to Target */
+
+unsigned SizeOf (const type* Type);
+/* Compute size of object represented by type array. */
+
+unsigned PSizeOf (const type* Type);
+/* Compute size of pointer object. */
+
+unsigned TypeOf (const type* Type);
+/* Get the code generator base type of the object */
+
+type* Indirect (type* Type);
+/* Do one indirection for the given type, that is, return the type where the
+ * given type points to.
+ */
+
+int IsVoid (const type* Type);
+/* Return true if this is a void type */
+
+int IsPtr (const type* Type);
+/* Return true if this is a pointer type */
+
+int IsChar (const type* Type);
+/* Return true if this is a character type */
+
+int IsInt (const type* Type);
+/* Return true if this is an integer type */
+
+int IsLong (const type* Type);
+/* Return true if this is a long type (signed or unsigned) */
+
+int IsUnsigned (const type* Type);
+/* Return true if this is an unsigned type */
+
+int IsStruct (const type* Type);
+/* Return true if this is a struct type */
+
+int IsFunc (const type* Type);
+/* Return true if this is a function type */
+
+int IsFastCallFunc (const type* Type);
+/* Return true if this is a function type with __fastcall__ calling conventions */
+
+int IsFuncPtr (const type* Type);
+/* Return true if this is a function pointer */
+
+int IsArray (const type* Type);
+/* Return true if this is an array type */
+
+struct FuncDesc* GetFuncDesc (const type* Type);
+/* Get the FuncDesc pointer from a function or pointer-to-function type */
+
+
+
+/* End of datatype.h */
+
+#endif
+
+
+
diff --git a/src/cc65/declare.c b/src/cc65/declare.c
new file mode 100644 (file)
index 0000000..8c40fa8
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * declare.c
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "anonname.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "expr.h"
+#include "funcdesc.h"
+#include "function.h"
+#include "global.h"
+#include "litpool.h"
+#include "mem.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "declare.h"
+
+
+
+/*****************************************************************************/
+/*                                Forwards                                  */
+/*****************************************************************************/
+
+
+
+static void ParseTypeSpec (DeclSpec* D, int Default);
+/* Parse a type specificier */
+
+
+
+/*****************************************************************************/
+/*                           internal functions                             */
+/*****************************************************************************/
+
+
+
+static void optional_modifiers (void)
+/* Eat optional "const" or "volatile" tokens */
+{
+    while (curtok == CONST || curtok == VOLATILE) {
+       /* Skip it */
+       gettok ();
+    }
+}
+
+
+
+static void optionalint (void)
+/* Eat an optional "int" token */
+{
+    if (curtok == INT) {
+       /* Skip it */
+       gettok ();
+    }
+}
+
+
+
+static void optionalsigned (void)
+/* Eat an optional "signed" token */
+{
+    if (curtok == SIGNED) {
+       /* Skip it */
+       gettok ();
+    }
+}
+
+
+
+static void InitDeclSpec (DeclSpec* D)
+/* Initialize the DeclSpec struct for use */
+{
+    D->StorageClass    = 0;
+    D->Type[0]         = T_END;
+    D->Flags           = 0;
+}
+
+
+
+static void InitDeclaration (Declaration* D)
+/* Initialize the Declaration struct for use */
+{
+    D->Ident[0]                = '\0';
+    D->Type[0]         = T_END;
+    D->T               = D->Type;
+}
+
+
+
+static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
+/* Parse a storage class */
+{
+    /* Assume we're using an explicit storage class */
+    D->Flags &= ~DS_DEF_STORAGE;
+
+    /* Check the storage class given */
+    switch (curtok) {
+
+       case EXTERN:
+           D->StorageClass = SC_EXTERN | SC_STATIC;
+           gettok ();
+           break;
+
+       case STATIC:
+           D->StorageClass = SC_STATIC;
+           gettok ();
+           break;
+
+       case REGISTER:
+           D->StorageClass = SC_REGISTER | SC_STATIC;
+           gettok ();
+           break;
+
+       case AUTO:
+           D->StorageClass = SC_AUTO;
+           gettok ();
+           break;
+
+       case TYPEDEF:
+           D->StorageClass = SC_TYPEDEF;
+           gettok ();
+           break;
+
+       default:
+           /* No storage class given, use default */
+                   D->Flags |= DS_DEF_STORAGE;
+           D->StorageClass = DefStorage;
+           break;
+    }
+}
+
+
+
+static void ParseEnumDecl (void)
+/* Process an enum declaration . */
+{
+    int EnumVal;
+    ident Ident;
+
+    /* Accept forward definitions */
+    if (curtok != LCURLY) {
+       return;
+    }
+
+    /* Skip the opening curly brace */
+    gettok ();
+
+    /* Read the enum tags */
+    EnumVal = 0;
+    while (curtok != RCURLY) {
+
+       /* We expect an identifier */
+       if (curtok != IDENT) {
+           Error (ERR_IDENT_EXPECTED);
+           continue;
+       }
+
+       /* Remember the identifier and skip it */
+       strcpy (Ident, CurTok.Ident);
+       gettok ();
+
+       /* Check for an assigned value */
+       if (curtok == ASGN) {
+           struct expent lval;
+           gettok ();
+           constexpr (&lval);
+           EnumVal = lval.e_const;
+       }
+
+       /* Add an entry to the symbol table */
+       AddEnumSym (Ident, EnumVal++);
+
+       /* Check for end of definition */
+       if (curtok != COMMA)
+           break;
+       gettok ();
+    }
+    ConsumeRCurly ();
+}
+
+
+
+static SymEntry* ParseStructDecl (const char* Name, type StructType)
+/* Parse a struct/union declaration. */
+{
+
+    unsigned Size;
+    unsigned Offs;
+    SymTable* FieldTab;
+    SymEntry* Entry;
+
+
+    if (curtok != LCURLY) {
+       /* Just a forward declaration. Try to find a struct with the given
+        * name. If there is none, insert a forward declaration into the
+        * current lexical level.
+        */
+       Entry = FindStructSym (Name);
+       if (Entry == 0 || Entry->Flags != SC_STRUCT) {
+           Entry = AddStructSym (Name, 0, 0);
+       }
+       return Entry;     
+    }
+
+    /* Add a forward declaration for the struct in the current lexical level */
+    Entry = AddStructSym (Name, 0, 0);
+
+    /* Skip the curly brace */
+    gettok ();
+
+    /* Enter a new lexical level for the struct */
+    EnterStructLevel ();
+
+    /* Parse struct fields */
+    Size = 0;
+    while (curtok != RCURLY) {
+
+       /* Get the type of the entry */
+       DeclSpec Spec;
+       InitDeclSpec (&Spec);
+       ParseTypeSpec (&Spec, -1);
+
+       /* Read fields with this type */
+       while (1) {
+
+           /* Get type and name of the struct field */
+           Declaration Decl;
+           ParseDecl (&Spec, &Decl, 0);
+
+           /* Add a field entry to the table */
+           AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
+
+           /* Calculate offset of next field/size of the union */
+           Offs = SizeOf (Decl.Type);
+           if (StructType == T_STRUCT) {
+               Size += Offs;
+           } else {
+               if (Offs > Size) {
+                   Size = Offs;
+               }
+           }
+
+           if (curtok != COMMA)
+               break;
+           gettok ();
+       }
+       ConsumeSemi ();
+    }
+
+    /* Skip the closing brace */
+    gettok ();
+
+    /* Remember the symbol table and leave the struct level */
+    FieldTab = GetSymTab ();
+    LeaveStructLevel ();
+
+    /* Make a real entry from the forward decl and return it */
+    return AddStructSym (Name, Size, FieldTab);
+}
+
+
+
+static void ParseTypeSpec (DeclSpec* D, int Default)
+/* Parse a type specificier */
+{
+    ident Ident;
+    SymEntry* Entry;
+    type StructType;
+
+    /* Assume have an explicit type */
+    D->Flags &= ~DS_DEF_TYPE;
+
+    /* Skip const or volatile modifiers if needed */
+    optional_modifiers ();
+
+    /* Look at the data type */
+    switch (curtok) {
+
+       case VOID:
+           gettok ();
+           D->Type[0] = T_VOID;
+           D->Type[1] = T_END;
+           break;
+
+       case CHAR:
+           gettok ();
+           D->Type[0] = GetDefaultChar();
+           D->Type[1] = T_END;
+           break;
+
+       case LONG:
+           gettok ();
+           if (curtok == UNSIGNED) {
+               gettok ();
+               optionalint ();
+               D->Type[0] = T_ULONG;
+               D->Type[1] = T_END;
+           } else {
+               optionalsigned ();
+               optionalint ();
+               D->Type[0] = T_LONG;
+               D->Type[1] = T_END;
+           }
+           break;
+
+       case SHORT:
+           gettok ();
+           if (curtok == UNSIGNED) {
+               gettok ();
+               optionalint ();
+               D->Type[0] = T_USHORT;
+               D->Type[1] = T_END;
+           } else {
+               optionalsigned ();
+               optionalint ();
+               D->Type[0] = T_SHORT;
+               D->Type[1] = T_END;
+           }
+           break;
+
+       case INT:
+           gettok ();
+           D->Type[0] = T_INT;
+           D->Type[1] = T_END;
+           break;
+
+       case SIGNED:
+           gettok ();
+           switch (curtok) {
+
+                       case CHAR:
+                   gettok ();
+                   D->Type[0] = T_CHAR;
+                   D->Type[1] = T_END;
+                   break;
+
+               case SHORT:
+                   gettok ();
+                   optionalint ();
+                   D->Type[0] = T_SHORT;
+                   D->Type[1] = T_END;
+                   break;
+
+               case LONG:
+                   gettok ();
+                   optionalint ();
+                   D->Type[0] = T_LONG;
+                   D->Type[1] = T_END;
+                   break;
+
+               case INT:
+                   gettok ();
+                   /* FALL THROUGH */
+
+               default:
+                   D->Type[0] = T_INT;
+                   D->Type[1] = T_END;
+                   break;
+           }
+           break;
+
+       case UNSIGNED:
+           gettok ();
+           switch (curtok) {
+
+                       case CHAR:
+                   gettok ();
+                   D->Type[0] = T_UCHAR;
+                   D->Type[1] = T_END;
+                   break;
+
+               case SHORT:
+                   gettok ();
+                   optionalint ();
+                   D->Type[0] = T_USHORT;
+                   D->Type[1] = T_END;
+                   break;
+
+               case LONG:
+                   gettok ();
+                   optionalint ();
+                   D->Type[0] = T_ULONG;
+                   D->Type[1] = T_END;
+                   break;
+
+               case INT:
+                   gettok ();
+                   /* FALL THROUGH */
+
+               default:
+                   D->Type[0] = T_UINT;
+                   D->Type[1] = T_END;
+                   break;
+           }
+           break;
+
+       case STRUCT:
+       case UNION:
+           StructType = (curtok == STRUCT)? T_STRUCT : T_UNION;
+           gettok ();
+           if (curtok == IDENT) {
+               strcpy (Ident, CurTok.Ident);
+               gettok ();
+           } else {
+               AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
+           }
+           /* Declare the struct in the current scope */
+           Entry = ParseStructDecl (Ident, StructType);
+                   /* Encode the struct entry into the type */
+           D->Type[0] = StructType;
+           EncodePtr (D->Type+1, Entry);
+           D->Type[DECODE_SIZE+1] = T_END;
+           break;
+
+       case ENUM:
+           gettok ();
+           if (curtok != LCURLY) {
+               /* Named enum */
+               Consume (IDENT, ERR_IDENT_EXPECTED);
+           }
+           ParseEnumDecl ();
+           D->Type[0] = T_INT;
+           D->Type[1] = T_END;
+           break;
+
+        case IDENT:
+           Entry = FindSym (CurTok.Ident);
+           if (Entry && IsTypeDef (Entry)) {
+                       /* It's a typedef */
+               gettok ();
+               TypeCpy (D->Type, Entry->Type);
+               break;
+           }
+           /* FALL THROUGH */
+
+       default:
+           if (Default < 0) {
+               Error (ERR_TYPE_EXPECTED);
+               D->Type[0] = T_INT;
+               D->Type[1] = T_END;
+           } else {
+               D->Flags  |= DS_DEF_TYPE;
+               D->Type[0] = (type) Default;
+               D->Type[1] = T_END;
+           }
+           break;
+    }
+}
+
+
+
+static FuncDesc* ParseFuncDecl (void)
+/* Parse the argument list of a function. */
+{
+    unsigned UnnamedCount = 0;
+    unsigned Offs;
+    SymEntry* Sym;
+    type* Type;
+
+    /* Create a new function descriptor */
+    FuncDesc* F = NewFuncDesc ();
+
+    /* Enter a new lexical level */
+    EnterFunctionLevel ();
+
+    /* Check for an empty or void parameter list */
+    if (curtok == RPAREN) {
+       /* Parameter list is empty */
+       F->Flags |= (FD_EMPTY | FD_ELLIPSIS);
+    } else if (curtok == VOID && nxttok == RPAREN) {
+       /* Parameter list declared as void */
+       gettok ();
+       F->Flags |= FD_VOID_PARAM;
+    }
+
+    /* Parse params */
+    while (curtok != RPAREN) {
+
+       DeclSpec Spec;
+       Declaration Decl;
+
+       /* Allow an ellipsis as last parameter */
+       if (curtok == ELLIPSIS) {
+           gettok ();
+           F->Flags |= FD_ELLIPSIS;
+           break;
+       }
+
+       /* Read the declaration specifier */
+       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+
+               /* We accept only auto and register as storage class specifiers, but
+        * we ignore all this and use auto.
+        */
+       if ((Spec.StorageClass & SC_AUTO) == 0 &&
+           (Spec.StorageClass & SC_REGISTER) == 0) {
+           Error (ERR_ILLEGAL_STORAGE_CLASS);
+       }
+       Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
+
+       /* Allow parameters without a name, but remember if we had some to
+        * eventually print an error message later.
+        */
+       ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
+               if (Decl.Ident[0] == '\0') {
+
+           /* Unnamed symbol. Generate a name that is not user accessible,
+            * then handle the symbol normal.
+            */
+           AnonName (Decl.Ident, "param");
+           ++UnnamedCount;
+
+           /* Clear defined bit on nonames */
+           Spec.StorageClass &= ~SC_DEF;
+       }
+
+       /* If the parameter is an array, convert it to a pointer */
+       Type = Decl.Type;
+       if (IsArray (Type)) {
+           Type += DECODE_SIZE;
+           Type[0] = T_PTR;
+       }
+
+       /* Create a symbol table entry */
+       AddLocalSym (Decl.Ident, Type, Spec.StorageClass, 0);
+
+       /* Count arguments */
+               ++F->ParamCount;
+       F->ParamSize += SizeOf (Type);
+
+       /* Check for more parameters */
+       if (curtok == COMMA) {
+           gettok ();
+       } else {
+           break;
+       }
+    }
+
+    /* Skip right paren. We must explicitly check for one here, since some of
+     * the breaks above bail out without checking.
+     */
+    ConsumeRParen ();
+
+    /* Assign offsets. If the function has a variable parameter list,
+     * there's one additional byte (the arg size).
+     */
+    Offs = (F->Flags & FD_ELLIPSIS)? 1 : 0;
+    Sym = GetSymTab()->SymTail;
+    while (Sym) {
+       Sym->V.Offs = Offs;
+               Offs += SizeOf (Sym->Type);
+       Sym = Sym->PrevSym;
+    }
+
+    /* Check if this is a function definition */
+    if (curtok == LCURLY) {
+       /* Print an error if in strict ANSI mode and we have unnamed
+        * parameters.
+        */
+       if (ANSI && UnnamedCount > 0) {
+           Error (ERR_MISSING_PARAM_NAME);
+       }
+    }
+
+    /* Leave the lexical level remembering the symbol tables */
+    RememberFunctionLevel (F);
+
+    /* Return the function descriptor */
+    return F;
+}
+
+
+
+static void Decl (Declaration* D, unsigned Mode)
+/* Recursively process declarators. Build a type array in reverse order. */
+{
+    if (curtok == STAR) {
+               gettok ();
+       /* Allow optional const or volatile modifiers */
+       optional_modifiers ();
+               Decl (D, Mode);
+               *D->T++ = T_PTR;
+               return;
+    } else if (curtok == LPAREN) {
+               gettok ();
+               Decl (D, Mode);
+               ConsumeRParen ();
+    } else if (curtok == FASTCALL) {
+       /* Remember the current type pointer */
+       type* T = D->T;
+       /* Skip the fastcall token */
+       gettok ();
+       /* Parse the function */
+       Decl (D, Mode);
+       /* Set the fastcall flag */
+       if (!IsFunc (T)) {
+           Error (ERR_ILLEGAL_MODIFIER);
+       } else {
+           FuncDesc* F = DecodePtr (T+1);
+                   F->Flags |= FD_FASTCALL;
+       }
+       return;
+    } else {
+       /* Things depend on Mode now:
+                *  - Mode == DM_NEED_IDENT means:
+        *      we *must* have a type and a variable identifer.
+        *  - Mode == DM_NO_IDENT means:
+        *      we must have a type but no variable identifer
+        *      (if there is one, it's not read).
+        *  - Mode == DM_ACCEPT_IDENT means:
+        *      we *may* have an identifier. If there is an identifier,
+        *      it is read, but it is no error, if there is none.
+        */
+       if (Mode == DM_NO_IDENT) {
+           D->Ident[0] = '\0';
+       } else if (curtok == IDENT) {
+                   strcpy (D->Ident, CurTok.Ident);
+           gettok ();
+       } else {
+           if (Mode == DM_NEED_IDENT) {
+               Error (ERR_IDENT_EXPECTED);
+           }
+           D->Ident[0] = '\0';
+           return;
+       }
+    }
+
+    while (curtok == LBRACK || curtok == LPAREN) {
+               if (curtok == LPAREN) {
+                   /* Function declaration */
+           FuncDesc* F;
+                   gettok ();
+           /* Parse the function declaration */
+                   F = ParseFuncDecl ();
+           *D->T++ = T_FUNC;
+           EncodePtr (D->T, F);
+           D->T += DECODE_SIZE;
+               } else {
+           /* Array declaration */
+                   unsigned long Size = 0;
+                   gettok ();
+           /* Read the size if it is given */
+                   if (curtok != RBRACK) {
+               struct expent lval;
+                       constexpr (&lval);
+                       Size = lval.e_const;
+                   }
+                   ConsumeRBrack ();
+                   *D->T++ = T_ARRAY;
+                   Encode (D->T, Size);
+                   D->T += DECODE_SIZE;
+               }
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+type* ParseType (type* Type)
+/* Parse a complete type specification */
+{
+    DeclSpec Spec;
+    Declaration Decl;
+
+    /* Get a type without a default */
+    InitDeclSpec (&Spec);
+    ParseTypeSpec (&Spec, -1);
+
+    /* Parse additional declarators */
+    InitDeclaration (&Decl);
+    ParseDecl (&Spec, &Decl, DM_NO_IDENT);
+
+    /* Copy the type to the target buffer */
+    TypeCpy (Type, Decl.Type);
+
+    /* Return a pointer to the target buffer */
+    return Type;
+}
+
+
+
+void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
+/* Parse a variable, type or function declaration */
+{
+    /* Initialize the Declaration struct */
+    InitDeclaration (D);
+
+    /* Get additional declarators and the identifier */
+    Decl (D, Mode);
+
+    /* Add the base type. */
+    TypeCpy (D->T, Spec->Type);
+
+    /* Check the size of the generated type */
+    if (!IsFunc (D->Type) && SizeOf (D->Type) >= 0x10000) {
+       Error (ERR_ILLEGAL_SIZE);
+    }
+}
+
+
+
+void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
+/* Parse a declaration specification */
+{
+    /* Initialize the DeclSpec struct */
+    InitDeclSpec (D);
+
+    /* First, get the storage class specifier for this declaration */
+    ParseStorageClass (D, DefStorage);
+
+    /* Parse the type specifiers */
+    ParseTypeSpec (D, DefType);
+}
+
+
+
+static void ParseVoidInit (void)
+/* Parse an initialization of a void variable (special cc65 extension) */
+{
+    struct expent lval;
+
+    /* Allow an arbitrary list of values */
+    ConsumeLCurly ();
+    do {
+       constexpr (&lval);
+       switch (lval.e_tptr[0]) {
+
+           case T_CHAR:
+           case T_UCHAR:
+               if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+                   /* Make it byte sized */
+                   lval.e_const &= 0xFF;
+               }
+               DefineData (&lval);
+               break;
+
+           case T_SHORT:
+           case T_USHORT:
+           case T_INT:
+           case T_UINT:
+           case T_PTR:
+           case T_ARRAY:
+               if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+                   /* Make it word sized */
+                   lval.e_const &= 0xFFFF;
+               }
+               DefineData (&lval);
+               break;
+
+           case T_LONG:
+           case T_ULONG:
+               DefineData (&lval);
+               break;
+
+           default:
+               Error (ERR_ILLEGAL_TYPE);
+               break;
+
+       }
+
+       if (curtok != COMMA) {
+           break;
+       }
+       gettok ();
+
+    } while (curtok != RCURLY);
+
+    ConsumeRCurly ();
+}
+
+
+
+static void ParseStructInit (type* Type)
+/* Parse initialization of a struct or union */
+{
+    SymEntry* Entry;
+    SymTable* Tab;
+
+    /* Consume the opening curly brace */
+    ConsumeLCurly ();
+
+    /* Get a pointer to the struct entry from the type */
+    Entry = (SymEntry*) Decode (Type + 1);
+
+    /* Check if this struct definition has a field table. If it doesn't, it
+     * is an incomplete definition.
+     */
+    Tab = Entry->V.S.SymTab;
+    if (Tab == 0) {
+       Error (ERR_INIT_INCOMPLETE_TYPE);
+       /* Returning here will cause lots of errors, but recovery is difficult */
+       return;
+    }
+
+    /* Get a pointer to the list of symbols */
+    Entry = Tab->SymHead;
+    while (curtok != RCURLY) {
+       if (Entry == NULL) {
+           Error (ERR_TOO_MANY_INITIALIZERS);
+           return;
+       }
+       ParseInit (Entry->Type);
+       Entry = Entry->NextSym;
+       if (curtok != COMMA)
+           break;
+       gettok ();
+    }
+
+    /* Consume the closing curly brace */
+    ConsumeRCurly ();
+
+    /* If there are struct fields left, reserve additional storage */
+    while (Entry) {
+       g_zerobytes (SizeOf (Entry->Type));
+       Entry = Entry->NextSym;
+    }
+}
+
+
+
+
+
+void ParseInit (type *tptr)
+/* Parse initialization of variables */
+{
+    int count;
+    struct expent lval;
+    type* t;
+    const char* str;
+    int sz;
+
+    switch (*tptr) {
+
+       case T_CHAR:
+       case T_UCHAR:
+           constexpr (&lval);
+           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+               /* Make it byte sized */
+               lval.e_const &= 0xFF;
+           }
+           assignadjust (tptr, &lval);
+           DefineData (&lval);
+           break;
+
+       case T_SHORT:
+       case T_USHORT:
+       case T_INT:
+       case T_UINT:
+       case T_PTR:
+           constexpr (&lval);
+           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+               /* Make it word sized */
+               lval.e_const &= 0xFFFF;
+           }
+           assignadjust (tptr, &lval);
+           DefineData (&lval);
+           break;
+
+       case T_LONG:
+       case T_ULONG:
+           constexpr (&lval);
+           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+               /* Make it long sized */
+               lval.e_const &= 0xFFFFFFFF;
+           }
+           assignadjust (tptr, &lval);
+           DefineData (&lval);
+           break;
+
+       case T_ARRAY:
+           sz = Decode (tptr + 1);
+           t = tptr + DECODE_SIZE + 1;
+                   if ((t [0] == T_CHAR || t [0] == T_UCHAR) && curtok == SCONST) {
+               str = GetLiteral (curval);
+               count = strlen (str) + 1;
+               TranslateLiteralPool (curval);  /* Translate into target charset */
+               g_defbytes (str, count);
+               ResetLiteralOffs (curval);      /* Remove string from pool */
+               gettok ();
+           } else {
+               ConsumeLCurly ();
+               count = 0;
+               while (curtok != RCURLY) {
+                   ParseInit (tptr + DECODE_SIZE + 1);
+                   ++count;
+                   if (curtok != COMMA)
+                       break;
+                   gettok ();
+               }
+               ConsumeRCurly ();
+           }
+           if (sz == 0) {
+               Encode (tptr + 1, count);
+           } else if (count < sz) {
+               g_zerobytes ((sz - count) * SizeOf (tptr + DECODE_SIZE + 1));
+           } else if (count > sz) {
+               Error (ERR_TOO_MANY_INITIALIZERS);
+           }
+           break;
+
+        case T_STRUCT:
+        case T_UNION:
+           ParseStructInit (tptr);
+           break;
+
+       case T_VOID:
+           if (!ANSI) {
+               /* Special cc65 extension in non ANSI mode */
+               ParseVoidInit ();
+               break;
+           }
+           /* FALLTHROUGH */
+
+       default:
+           Error (ERR_ILLEGAL_TYPE);
+           break;
+
+    }
+}
+
+
+
diff --git a/src/cc65/declare.h b/src/cc65/declare.h
new file mode 100644 (file)
index 0000000..57bf415
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * declare.h
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#ifndef DECLARE_H
+#define DECLARE_H
+
+
+
+#include "scanner.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Masks for the Flags field in DeclSpec */
+#define DS_DEF_STORAGE         0x0001U /* Default storage class used */
+#define DS_DEF_TYPE            0x0002U /* Default type used */
+
+/* Result of ParseDeclSpec */
+typedef struct DeclSpec DeclSpec;
+struct DeclSpec {
+    unsigned   StorageClass;           /* One of the SC_xxx flags */
+    type       Type [MAXTYPELEN];      /* Type of the declaration spec */
+    unsigned   Flags;                  /* Bitmapped flags */
+};
+
+/* Result of ParseDecl */
+typedef struct Declaration Declaration;
+struct Declaration {
+    ident      Ident;                  /* The identifier if any, else empty */
+    type       Type [MAXTYPELEN];      /* The type */
+
+    /* Working variables */
+    type*      T;                      /* Used to build Type */
+};
+
+/* Modes for ParseDecl */
+#define DM_NEED_IDENT  0U              /* We must have an identifier */
+#define DM_NO_IDENT    1U              /* We won't read an identifier */
+#define DM_ACCEPT_IDENT        2U              /* We will accept an id if there is one */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+type* ParseType (type* Type);
+/* Parse a complete type specification */
+
+void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode);
+/* Parse a variable, type or function declaration */
+
+void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType);
+/* Parse a declaration specification */
+
+void ParseInit (type* tptr);
+/* Parse initialization of variables */
+
+
+
+/* End of declare.h */
+
+#endif
+
+
+
diff --git a/src/cc65/error.c b/src/cc65/error.c
new file mode 100644 (file)
index 0000000..4d32502
--- /dev/null
@@ -0,0 +1,310 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 error.c                                  */
+/*                                                                           */
+/*                 Error handling for the cc65 C compiler                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "global.h"
+#include "io.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+static char* WarnMsg [WARN_COUNT-1] = {
+    "Unreachable code",
+    "Condition is never true",
+    "Condition is always true",
+    "Converting pointer to integer without a cast",
+    "Converting integer to pointer without a cast",
+    "Function call without a prototype",
+    "Unknown #pragma",
+    "No case labels",
+    "Function must be extern",
+    "Parameter `%s' is never used",
+    "`%s' is defined but never used",
+    "Constant is long",
+    "`/*' found inside a comment",
+};
+
+
+
+/* Error messages sorted by ErrTypes */
+static char* ErrMsg [ERR_COUNT-1] = {
+    "Invalid character (%u)",
+    "Unexpected newline",
+    "End-of-file reached in comment starting at line %u",
+    "Syntax error",
+    "`\"' expected",
+    "`:' expected",
+    "`;' expected",
+    "`(' expected",
+    "`)' expected",
+    "`[' expected",
+    "`]' expected",
+    "`{' expected",
+    "`}' expected",
+    "Identifier expected",
+    "Type expected",
+    "Incompatible types",
+    "Incompatible pointer types",
+    "Too many arguments in function call",
+    "Too few arguments in function call",
+    "Macro argument count mismatch",
+    "Duplicate macro parameter: %s",
+    "Variable identifier expected",
+    "Integer expression expected",
+    "Constant expression expected",
+    "No active loop",
+    "`\"' or `<' expected",
+    "Missing terminator or name too long",
+    "Include file `%s' not found",
+    "Open failure on include file `%s'",
+    "Invalid #error directive",
+    "#error: %s",
+    "Unexpected `#endif'",
+    "Unexpected `#else'",
+    "`#endif' expected",
+    "Compiler directive expected",
+    "Symbol `%s' defined more than once",
+    "String literal expected",
+    "`while' expected",
+    "Function must return a value",
+    "Function cannot return a value",
+    "Unexpected `continue'",
+    "Undefined symbol: `%s'",
+    "Undefined label: `%s'",
+    "Include nesting too deep",
+    "Too many local variables",
+    "Too many initializers",
+    "Cannot initialize incomplete type",
+    "Cannot subscript",
+    "Operation not allowed on these types",
+    "Struct expected",
+    "Struct/union has no field named `%s'",
+    "Struct pointer expected",
+    "lvalue expected",
+    "Expression expected",
+    "Preprocessor expression expected",
+    "Illegal type",
+    "Illegal function call",
+    "Illegal indirection",
+    "Illegal address",
+    "Illegal macro call",
+    "Illegal hex digit",
+    "Illegal character constant",
+    "Illegal modifier",
+    "Illegal storage class",
+    "Division by zero",
+    "Modulo operation with zero",
+    "Range error",
+    "Symbol is already different kind",
+    "Too many lexical levels",
+    "Parameter name omitted",
+    "Old style function decl used as prototype",
+    "Declaration for parameter `%s' but no such parameter",
+    "Cannot take address of a register variable",
+    "Illegal size of data type",
+    "__fastcall__ is not allowed for C functions",
+    "Variable has unknown size",
+};
+
+
+
+static char* FatMsg [FAT_COUNT-1] = {
+    "Too many errors",
+    "Cannot open output file: %s",
+    "Cannot write to output file (disk full?)",
+    "Cannot open input file: %s",
+    "Out of memory",
+    "Stack overflow",
+    "Stack empty",
+    "Out of string space",
+    "Too many case labels",
+};
+
+
+
+/* Count of errors/warnings */
+unsigned ErrorCount    = 0;
+unsigned WarningCount  = 0;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...)
+/* Print warning message. */
+{
+    va_list ap;
+
+    if (!NoWarn) {
+       fprintf (stderr, "%s(%u): Warning #%u: ", fin, curpos, WarnNum);
+
+       va_start (ap, WarnNum);
+       vfprintf (stderr, WarnMsg [WarnNum-1], ap);
+       va_end (ap);
+       fprintf (stderr, "\n");
+
+       if (Verbose) {
+           fprintf (stderr, "Line: %s\n", line);
+       }
+    }
+    ++ WarningCount;
+}
+
+
+
+void PPWarning (unsigned WarnNum, ...)
+/* Print warning message. For use within the preprocessor. */
+{
+    va_list ap;
+
+    if (!NoWarn) {
+       fprintf (stderr, "%s(%u): Warning #%u: ", fin, ln, WarnNum);
+
+       va_start (ap, WarnNum);
+       vfprintf (stderr, WarnMsg [WarnNum-1], ap);
+       va_end (ap);
+       fprintf (stderr, "\n");
+    }
+    ++WarningCount;
+}
+
+
+
+void Error (unsigned ErrNum, ...)
+/* Print an error message */
+{
+    va_list ap;
+
+    fprintf (stderr, "%s(%u): Error #%u: ", fin, curpos, ErrNum);
+
+    va_start (ap, ErrNum);
+    vfprintf (stderr, ErrMsg [ErrNum-1], ap);
+    va_end (ap);
+    fprintf (stderr, "\n");
+
+    if (Verbose) {
+               fprintf (stderr, "Line: %s\n", line);
+    }
+    ++ErrorCount;
+    if (ErrorCount > 10) {
+               Fatal (FAT_TOO_MANY_ERRORS);
+    }
+}
+
+
+
+void PPError (unsigned ErrNum, ...)
+/* Print an error message. For use within the preprocessor.  */
+{
+    va_list ap;
+
+    fprintf (stderr, "%s(%u): Error #%u: ", fin, ln, ErrNum);
+
+    va_start (ap, ErrNum);
+    vfprintf (stderr, ErrMsg [ErrNum-1], ap);
+    va_end (ap);
+    fprintf (stderr, "\n");
+
+    ++ErrorCount;
+    if (ErrorCount > 10) {
+               Fatal (FAT_TOO_MANY_ERRORS);
+    }
+}
+
+
+
+void Fatal (unsigned FatNum, ...)
+/* Print a message about a fatal error and die */
+{
+    va_list ap;
+
+    fprintf (stderr, "%s(%u): Fatal #%u: ", fin, curpos, FatNum);
+
+    va_start (ap, FatNum);
+    vfprintf (stderr, FatMsg [FatNum-1], ap);
+    va_end (ap);
+    fprintf (stderr, "\n");
+
+    if (Verbose) {
+               fprintf (stderr, "Line: %s\n", line);
+    }
+    exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (char* Format, ...)
+/* Print a message about an internal compiler error and die. */
+{
+    va_list ap;
+
+    fprintf (stderr, "%s(%u): Internal compiler error:\n", fin, curpos);
+
+    va_start (ap, Format);
+    vfprintf (stderr, Format, ap);
+    va_end (ap);
+    fprintf (stderr, "\nLine: %s\n", line);
+
+    /* Use abort to create a core dump */
+    abort ();
+}
+
+
+
+void ErrorReport (void)
+/* Report errors (called at end of compile) */
+{
+    if (ErrorCount == 0 && Verbose) {
+       printf ("No errors.\n");
+    }
+}
+
+
+
diff --git a/src/cc65/error.h b/src/cc65/error.h
new file mode 100644 (file)
index 0000000..6e2912c
--- /dev/null
@@ -0,0 +1,206 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 error.h                                  */
+/*                                                                           */
+/*                 Error handling for the cc65 C compiler                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Warning numbers */
+enum Warnings {
+    WARN_NONE,                         /* No warning */
+    WARN_UNREACHABLE_CODE,
+    WARN_COND_NEVER_TRUE,
+    WARN_COND_ALWAYS_TRUE,
+    WARN_PTR_TO_INT_CONV,
+    WARN_INT_TO_PTR_CONV,
+    WARN_FUNC_WITHOUT_PROTO,
+    WARN_UNKNOWN_PRAGMA,
+    WARN_NO_CASE_LABELS,
+    WARN_FUNC_MUST_BE_EXTERN,
+    WARN_UNUSED_PARM,
+    WARN_UNUSED_ITEM,
+    WARN_CONSTANT_IS_LONG,
+    WARN_NESTED_COMMENT,
+    WARN_COUNT                         /* Warning count */
+};
+
+/* Error numbers */
+enum Errors {
+    ERR_NONE,                          /* No error */
+    ERR_INVALID_CHAR,
+    ERR_UNEXPECTED_NEWLINE,
+    ERR_EOF_IN_COMMENT,
+    ERR_SYNTAX,
+    ERR_QUOTE_EXPECTED,
+    ERR_COLON_EXPECTED,
+    ERR_SEMICOLON_EXPECTED,
+    ERR_LPAREN_EXPECTED,
+    ERR_RPAREN_EXPECTED,
+    ERR_LBRACK_EXPECTED,
+    ERR_RBRACK_EXPECTED,
+    ERR_LCURLY_EXPECTED,
+    ERR_RCURLY_EXPECTED,
+    ERR_IDENT_EXPECTED,
+    ERR_TYPE_EXPECTED,
+    ERR_INCOMPATIBLE_TYPES,
+    ERR_INCOMPATIBLE_POINTERS,
+    ERR_TOO_MANY_FUNC_ARGS,
+    ERR_TOO_FEW_FUNC_ARGS,
+    ERR_MACRO_ARGCOUNT,
+    ERR_DUPLICATE_MACRO_ARG,
+    ERR_VAR_IDENT_EXPECTED,
+    ERR_INT_EXPR_EXPECTED,
+    ERR_CONST_EXPR_EXPECTED,
+    ERR_NO_ACTIVE_LOOP,
+    ERR_INCLUDE_LTERM_EXPECTED,
+    ERR_INCLUDE_RTERM_EXPECTED,
+    ERR_INCLUDE_NOT_FOUND,
+    ERR_INCLUDE_OPEN_FAILURE,
+    ERR_INVALID_USER_ERROR,
+    ERR_USER_ERROR,
+    ERR_UNEXPECTED_CPP_ENDIF,
+    ERR_UNEXPECTED_CPP_ELSE,
+    ERR_CPP_ENDIF_EXPECTED,
+    ERR_CPP_DIRECTIVE_EXPECTED,
+    ERR_MULTIPLE_DEFINITION,
+    ERR_STRLIT_EXPECTED,
+    ERR_WHILE_EXPECTED,
+    ERR_MUST_RETURN_VALUE,
+    ERR_CANNOT_RETURN_VALUE,
+    ERR_UNEXPECTED_CONTINUE,
+    ERR_UNDEFINED_SYMBOL,
+    ERR_UNDEFINED_LABEL,
+    ERR_INCLUDE_NESTING,
+    ERR_TOO_MANY_LOCALS,
+    ERR_TOO_MANY_INITIALIZERS,
+    ERR_INIT_INCOMPLETE_TYPE,
+    ERR_CANNOT_SUBSCRIPT,
+    ERR_OP_NOT_ALLOWED,
+    ERR_STRUCT_EXPECTED,
+    ERR_STRUCT_FIELD_MISMATCH,
+    ERR_STRUCT_PTR_EXPECTED,
+    ERR_LVALUE_EXPECTED,
+    ERR_EXPR_EXPECTED,
+    ERR_CPP_EXPR_EXPECTED,
+    ERR_ILLEGAL_TYPE,
+    ERR_ILLEGAL_FUNC_CALL,
+    ERR_ILLEGAL_INDIRECT,
+    ERR_ILLEGAL_ADDRESS,
+    ERR_ILLEGAL_MACRO_CALL,
+    ERR_ILLEGAL_HEX_DIGIT,
+    ERR_ILLEGAL_CHARCONST,
+    ERR_ILLEGAL_MODIFIER,
+    ERR_ILLEGAL_STORAGE_CLASS,
+    ERR_DIV_BY_ZERO,
+    ERR_MOD_BY_ZERO,
+    ERR_RANGE,
+    ERR_SYMBOL_KIND,
+    ERR_LEVEL_NESTING,
+    ERR_MISSING_PARAM_NAME,
+    ERR_OLD_STYLE_PROTO,
+    ERR_PARAM_DECL,
+    ERR_CANNOT_TAKE_ADDR_OF_REG,
+    ERR_ILLEGAL_SIZE,
+    ERR_FASTCALL,
+    ERR_UNKNOWN_SIZE,
+    ERR_COUNT                          /* Error count */
+};
+
+/* Fatal errors */
+enum Fatals {
+    FAT_NONE,
+    FAT_TOO_MANY_ERRORS,
+    FAT_CANNOT_OPEN_OUTPUT,
+    FAT_CANNOT_WRITE_OUTPUT,
+    FAT_CANNOT_OPEN_INPUT,
+    FAT_OUT_OF_MEMORY,
+    FAT_STACK_OVERFLOW,
+    FAT_STACK_EMPTY,
+    FAT_OUT_OF_STRSPACE,
+    FAT_TOO_MANY_CASE_LABELS,
+    FAT_COUNT                          /* Fatal error count */
+};
+
+
+
+/* Count of errors/warnings */
+extern unsigned ErrorCount;
+extern unsigned WarningCount;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...);
+/* Print warning message. */
+
+void PPWarning (unsigned WarnNum, ...);
+/* Print warning message. For use within the preprocessor. */
+
+void Error (unsigned ErrNum, ...);
+/* Print an error message */
+
+void PPError (unsigned ErrNum, ...);
+/* Print an error message. For use within the preprocessor.  */
+
+void Fatal (unsigned FatNum, ...);
+/* Print a message about a fatal error and die */
+
+void Internal (char* Format, ...);
+/* Print a message about an internal compiler error and die. */
+
+void ErrorReport (void);
+/* Report errors (called at end of compile) */
+
+
+
+/* End of error.h */
+#endif
+
+
+
+
+
diff --git a/src/cc65/expr.c b/src/cc65/expr.c
new file mode 100644 (file)
index 0000000..009edce
--- /dev/null
@@ -0,0 +1,2980 @@
+/*
+ * expr.c
+ *
+ * Ullrich von Bassewitz, 21.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "function.h"
+#include "global.h"
+#include "io.h"
+#include "litpool.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "preproc.h"
+#include "scanner.h"
+#include "stdfunc.h"
+#include "symtab.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Generator attributes */
+#define GEN_NOPUSH     0x01            /* Don't push lhs */
+
+/* Map a generator function and its attributes to a token */
+typedef struct {
+    unsigned char Tok;                 /* Token to map to */
+    unsigned char Flags;               /* Flags for generator function */
+    void                 (*Func) (unsigned, unsigned long);    /* Generator func */
+} GenDesc;
+
+/* Descriptors for the operations */
+static GenDesc GenMUL    = { STAR,   GEN_NOPUSH,                       g_mul };
+static GenDesc GenDIV    = { DIV,    GEN_NOPUSH,                       g_div };
+static GenDesc GenMOD    = { MOD,    GEN_NOPUSH,                       g_mod };
+static GenDesc GenASL    = { ASL,    GEN_NOPUSH,                       g_asl };
+static GenDesc GenASR    = { ASR,    GEN_NOPUSH,               g_asr };
+static GenDesc GenLT     = { LT,     GEN_NOPUSH,               g_lt  };
+static GenDesc GenLE     = { LE,     GEN_NOPUSH,               g_le  };
+static GenDesc GenGE     = { GE,     GEN_NOPUSH,               g_ge  };
+static GenDesc GenGT     = { GT,     GEN_NOPUSH,               g_gt  };
+static GenDesc GenEQ     = { EQ,     GEN_NOPUSH,               g_eq  };
+static GenDesc GenNE     = { NE,     GEN_NOPUSH,               g_ne  };
+static GenDesc GenAND    = { AMP,    GEN_NOPUSH,                       g_and };
+static GenDesc GenXOR    = { XOR,    GEN_NOPUSH,                       g_xor };
+static GenDesc GenOR     = { BAR,    GEN_NOPUSH,                       g_or  };
+static GenDesc GenPASGN  = { PASGN,  GEN_NOPUSH,                       g_add };
+static GenDesc GenSASGN  = { SASGN,  GEN_NOPUSH,                       g_sub };
+static GenDesc GenMASGN  = { MASGN,  GEN_NOPUSH,                       g_mul };
+static GenDesc GenDASGN  = { DASGN,  GEN_NOPUSH,                       g_div };
+static GenDesc GenMOASGN = { MOASGN, GEN_NOPUSH,                       g_mod };
+static GenDesc GenSLASGN = { SLASGN, GEN_NOPUSH,                       g_asl };
+static GenDesc GenSRASGN = { SRASGN, GEN_NOPUSH,                       g_asr };
+static GenDesc GenAASGN  = { AASGN,  GEN_NOPUSH,                       g_and };
+static GenDesc GenXOASGN = { XOASGN, GEN_NOPUSH,                       g_xor };
+static GenDesc GenOASGN  = { OASGN,  GEN_NOPUSH,                       g_or  };
+
+
+
+/*****************************************************************************/
+/*                            Function forwards                             */
+/*****************************************************************************/
+
+
+
+static int hie10 (struct expent* lval);
+/* Handle ++, --, !, unary - etc. */
+
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static unsigned GlobalModeFlags (unsigned flags)
+/* Return the addressing mode flags for the variable with the given flags */
+{
+    flags &= E_MCTYPE;
+    if (flags == E_TGLAB) {
+       /* External linkage */
+       return CF_EXTERNAL;
+    } else if (flags == E_TREGISTER) {
+       /* Register variable */
+       return CF_REGVAR;
+    } else {
+       /* Static */
+       return CF_STATIC;
+    }
+}
+
+
+
+static int IsNullPtr (struct expent* lval)
+/* Return true if this is the NULL pointer constant */
+{
+    return (IsInt (lval->e_tptr) &&            /* Is it an int? */
+                   lval->e_flags == E_MCONST &&        /* Is it constant? */
+           lval->e_const == 0);                /* And is it's value zero? */
+}
+
+
+
+static type* promoteint (type* lhst, type* rhst)
+/* In an expression with two ints, return the type of the result */
+{
+    /* Rules for integer types:
+     *   - If one of the values is a long, the result is long.
+     *   - If one of the values        is unsigned, the result is also unsigned.
+     *   - Otherwise the result is an int.
+     */
+    if (IsLong (lhst) || IsLong (rhst)) {
+       if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
+                   return type_ulong;
+       } else {
+           return type_long;
+       }
+    } else {
+       if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
+           return type_uint;
+       } else {
+           return type_int;
+       }
+    }
+}
+
+
+
+static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush)
+/* Adjust the two values for a binary operation. lhs is expected on stack or
+ * to be constant, rhs is expected to be in the primary register or constant.
+ * The function will put the type of the result into lhs and return the
+ * code generator flags for the operation.
+ * If NoPush is given, it is assumed that the operation does not expect the lhs
+ * to be on stack, and that lhs is in a register instead.
+ * Beware: The function does only accept int types.
+ */
+{
+    unsigned ltype, rtype;
+    unsigned flags;
+
+    /* Get the type strings */
+    type* lhst = lhs->e_tptr;
+    type* rhst = rhs->e_tptr;
+
+    /* Generate type adjustment code if needed */
+    ltype = TypeOf (lhst);
+    if (lhs->e_flags == E_MCONST) {
+       ltype |= CF_CONST;
+    }
+    if (NoPush) {
+       /* Value is in primary register*/
+       ltype |= CF_REG;
+    }
+    rtype = TypeOf (rhst);
+    if (rhs->e_flags == E_MCONST) {
+       rtype |= CF_CONST;
+    }
+    flags = g_typeadjust (ltype, rtype);
+
+    /* Set the type of the result */
+    lhs->e_tptr = promoteint (lhst, rhst);
+
+    /* Return the code generator flags */
+    return flags;
+}
+
+
+
+unsigned assignadjust (type* lhst, struct expent* rhs)
+/* Adjust the type of the right hand expression so that it can be assigned to
+ * the type on the left hand side. This function is used for assignment and
+ * for converting parameters in a function call. It returns the code generator
+ * flags for the operation. The type string of the right hand side will be
+ * set to the type of the left hand side.
+ */
+{
+    /* Get the type of the right hand side */
+    type* rhst = rhs->e_tptr;
+
+    /* After calling this function, rhs will have the type of the lhs */
+    rhs->e_tptr = lhst;
+
+    /* First, do some type checking */
+    if (IsVoid (lhst) || IsVoid (rhst)) {
+       /* If one of the sides are of type void, output a more apropriate
+        * error message.
+        */
+               Error (ERR_ILLEGAL_TYPE);
+    } else if (IsInt (lhst)) {
+       if (IsPtr (rhst)) {
+           /* Pointer -> int conversion */
+           Warning (WARN_PTR_TO_INT_CONV);
+               } else if (!IsInt (rhst)) {
+           Error (ERR_INCOMPATIBLE_TYPES);
+       } else {
+           /* Adjust the int types. To avoid manipulation of TOS mark lhs
+            * as const.
+            */
+           unsigned flags = TypeOf (rhst);
+                   if (rhs->e_flags & E_MCONST) {
+               flags |= CF_CONST;
+           }
+           return g_typeadjust (TypeOf (lhst) | CF_CONST, flags);
+        }
+    } else if (IsPtr (lhst)) {
+       if (IsPtr (rhst)) {
+           /* Pointer to pointer assignment is valid, if:
+            *   - both point to the same types, or
+            *   - the rhs pointer is a void pointer, or
+            *   - the lhs pointer is a void pointer.
+            */
+           type* left  = Indirect (lhst);
+           type* right = Indirect (rhst);
+                   if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
+               Error (ERR_INCOMPATIBLE_POINTERS);
+           }
+       } else if (IsInt (rhst)) {
+           /* Int to pointer assignment is valid only for constant zero */
+           if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) {
+               Warning (WARN_INT_TO_PTR_CONV);
+           }
+       } else if (IsFuncPtr (lhst) && IsFunc(rhst)) {
+           /* Assignment of function to function pointer is allowed, provided
+            * that both functions have the same parameter list.
+            */
+           if (!EqualTypes(Indirect (lhst), rhst)) {
+               Error (ERR_INCOMPATIBLE_TYPES);
+           }
+       } else {
+           Error (ERR_INCOMPATIBLE_TYPES);
+       }
+    } else {
+       Error (ERR_INCOMPATIBLE_TYPES);
+    }
+
+    /* Return an int value in all cases where the operands are not both ints */
+    return CF_INT;
+}
+
+
+
+void DefineData (struct expent* lval)
+/* Output a data definition for the given expression */
+{
+    unsigned flags = lval->e_flags;
+
+    switch (flags & E_MCTYPE) {
+
+               case E_TCONST:
+           /* Number */
+           g_defdata (TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
+                   break;
+
+       case E_TREGISTER:
+           /* Register variable. Taking the address is usually not
+            * allowed.
+            */
+           if (!AllowRegVarAddr) {
+               Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
+           }
+           /* FALLTHROUGH */
+
+               case E_TGLAB:
+        case E_TLLAB:
+                   /* Local or global symbol */
+           g_defdata (GlobalModeFlags (flags), lval->e_name, lval->e_const);
+           break;
+
+               case E_TLIT:
+           /* a literal of some kind */
+                   g_defdata (CF_STATIC, LiteralLabel, lval->e_const);
+                   break;
+
+               default:
+           Internal ("Unknown constant type: %04X", flags);
+    }
+}
+
+
+
+static void lconst (unsigned flags, struct expent* lval)
+/* Load primary reg with some constant value. */
+{
+    switch (lval->e_flags & E_MCTYPE) {
+
+       case E_TLOFFS:
+                   g_leasp (lval->e_const);
+           break;
+
+               case E_TCONST:
+           /* Number constant */
+                   g_getimmed (flags | TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
+                   break;
+
+       case E_TREGISTER:
+           /* Register variable. Taking the address is usually not
+            * allowed.
+            */
+           if (!AllowRegVarAddr) {
+               Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
+           }
+           /* FALLTHROUGH */
+
+               case E_TGLAB:
+        case E_TLLAB:
+                   /* Local or global symbol, load address */
+           flags |= GlobalModeFlags (lval->e_flags);
+           flags &= ~CF_CONST;
+           g_getimmed (flags, lval->e_name, lval->e_const);
+                   break;
+
+               case E_TLIT:
+           /* Literal string */
+           g_getimmed (CF_STATIC, LiteralLabel, lval->e_const);
+                   break;
+
+               default:
+           Internal ("Unknown constant type: %04X", lval->e_flags);
+    }
+}
+
+
+
+static int kcalc (int tok, long val1, long val2)
+/* Calculate an operation with left and right operand constant. */
+{
+    switch (tok) {
+       case EQ:
+           return (val1 == val2);
+       case NE:
+           return (val1 != val2);
+       case LT:
+           return (val1 < val2);
+       case LE:
+           return (val1 <= val2);
+       case GE:
+           return (val1 >= val2);
+       case GT:
+           return (val1 > val2);
+       case BAR:
+           return (val1 | val2);
+       case XOR:
+           return (val1 ^ val2);
+       case AMP:
+           return (val1 & val2);
+       case ASR:
+           return (val1 >> val2);
+       case ASL:
+           return (val1 << val2);
+       case STAR:
+           return (val1 * val2);
+       case DIV:
+           if (val2 == 0) {
+               Error (ERR_DIV_BY_ZERO);
+               return 0x7FFFFFFF;
+           }
+           return (val1 / val2);
+       case MOD:
+           if (val2 == 0) {
+               Error (ERR_MOD_BY_ZERO);
+               return 0;
+           }
+           return (val1 % val2);
+       default:
+           Internal ("kcalc: got token 0x%X\n", tok);
+           return 0;
+    }
+}
+
+
+
+static GenDesc* FindGen (int Tok, GenDesc** Table)
+{
+    GenDesc* G;
+    while ((G = *Table) != 0) {
+       if (G->Tok == Tok) {
+           return G;
+       }
+       ++Table;
+    }
+    return 0;
+}
+
+
+
+static int istypeexpr (void)
+/* Return true if some sort of variable or type is waiting (helper for cast
+ * and sizeof() in hie10).
+ */
+{
+    SymEntry* Entry;
+
+    return curtok == LPAREN && (
+                   (nxttok >= FIRSTTYPE && nxttok <= LASTTYPE) ||
+           (nxttok == CONST)                           ||
+                   (nxttok  == IDENT                       &&
+           (Entry = FindSym (NextTok.Ident)) != 0  &&
+           IsTypeDef (Entry))
+           );
+}
+
+
+
+static void PushAddr (struct expent* lval)
+/* If the expression contains an address that was somehow evaluated,
+ * push this address on the stack. This is a helper function for all
+ * sorts of implicit or explicit assignment functions where the lvalue
+ * must be saved if it's not constant, before evaluating the rhs.
+ */
+{
+    /* Get the address on stack if needed */
+    if (lval->e_flags != E_MREG && (lval->e_flags & E_MEXPR)) {
+       /* Push the address (always a pointer) */
+       g_push (CF_PTR, 0);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void exprhs (unsigned flags, int k, struct expent *lval)
+/* Put the result of an expression into the primary register */
+{
+    int f;
+
+    f = lval->e_flags;
+    if (k) {
+               /* Dereferenced lvalue */
+       flags |= TypeOf (lval->e_tptr);
+       if (lval->e_test & E_FORCETEST) {
+           flags |= CF_TEST;
+           lval->e_test &= ~E_FORCETEST;
+       }
+               if (f & E_MGLOBAL) {    /* ref to globalvar */
+                   /* Generate code */
+           flags |= GlobalModeFlags (f);
+                   g_getstatic (flags, lval->e_name, lval->e_const);
+               } else if (f & E_MLOCAL) {
+           /* ref to localvar */
+                   g_getlocal (flags, lval->e_const);
+       } else if (f & E_MCONST) {
+           /* ref to absolute address */
+           g_getstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
+       } else if (f == E_MEOFFS) {
+           g_getind (flags, lval->e_const);
+       } else if (f != E_MREG) {
+           g_getind (flags, 0);
+       }
+    } else if (f == E_MEOFFS) {
+       /* reference not storable */
+       flags |= TypeOf (lval->e_tptr);
+               g_inc (flags | CF_CONST, lval->e_const);
+    } else if ((f & E_MEXPR) == 0) {
+       /* Constant of some sort, load it into the primary */
+       lconst (flags, lval);
+    }
+    if (lval->e_test & E_FORCETEST) {  /* we testing this value? */
+       /* debug... */
+       AddCodeHint ("forcetest");
+       flags |= TypeOf (lval->e_tptr);
+               g_test (flags);                 /* yes, force a test */
+               lval->e_test &= ~E_FORCETEST;
+    }
+}
+
+
+static void callfunction (struct expent* lval)
+/* Perform a function call.  Called from hie11, this routine will
+ * either call the named function, or if the supplied ptr is zero,
+ * will call the contents of P.
+ */
+{
+    struct expent lval2;
+    FuncDesc*    Func;         /* Function descriptor */
+    int                  Ellipsis;     /* True if we have an open param list */
+    SymEntry*    Param;        /* Current formal parameter */
+    unsigned     ParamCount;   /* Actual parameter count */
+    unsigned     ParamSize;    /* Number of parameter bytes */
+    unsigned     Flags;
+    unsigned     CFlags;
+    CodeMark     Mark;
+
+
+    /* Get a pointer to the function descriptor from the type string */
+    Func = GetFuncDesc (lval->e_tptr);
+
+    /* Initialize vars to keep gcc silent */
+    Param = 0;
+    Mark  = 0;
+
+    /* Check if this is a function pointer. If so, save it. If not, check for
+     * special known library functions that may be inlined.
+     */
+    if (lval->e_flags & E_MEXPR) {
+               /* Function pointer is in primary register, save it */
+               Mark = GetCodePos ();
+               g_save (CF_PTR);
+    } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) {
+               /* Inline this function */
+               HandleStdFunc (lval);
+               return;
+    }
+
+    /* Parse the actual parameter list */
+    ParamSize  = 0;
+    ParamCount = 0;
+    Ellipsis   = 0;
+    while (curtok != RPAREN) {
+
+       /* Add a hint for the optimizer */
+       AddCodeHint ("param:start");
+
+       /* Count arguments */
+       ++ParamCount;
+
+       /* Fetch the pointer to the next argument, check for too many args */
+       if (ParamCount <= Func->ParamCount) {
+           if (ParamCount == 1) {
+               /* First argument */
+               Param = Func->SymTab->SymHead;
+           } else {
+               /* Next argument */
+               Param = Param->NextSym;
+               CHECK ((Param->Flags & SC_PARAM) != 0);
+           }
+       } else if (!Ellipsis) {
+           /* Too many arguments. Do we have an open param list? */
+           if ((Func->Flags & FD_ELLIPSIS) == 0) {
+               /* End of param list reached, no ellipsis */
+               Error (ERR_TOO_MANY_FUNC_ARGS);
+           }
+           /* Assume an ellipsis even in case of errors to avoid an error
+            * message for each other argument.
+            */
+           Ellipsis = 1;
+       }
+
+       /* Do some optimization: If we have a constant value to push,
+        * use a special function that may optimize.
+        */
+               CFlags = CF_NONE;
+               if (!Ellipsis && SizeOf (Param->Type) == 1) {
+           CFlags = CF_FORCECHAR;
+       }
+       Flags = 0;
+               if (evalexpr (CFlags, hie1, &lval2) == 0) {
+                   /* A constant value */
+           Flags |= CF_CONST;
+       }
+
+       /* If we don't have an argument spec, accept anything, otherwise
+        * convert the actual argument to the type needed.
+        */
+               if (!Ellipsis) {
+           /* Promote the argument if needed */
+                   assignadjust (Param->Type, &lval2);
+           /* If we have a prototype, chars may be pushed as chars */
+           Flags |= CF_FORCECHAR;
+               }
+
+       /* Use the type of the argument for the push */
+               Flags |= TypeOf (lval2.e_tptr);
+
+       /* If this is a fastcall function, don't push the last argument */
+               if (ParamCount == Func->ParamCount && (Func->Flags & FD_FASTCALL) != 0) {
+           /* Just load the argument into the primary. This is only needed if
+            * we have a constant argument, otherwise the value is already in
+            * the primary.
+            */
+           if (Flags & CF_CONST) {
+               exprhs (CF_FORCECHAR, 0, &lval2);
+           }
+       } else {
+           /* Push the argument, count the argument size */
+           g_push (Flags, lval2.e_const);
+           ParamSize += sizeofarg (Flags);
+       }
+
+       /* Add an optimizer hint */
+       AddCodeHint ("param:end");
+
+       /* Check for end of argument list */
+       if (curtok != COMMA) {
+           break;
+       }
+       gettok ();
+    }
+
+    /* We need the closing bracket here */
+    ConsumeRParen ();
+
+    /* Check if we had enough parameters */
+    if (ParamCount < Func->ParamCount) {
+       Error (ERR_TOO_FEW_FUNC_ARGS);
+    }
+
+    /* */
+    if (lval->e_flags & E_MEXPR) {
+       /* Function called via pointer: Restore it and call function */
+       if (ParamSize != 0) {
+           g_restore (CF_PTR);
+       } else {
+           /* We had no parameters - remove save code */
+                   RemoveCode (Mark);
+       }
+       g_callind (TypeOf (lval->e_tptr), ParamSize);
+    } else {
+               g_call (TypeOf (lval->e_tptr), (char*) lval->e_name, ParamSize);
+    }
+}
+
+
+
+void doasm (void)
+/* This function parses ASM statements. The syntax of the ASM directive
+ * looks like the one defined for C++ (C has no ASM directive), that is,
+ * a string literal in parenthesis.
+ */
+{
+    /* Skip the ASM */
+    gettok ();
+
+    /* Need left parenthesis */
+    ConsumeLParen ();
+
+    /* String literal */
+    if (curtok != SCONST) {
+       Error (ERR_STRLIT_EXPECTED);
+    } else {
+       /* Write the string directly into the output, followed by a newline */
+               AddCodeLine (GetLiteral (curval));
+
+       /* Reset the string pointer, effectivly clearing the string from the
+        * string table. Since we're working with one token lookahead, this
+        * will fail if the next token is also a string token, but that's a
+        * syntax error anyway, because we expect a right paren.
+        */
+       ResetLiteralOffs (curval);
+    }
+
+    /* Skip the string token */
+    gettok ();
+
+    /* Closing paren needed */
+    ConsumeRParen ();
+}
+
+
+
+static int primary (struct expent* lval)
+/* This is the lowest level of the expression parser. */
+{
+    int k;
+
+    /* not a test at all, yet */
+    lval->e_test = 0;
+
+    /* Character and integer constants. */
+    if (curtok == ICONST || curtok == CCONST) {
+       lval->e_flags = E_MCONST | E_TCONST;
+       lval->e_tptr  = curtype;
+       lval->e_const = curval;
+       gettok ();
+       return 0;
+    }
+
+    /* Process parenthesized subexpression by calling the whole parser
+     * recursively.
+     */
+    if (curtok == LPAREN) {
+       gettok ();
+       memset (lval, 0, sizeof (*lval));       /* Remove any attributes */
+       k = hie0 (lval);
+               ConsumeRParen ();
+       return k;
+    }
+
+    /* All others may only be used if the expression evaluation is not called
+     * recursively by the preprocessor.
+     */
+    if (Preprocessing) {
+               /* Illegal expression in PP mode */
+       Error (ERR_CPP_EXPR_EXPECTED);
+       lval->e_flags = E_MCONST;
+       lval->e_tptr = type_int;
+       return 0;
+    }
+
+    /* Identifier? */
+    if (curtok == IDENT) {
+
+       SymEntry* Sym;
+       ident Ident;
+
+       /* Get a pointer to the symbol table entry */
+               Sym = FindSym (CurTok.Ident);
+
+       /* Is the symbol known? */
+       if (Sym) {
+
+           /* We found the symbol - skip the name token */
+           gettok ();
+
+           /* The expression type is the symbol type */
+           lval->e_tptr = Sym->Type;
+
+           /* Check for illegal symbol types */
+           if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
+               /* Cannot use labels in expressions */
+               Error (ERR_SYMBOL_KIND);
+               return 1;
+                   } else if (Sym->Flags & SC_TYPE) {
+               /* Cannot use type symbols */
+               Error (ERR_VAR_IDENT_EXPECTED);
+               /* Assume an int type to make lval valid */
+               lval->e_flags = E_MLOCAL | E_TLOFFS;
+               lval->e_tptr = type_int;
+               lval->e_const = 0;
+               return 0;
+           }
+
+           /* Check for legal symbol types */
+                   if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
+               lval->e_flags = E_MCONST;
+               lval->e_const = Sym->V.EnumVal;
+               return 0;
+           } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
+               /* Function */
+               lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+               lval->e_name = (unsigned long) Sym->Name;
+               lval->e_const = 0;
+           } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
+               /* Local variable */
+               lval->e_flags = E_MLOCAL | E_TLOFFS;
+               lval->e_const = Sym->V.Offs;
+           } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
+               /* Static variable */
+               if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
+                   lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+                   lval->e_name = (unsigned long) Sym->Name;
+               } else {
+                   lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
+                   lval->e_name = Sym->V.Label;
+               }
+               lval->e_const = 0;
+           } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
+               /* Register variable, zero page based */
+               lval->e_flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
+               lval->e_name  = Sym->V.Offs;
+               lval->e_const = 0;
+                   } else {
+               /* Local static variable */
+               lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
+               lval->e_name  = Sym->V.Offs;
+               lval->e_const = 0;
+           }
+
+           /* The symbol is referenced now */
+           Sym->Flags |= SC_REF;
+                   if (IsFunc (lval->e_tptr) || IsArray (lval->e_tptr)) {
+               return 0;
+           }
+           return 1;
+       }
+
+       /* We did not find the symbol. Remember the name, then skip it */
+       strcpy (Ident, CurTok.Ident);
+       gettok ();
+
+       /* IDENT is either an auto-declared function or an undefined variable. */
+       if (curtok == LPAREN) {
+           /* Declare a function returning int. For that purpose, prepare a
+            * function signature for a function having an empty param list
+            * and returning int.
+            */
+           Warning (WARN_FUNC_WITHOUT_PROTO);
+           Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF);
+           lval->e_tptr  = Sym->Type;
+           lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+                   lval->e_name  = (unsigned long) Sym->Name;
+           lval->e_const = 0;
+           return 0;
+
+       } else {
+
+           /* Undeclared Variable */
+           Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
+           lval->e_flags = E_MLOCAL | E_TLOFFS;
+           lval->e_tptr = type_int;
+           lval->e_const = 0;
+           Error (ERR_UNDEFINED_SYMBOL, Ident);
+           return 1;
+
+       }
+    }
+
+    /* String literal? */
+    if (curtok == SCONST) {
+       lval->e_flags = E_MCONST | E_TLIT;
+               lval->e_const = curval;
+       lval->e_tptr  = GetCharArrayType (strlen (GetLiteral (curval)));
+       gettok ();
+       return 0;
+    }
+
+    /* ASM statement? */
+    if (curtok == ASM) {
+       doasm ();
+       lval->e_tptr  = type_void;
+       lval->e_flags = E_MEXPR;
+       lval->e_const = 0;
+       return 0;
+    }
+
+    /* __AX__ and __EAX__ pseudo values? */
+    if (curtok == AX || curtok == EAX) {
+               lval->e_tptr  = (curtok == AX)? type_uint : type_ulong;
+       lval->e_flags = E_MREG;
+       lval->e_test &= ~E_CC;
+       lval->e_const = 0;
+       gettok ();
+       return 1;               /* May be used as lvalue */
+    }
+
+    /* Illegal primary. */
+    Error (ERR_EXPR_EXPECTED);
+    lval->e_flags = E_MCONST;
+    lval->e_tptr = type_int;
+    return 0;
+}
+
+
+
+static int arrayref (int k, struct expent* lval)
+/* Handle an array reference */
+{
+    unsigned lflags;
+    unsigned rflags;
+    int ConstBaseAddr;
+    int ConstSubAddr;
+    int l;
+    struct expent lval2;
+    CodeMark Mark1;
+    CodeMark Mark2;
+    type* tptr1;
+    type* tptr2;
+
+
+    /* Skip the bracket */
+    gettok ();
+
+    /* Get the type of left side */
+    tptr1 = lval->e_tptr;
+
+    /* We can apply a special treatment for arrays that have a const base
+     * address. This is true for most arrays and will produce a lot better
+     * code. Check if this is a const base address.
+     */
+    lflags = lval->e_flags & ~E_MCTYPE;
+    ConstBaseAddr = (lflags == E_MCONST)       || /* Constant numeric address */
+                            (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */
+                            lflags == E_MLOCAL;          /* Local array */
+
+    /* If we have a constant base, we delay the address fetch */
+    Mark1 = GetCodePos ();
+    Mark2 = 0;         /* Silence gcc */
+    if (!ConstBaseAddr) {
+       /* Get a pointer to the array into the primary */
+       exprhs (CF_NONE, k, lval);
+
+       /* Get the array pointer on stack. Do not push more than 16
+        * bit, even if this value is greater, since we cannot handle
+        * other than 16bit stuff when doing indexing.
+        */
+       Mark2 = GetCodePos ();
+       g_push (CF_PTR, 0);
+    }
+
+    /* TOS now contains ptr to array elements. Get the subscript. */
+    l = hie0 (&lval2);
+    if (l == 0 && lval2.e_flags == E_MCONST) {
+
+       /* The array subscript is a constant - remove value from stack */
+       if (!ConstBaseAddr) {
+           RemoveCode (Mark2);
+           pop (CF_PTR);
+       } else {
+           /* Get an array pointer into the primary */
+           exprhs (CF_NONE, k, lval);
+       }
+
+       if (IsPtr (tptr1)) {
+
+           /* Scale the subscript value according to element size */
+           lval2.e_const *= PSizeOf (tptr1);
+
+           /* Remove code for lhs load */
+           RemoveCode (Mark1);
+
+           /* Handle constant base array on stack. Be sure NOT to
+            * handle pointers the same way, this won't work.
+            */
+           if (IsArray (tptr1) &&
+               ((lval->e_flags & ~E_MCTYPE) == E_MCONST ||
+               (lval->e_flags & ~E_MCTYPE) == E_MLOCAL ||
+               (lval->e_flags & E_MGLOBAL) != 0 ||
+               (lval->e_flags == E_MEOFFS))) {
+               lval->e_const += lval2.e_const;
+
+           } else {
+               /* Pointer - load into primary and remember offset */
+               if ((lval->e_flags & E_MEXPR) == 0 || k != 0) {
+                   exprhs (CF_NONE, k, lval);
+               }
+               lval->e_const = lval2.e_const;
+               lval->e_flags = E_MEOFFS;
+           }
+
+                   /* Result is of element type */
+           lval->e_tptr = Indirect (tptr1);
+
+           /* Done */
+           goto end_array;
+
+               } else if ((tptr2 = lval2.e_tptr) [0] & T_POINTER) {
+           /* Subscript is pointer, get element type */
+           lval2.e_tptr = Indirect (tptr2);
+
+           /* Scale the rhs value in the primary register */
+           g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
+           /* */
+           lval->e_tptr = lval2.e_tptr;
+       } else {
+           Error (ERR_CANNOT_SUBSCRIPT);
+       }
+
+       /* Add the subscript. Since arrays are indexed by integers,
+        * we will ignore the true type of the subscript here and
+        * use always an int.
+        */
+       g_inc (CF_INT | CF_CONST, lval2.e_const);
+
+    } else {
+
+       /* Array subscript is not constant. Load it into the primary */
+       Mark2 = GetCodePos ();
+        exprhs (CF_NONE, l, &lval2);
+
+       tptr2 = lval2.e_tptr;
+       if (IsPtr (tptr1)) {
+
+           /* Get the element type */
+           lval->e_tptr = Indirect (tptr1);
+
+                   /* Indexing is based on int's, so we will just use the integer
+            * portion of the index (which is in (e)ax, so there's no further
+            * action required).
+            */
+           g_scale (CF_INT, SizeOf (lval->e_tptr));
+
+       } else if (IsPtr (tptr2)) {
+
+           /* Get the element type */
+           lval2.e_tptr = Indirect (tptr2);
+
+           /* Get the int value on top. If we go here, we're sure,
+            * both values are 16 bit (the first one was truncated
+                    * if necessary and the second one is a pointer).
+            * Note: If ConstBaseAddr is true, we don't have a value on
+            * stack, so to "swap" both, just push the subscript.
+            */
+           if (ConstBaseAddr) {
+               g_push (CF_INT, 0);
+               exprhs (CF_NONE, k, lval);
+               ConstBaseAddr = 0;
+           } else {
+               g_swap (CF_INT);
+           }
+
+           /* Scale it */
+           g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
+           lval->e_tptr = lval2.e_tptr;
+       } else {
+           Error (ERR_CANNOT_SUBSCRIPT);
+       }
+
+       /* The offset is now in the primary register. It didn't have a
+        * constant base address for the lhs, the lhs address is already
+        * on stack, and we must add the offset. If the base address was
+        * constant, we call special functions to add the address to the
+        * offset value.
+        */
+       if (!ConstBaseAddr) {
+           /* Add the subscript. Both values are int sized. */
+           g_add (CF_INT, 0);
+       } else {
+
+           /* If the subscript has itself a constant address, it is often
+            * a better idea to reverse again the order of the evaluation.
+            * This will generate better code if the subscript is a byte
+            * sized variable. But beware: This is only possible if the
+            * subscript was not scaled, that is, if this was a byte array
+            * or pointer.
+            */
+           rflags = lval2.e_flags & ~E_MCTYPE;
+           ConstSubAddr = (rflags == E_MCONST)       || /* Constant numeric address */
+                                   (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */
+                           rflags == E_MLOCAL;          /* Local array */
+
+                   if (ConstSubAddr && SizeOf (lval->e_tptr) == 1) {
+
+               type* SavedType;
+
+               /* Reverse the order of evaluation */
+               unsigned flags = (SizeOf (lval2.e_tptr) == 1)? CF_CHAR : CF_INT;
+               RemoveCode (Mark2);
+
+               /* Get a pointer to the array into the primary. We have changed
+                * e_tptr above but we need the original type to load the
+                * address, so restore it temporarily.
+                */
+               SavedType = lval->e_tptr;
+               lval->e_tptr = tptr1;
+               exprhs (CF_NONE, k, lval);
+               lval->e_tptr = SavedType;
+
+               /* Add the variable */
+               if (rflags == E_MLOCAL) {
+                   g_addlocal (flags, lval2.e_const);
+               } else {
+                   flags |= GlobalModeFlags (lval2.e_flags);
+                   g_addstatic (flags, lval2.e_name, lval2.e_const);
+               }
+           } else {
+               if (lflags == E_MCONST) {
+                   /* Constant numeric address. Just add it */
+                   g_inc (CF_INT | CF_UNSIGNED, lval->e_const);
+               } else if (lflags == E_MLOCAL) {
+                   /* Base address is a local variable address */
+                   if (IsArray (tptr1)) {
+                       g_addaddr_local (CF_INT, lval->e_const);
+                   } else {
+                       g_addlocal (CF_PTR, lval->e_const);
+                   }
+               } else {
+                   /* Base address is a static variable address */
+                   unsigned flags = CF_INT;
+                   flags |= GlobalModeFlags (lval->e_flags);
+                   if (IsArray (tptr1)) {
+                       g_addaddr_static (flags, lval->e_name, lval->e_const);
+                   } else {
+                       g_addstatic (flags, lval->e_name, lval->e_const);
+                   }
+               }
+           }
+       }
+    }
+    lval->e_flags = E_MEXPR;
+end_array:
+    ConsumeRBrack ();
+    return !IsArray (lval->e_tptr);
+
+}
+
+
+
+static int structref (int k, struct expent* lval)
+/* Process struct field after . or ->. */
+{
+    ident Ident;
+    SymEntry* Field;
+    int flags;
+
+    /* Skip the token and check for an identifier */
+    gettok ();
+    if (curtok != IDENT) {
+       Error (ERR_IDENT_EXPECTED);
+       lval->e_tptr = type_int;
+       return 0;
+    }
+
+    /* Get the symbol table entry and check for a struct field */
+    strcpy (Ident, CurTok.Ident);
+    gettok ();
+    Field = FindStructField (lval->e_tptr, Ident);
+    if (Field == 0) {
+       Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
+               lval->e_tptr = type_int;
+       return 0;
+    }
+
+    /* If we have constant input data, the result is also constant */
+    flags = lval->e_flags & ~E_MCTYPE;
+    if (flags == E_MCONST ||
+               (k == 0 && (flags == E_MLOCAL ||
+                   (flags & E_MGLOBAL) != 0 ||
+                   lval->e_flags  == E_MEOFFS))) {
+       lval->e_const += Field->V.Offs;
+    } else {
+       if ((flags & E_MEXPR) == 0 || k != 0) {
+           exprhs (CF_NONE, k, lval);
+       }
+       lval->e_const = Field->V.Offs;
+       lval->e_flags = E_MEOFFS;
+    }
+    lval->e_tptr = Field->Type;
+    return !IsArray (Field->Type);
+}
+
+
+
+static int hie11 (struct expent *lval)
+/* Handle compound types (structs and arrays) */
+{
+    int k;
+    type* tptr;
+
+
+    k = primary (lval);
+    if (curtok < LBRACK || curtok > PREF) {
+       /* Not for us */
+               return k;
+    }
+
+    while (1) {
+
+       if (curtok == LBRACK) {
+
+           /* Array reference */
+           k = arrayref (k, lval);
+
+       } else if (curtok == LPAREN) {
+
+           /* Function call. Skip the opening parenthesis */
+           gettok ();
+           tptr = lval->e_tptr;
+           if (IsFunc (tptr) || IsFuncPtr (tptr)) {
+               if (IsFuncPtr (tptr)) {
+                   /* Pointer to function. Handle transparently */
+                   exprhs (CF_NONE, k, lval);  /* Function pointer to A/X */
+                   ++lval->e_tptr;             /* Skip T_PTR */
+                   lval->e_flags |= E_MEXPR;
+               }
+               callfunction (lval);
+               lval->e_flags = E_MEXPR;
+               lval->e_tptr += DECODE_SIZE + 1;        /* Set to result */
+           } else {
+               Error (ERR_ILLEGAL_FUNC_CALL);
+           }
+           k = 0;
+
+       } else if (curtok == DOT) {
+
+           if (!IsStruct (lval->e_tptr)) {
+               Error (ERR_STRUCT_EXPECTED);
+           }
+           k = structref (0, lval);
+
+       } else if (curtok == PREF) {
+
+           tptr = lval->e_tptr;
+           if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) {
+               Error (ERR_STRUCT_PTR_EXPECTED);
+           }
+           k = structref (k, lval);
+
+       } else {
+           return k;
+       }
+    }
+}
+
+
+
+static void store (struct expent* lval)
+/* Store primary reg into this reference */
+{
+    int f;
+    unsigned flags;
+
+    f = lval->e_flags;
+    flags = TypeOf (lval->e_tptr);
+    if (f & E_MGLOBAL) {
+       flags |= GlobalModeFlags (f);
+       if (lval->e_test) {
+           /* Just testing */
+                   flags |= CF_TEST;
+       }
+
+       /* Generate code */
+               g_putstatic (flags, lval->e_name, lval->e_const);
+
+    } else if (f & E_MLOCAL) {
+               g_putlocal (flags, lval->e_const);
+    } else if (f == E_MEOFFS) {
+       g_putind (flags, lval->e_const);
+    } else if (f != E_MREG) {
+       if (f & E_MEXPR) {
+           g_putind (flags, 0);
+       } else {
+           /* Store into absolute address */
+           g_putstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
+       }
+    }
+
+    /* Assume that each one of the stores will invalidate CC */
+    lval->e_test &= ~E_CC;
+}
+
+
+
+static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned long))
+/* Handle --i and ++i */
+{
+    int k;
+    unsigned flags;
+    unsigned long val;
+
+    gettok ();
+    if ((k = hie10 (lval)) == 0) {
+       Error (ERR_LVALUE_EXPECTED);
+       return;
+    }
+
+    /* Get the data type */
+    flags = TypeOf (lval->e_tptr) | CF_FORCECHAR | CF_CONST;
+
+    /* Get the increment value in bytes */
+    val = (lval->e_tptr [0] == T_PTR)? PSizeOf (lval->e_tptr) : 1;
+
+    /* We're currently only able to handle some adressing modes */
+    if ((lval->e_flags & E_MGLOBAL) == 0 &&    /* Global address? */
+       (lval->e_flags & E_MLOCAL) == 0  &&     /* Local address? */
+       (lval->e_flags & E_MCONST) == 0  &&     /* Constant address? */
+       (lval->e_flags & E_MEXPR) == 0) {       /* Address in a/x? */
+
+       /* Use generic code. Push the address if needed */
+       PushAddr (lval);
+
+       /* Fetch the value */
+       exprhs (CF_NONE, k, lval);
+
+       /* Increment value in primary */
+               inc (flags, val);
+
+       /* Store the result back */
+       store (lval);
+
+    } else {
+
+       /* Special code for some addressing modes - use the special += ops */
+       if (lval->e_flags & E_MGLOBAL) {
+           flags |= GlobalModeFlags (lval->e_flags);
+           if (inc == g_inc) {
+               g_addeqstatic (flags, lval->e_name, lval->e_const, val);
+           } else {
+               g_subeqstatic (flags, lval->e_name, lval->e_const, val);
+           }
+       } else if (lval->e_flags & E_MLOCAL) {
+           /* ref to localvar */
+           if (inc == g_inc) {
+               g_addeqlocal (flags, lval->e_const, val);
+           } else {
+               g_subeqlocal (flags, lval->e_const, val);
+           }
+       } else if (lval->e_flags & E_MCONST) {
+           /* ref to absolute address */
+           flags |= CF_ABSOLUTE;
+           if (inc == g_inc) {
+               g_addeqstatic (flags, lval->e_const, 0, val);
+           } else {
+               g_subeqstatic (flags, lval->e_const, 0, val);
+           }
+       } else if (lval->e_flags & E_MEXPR) {
+           /* Address in a/x. */
+           if (inc == g_inc) {
+               g_addeqind (flags, lval->e_const, val);
+           } else {
+               g_subeqind (flags, lval->e_const, val);
+           }
+       } else {
+           Internal ("Invalid addressing mode");
+       }
+
+    }
+
+    /* Result is an expression */
+    lval->e_flags = E_MEXPR;
+}
+
+
+
+static void post_incdec (struct expent *lval, int k, void (*inc) (unsigned, unsigned long))
+/* Handle i-- and i++ */
+{
+    unsigned flags;
+
+    gettok ();
+    if (k == 0) {
+       Error (ERR_LVALUE_EXPECTED);
+               return;
+    }
+
+    /* Get the data type */
+    flags = TypeOf (lval->e_tptr);
+
+    /* Push the address if needed */
+    PushAddr (lval);
+
+    /* Fetch the value and save it (since it's the result of the expression) */
+    exprhs (CF_NONE, 1, lval);
+    g_save (flags | CF_FORCECHAR);
+
+    /* If we have a pointer expression, increment by the size of the type */
+    if (lval->e_tptr[0] == T_PTR) {
+       inc (flags | CF_CONST | CF_FORCECHAR, SizeOf (lval->e_tptr + 1));
+    } else {
+       inc (flags | CF_CONST | CF_FORCECHAR, 1);
+    }
+
+    /* Store the result back */
+    store (lval);
+
+    /* Restore the original value */
+    g_restore (flags | CF_FORCECHAR);
+    lval->e_flags = E_MEXPR;
+}
+
+
+
+static void unaryop (int tok, struct expent* lval)
+/* Handle unary -/+ and ~ */
+{
+    int k;
+    unsigned flags;
+
+    gettok ();
+    k = hie10 (lval);
+    if (k == 0 && lval->e_flags & E_MCONST) {
+       /* Value is constant */
+       switch (tok) {
+           case MINUS: lval->e_const = -lval->e_const; break;
+           case PLUS:                                  break;
+           case COMP:  lval->e_const = ~lval->e_const; break;
+           default:    Internal ("Unexpected token: %d", tok);
+       }
+    } else {
+       /* Value is not constant */
+       exprhs (CF_NONE, k, lval);
+
+       /* Get the type of the expression */
+       flags = TypeOf (lval->e_tptr);
+
+       /* Handle the operation */
+       switch (tok) {
+                   case MINUS: g_neg (flags);  break;
+           case PLUS:                  break;
+           case COMP:  g_com (flags);  break;
+           default:    Internal ("Unexpected token: %d", tok);
+       }
+       lval->e_flags = E_MEXPR;
+    }
+}
+
+
+
+static int typecast (struct expent* lval)
+/* Handle an explicit cast */
+{
+    int k;
+    type Type[MAXTYPELEN];
+    unsigned rflags;
+
+    /* Skip the left paren */
+    gettok ();
+
+    /* Read the type */
+    ParseType (Type);
+
+    /* Closing paren */
+    ConsumeRParen ();
+
+    /* Read the expression we have to cast */
+    k = hie10 (lval);
+
+    /* Get the type of the expression and honor constant values */
+    rflags = TypeOf (lval->e_tptr);
+    if (lval->e_flags & E_MCONST) {
+       rflags |= CF_CONST;
+    }
+
+    /* Do the actual cast. Special handling for void casts */
+    if (!IsVoid (Type)) {
+       /* Mark the lhs as const to avoid a manipulation of TOS */
+        g_typecast (TypeOf (Type) | CF_CONST, rflags);
+    }
+
+    /* Use the new type */
+    lval->e_tptr = TypeDup (Type);
+
+    /* Done */
+    return k;
+}
+
+
+
+static int hie10 (struct expent* lval)
+/* Handle ++, --, !, unary - etc. */
+{
+    int k;
+    type* t;
+
+    switch (curtok) {
+
+       case INC:
+           pre_incdec (lval, g_inc);
+           return 0;
+
+       case DEC:
+           pre_incdec (lval, g_dec);
+           return 0;
+
+       case PLUS:
+       case MINUS:
+       case COMP:
+           unaryop (curtok, lval);
+           return 0;
+
+       case BANG:
+           gettok ();
+           if (evalexpr (CF_NONE, hie10, lval) == 0) {
+               /* Constant expression */
+               lval->e_const = !lval->e_const;
+           } else {
+               g_bneg (TypeOf (lval->e_tptr));
+               lval->e_test |= E_CC;                   /* bneg will set cc */
+               lval->e_flags = E_MEXPR;                /* say it's an expr */
+           }
+           return 0;                           /* expr not storable */
+
+       case STAR:
+           gettok ();
+           if (evalexpr (CF_NONE, hie10, lval) != 0) {
+               /* Expression is not const, indirect value loaded into primary */
+               lval->e_flags = E_MEXPR;
+               lval->e_const = 0;              /* Offset is zero now */
+           }
+           t = lval->e_tptr;
+                   if (IsPtr (t)) {
+                       lval->e_tptr = Indirect (t);
+           } else {
+               Error (ERR_ILLEGAL_INDIRECT);
+           }
+           return 1;
+
+       case AMP:
+           gettok ();
+           k = hie10 (lval);
+           if (k == 0) {
+               /* Allow the & operator with an array */
+               if (!IsArray (lval->e_tptr)) {
+                   Error (ERR_ILLEGAL_ADDRESS);
+               }
+           } else {
+               t = TypeAlloc (TypeLen (lval->e_tptr) + 2);
+               t [0] = T_PTR;
+               TypeCpy (t + 1, lval->e_tptr);
+               lval->e_tptr = t;
+           }
+           return 0;
+
+       case SIZEOF:
+           gettok ();
+                   if (istypeexpr ()) {
+               type Type[MAXTYPELEN];
+               gettok ();
+               lval->e_const = SizeOf (ParseType (Type));
+               ConsumeRParen ();
+           } else {
+               /* Remember the output queue pointer */
+               CodeMark Mark = GetCodePos ();
+               hie10 (lval);
+               lval->e_const = SizeOf (lval->e_tptr);
+               /* Remove any generated code */
+               RemoveCode (Mark);
+           }
+           lval->e_flags = E_MCONST | E_TCONST;
+           lval->e_tptr = type_uint;
+           lval->e_test &= ~E_CC;
+           return 0;
+
+       default:
+                   if (istypeexpr ()) {
+               /* A cast */
+               return typecast (lval);
+           }
+    }
+
+    k = hie11 (lval);
+    switch (curtok) {
+       case INC:
+                   post_incdec (lval, k, g_inc);
+           return 0;
+
+       case DEC:
+           post_incdec (lval, k, g_dec);
+           return 0;
+
+       default:
+           return k;
+    }
+}
+
+
+
+static int hie_internal (GenDesc** ops,                /* List of generators */
+                                struct expent* lval,   /* parent expr's lval */
+                                int (*hienext) (struct expent*),
+                        int* UsedGen)          /* next higher level */
+/* Helper function */
+{
+    int k;
+    struct expent lval2;
+    CodeMark Mark1;
+    CodeMark Mark2;
+    GenDesc* Gen;
+    int tok;                           /* The operator token */
+    unsigned ltype, type;
+    int rconst;                                /* Operand is a constant */
+
+
+    k = hienext (lval);
+
+    *UsedGen = 0;
+    while ((Gen = FindGen (curtok, ops)) != 0) {
+
+       /* Tell the caller that we handled it's ops */
+       *UsedGen = 1;
+
+       /* All operators that call this function expect an int on the lhs */
+       if (!IsInt (lval->e_tptr)) {
+           Error (ERR_INT_EXPR_EXPECTED);
+       }
+
+       /* Remember the operator token, then skip it */
+               tok = curtok;
+       gettok ();
+
+       /* Get the lhs on stack */
+               Mark1 = GetCodePos ();
+       ltype = TypeOf (lval->e_tptr);
+       if (k == 0 && lval->e_flags == E_MCONST) {
+           /* Constant value */
+           Mark2 = GetCodePos ();
+                   g_push (ltype | CF_CONST, lval->e_const);
+       } else {
+           /* Value not constant */
+           exprhs (CF_NONE, k, lval);
+           Mark2 = GetCodePos ();
+           g_push (ltype, 0);
+       }
+
+       /* Get the right hand side */
+       rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
+
+       /* Check the type of the rhs */
+       if (!IsInt (lval2.e_tptr)) {
+           Error (ERR_INT_EXPR_EXPECTED);
+       }
+
+       /* Check for const operands */
+       if (k == 0 && lval->e_flags == E_MCONST && rconst) {
+
+           /* Both operands are constant, remove the generated code */
+           RemoveCode (Mark1);
+           pop (ltype);
+
+           /* Evaluate the result */
+           lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
+
+           /* Get the type of the result */
+           lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
+
+       } else {
+
+           /* If the right hand side is constant, and the generator function
+            * expects the lhs in the primary, remove the push of the primary
+            * now.
+            */
+           unsigned rtype = TypeOf (lval2.e_tptr);
+           type = 0;
+           if (rconst) {
+               /* Second value is constant - check for div */
+               type |= CF_CONST;
+               rtype |= CF_CONST;
+               if (tok == DIV && lval2.e_const == 0) {
+                   Error (ERR_DIV_BY_ZERO);
+               } else if (tok == MOD && lval2.e_const == 0) {
+                   Error (ERR_MOD_BY_ZERO);
+               }
+               if ((Gen->Flags & GEN_NOPUSH) != 0) {
+                   RemoveCode (Mark2);
+                   pop (ltype);
+                   ltype |= CF_REG;    /* Value is in register */
+               }
+           }
+
+           /* Determine the type of the operation result. */
+                   type |= g_typeadjust (ltype, rtype);
+           lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
+
+           /* Generate code */
+           Gen->Func (type, lval2.e_const);
+           lval->e_flags = E_MEXPR;
+       }
+
+       /* We have a rvalue now */
+       k = 0;
+    }
+
+    return k;
+}
+
+
+
+static int hie_compare (GenDesc** ops,         /* List of generators */
+                               struct expent* lval,    /* parent expr's lval */
+                               int (*hienext) (struct expent*))
+/* Helper function for the compare operators */
+{
+    int k;
+    struct expent lval2;
+    CodeMark Mark1;
+    CodeMark Mark2;
+    GenDesc* Gen;
+    int tok;                                   /* The operator token */
+    unsigned ltype;
+    int rconst;                                /* Operand is a constant */
+
+
+    k = hienext (lval);
+
+    while ((Gen = FindGen (curtok, ops)) != 0) {
+
+       /* Remember the operator token, then skip it */
+               tok = curtok;
+       gettok ();
+
+       /* Get the lhs on stack */
+       Mark1 = GetCodePos ();
+       ltype = TypeOf (lval->e_tptr);
+       if (k == 0 && lval->e_flags == E_MCONST) {
+           /* Constant value */
+           Mark2 = GetCodePos ();
+                   g_push (ltype | CF_CONST, lval->e_const);
+       } else {
+           /* Value not constant */
+           exprhs (CF_NONE, k, lval);
+           Mark2 = GetCodePos ();
+           g_push (ltype, 0);
+       }
+
+       /* Get the right hand side */
+       rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
+
+       /* Make sure, the types are compatible */
+       if (IsInt (lval->e_tptr)) {
+           if (!IsInt (lval2.e_tptr) && !(IsPtr(lval2.e_tptr) && IsNullPtr(lval))) {
+               Error (ERR_INCOMPATIBLE_TYPES);
+           }
+       } else if (IsPtr (lval->e_tptr)) {
+           if (IsPtr (lval2.e_tptr)) {
+               /* Both pointers are allowed in comparison if they point to
+                * the same type, or if one of them is a void pointer.
+                */
+                       type* left  = Indirect (lval->e_tptr);
+               type* right = Indirect (lval2.e_tptr);
+               if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
+                   /* Incomatible pointers */
+                   Error (ERR_INCOMPATIBLE_TYPES);
+               }
+           } else if (!IsNullPtr (&lval2)) {
+               Error (ERR_INCOMPATIBLE_TYPES);
+           }
+       }
+
+       /* Check for const operands */
+       if (k == 0 && lval->e_flags == E_MCONST && rconst) {
+
+           /* Both operands are constant, remove the generated code */
+           RemoveCode (Mark1);
+           pop (ltype);
+
+           /* Evaluate the result */
+           lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
+
+       } else {
+
+           /* If the right hand side is constant, and the generator function
+            * expects the lhs in the primary, remove the push of the primary
+            * now.
+            */
+           unsigned flags = 0;
+           if (rconst) {
+               flags |= CF_CONST;
+               if ((Gen->Flags & GEN_NOPUSH) != 0) {
+                   RemoveCode (Mark2);
+                   pop (ltype);
+                   ltype |= CF_REG;    /* Value is in register */
+               }
+           }
+
+           /* Determine the type of the operation result. If the left
+            * operand is of type char and the right is a constant, or
+            * if both operands are of type char, we will encode the
+            * operation as char operation. Otherwise the default
+            * promotions are used.
+            */
+           if (IsChar (lval->e_tptr) && (IsChar (lval2.e_tptr) || rconst)) {
+               flags |= CF_CHAR;
+               if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) {
+                   flags |= CF_UNSIGNED;
+               }
+               if (rconst) {
+                   flags |= CF_FORCECHAR;
+               }
+           } else {
+               unsigned rtype = TypeOf (lval2.e_tptr) | (flags & CF_CONST);
+                       flags |= g_typeadjust (ltype, rtype);
+           }
+
+           /* Generate code */
+           Gen->Func (flags, lval2.e_const);
+           lval->e_flags = E_MEXPR;
+       }
+
+       /* Result type is always int */
+               lval->e_tptr = type_int;
+
+       /* We have a rvalue now, condition codes are set */
+       k = 0;
+       lval->e_test |= E_CC;
+    }
+
+    return k;
+}
+
+
+
+static int hie9 (struct expent *lval)
+/* Process * and / operators. */
+{
+    static GenDesc* hie9_ops [] = {
+       &GenMUL, &GenDIV, &GenMOD, 0
+    };
+    int UsedGen;
+
+    return hie_internal (hie9_ops, lval, hie10, &UsedGen);
+}
+
+
+
+static void parseadd (int k, struct expent* lval)
+/* Parse an expression with the binary plus operator. lval contains the
+ * unprocessed left hand side of the expression and will contain the
+ * result of the expression on return.
+ */
+{
+    struct expent lval2;
+    unsigned flags;            /* Operation flags */
+    CodeMark Mark;             /* Remember code position */
+    type* lhst;                        /* Type of left hand side */
+    type* rhst;                        /* Type of right hand side */
+
+
+    /* Skip the PLUS token */
+    gettok ();
+
+    /* Get the left hand side type, initialize operation flags */
+    lhst = lval->e_tptr;
+    flags = 0;
+
+    /* Check for constness on both sides */
+    if (k == 0 && lval->e_flags == E_MCONST) {
+
+       /* The left hand side is a constant. Good. Get rhs */
+               if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+                   /* Right hand side is also constant. Get the rhs type */
+           rhst = lval2.e_tptr;
+
+           /* Both expressions are constants. Check for pointer arithmetic */
+                   if (IsPtr (lhst) && IsInt (rhst)) {
+                       /* Left is pointer, right is int, must scale rhs */
+               lval->e_const = lval->e_const + lval2.e_const * PSizeOf (lhst);
+               /* Result type is a pointer */
+           } else if (IsInt (lhst) && IsPtr (rhst)) {
+               /* Left is int, right is pointer, must scale lhs */
+                       lval->e_const = lval->e_const * PSizeOf (rhst) + lval2.e_const;
+               /* Result type is a pointer */
+               lval->e_tptr = lval2.e_tptr;
+                   } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer addition */
+               lval->e_const += lval2.e_const;
+               typeadjust (lval, &lval2, 1);
+           } else {
+                       /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+           }
+
+                   /* Result is constant, condition codes not set */
+                   lval->e_test = E_MCONST;
+
+       } else {
+
+           /* lhs is constant, rhs is not. Get the rhs type. */
+           rhst = lval2.e_tptr;
+
+           /* Check for pointer arithmetic */
+           if (IsPtr (lhst) && IsInt (rhst)) {
+               /* Left is pointer, right is int, must scale rhs */
+               g_scale (CF_INT, PSizeOf (lhst));
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+           } else if (IsInt (lhst) && IsPtr (rhst)) {
+               /* Left is int, right is pointer, must scale lhs */
+                       lval->e_const *= PSizeOf (rhst);
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+               lval->e_tptr = lval2.e_tptr;
+                   } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer addition */
+                       flags = typeadjust (lval, &lval2, 1);
+           } else {
+                       /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+                   }
+
+           /* Generate code for the add */
+           g_inc (flags | CF_CONST, lval->e_const);
+
+           /* Result is in primary register */
+           lval->e_flags = E_MEXPR;
+           lval->e_test &= ~E_CC;
+
+               }
+
+    } else {
+
+       /* Left hand side is not constant. Get the value onto the stack. */
+       exprhs (CF_NONE, k, lval);              /* --> primary register */
+               Mark = GetCodePos ();
+       g_push (TypeOf (lval->e_tptr), 0);      /* --> stack */
+
+       /* Evaluate the rhs */
+               if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+                   /* Right hand side is a constant. Get the rhs type */
+           rhst = lval2.e_tptr;
+
+           /* Remove pushed value from stack */
+           RemoveCode (Mark);
+           pop (TypeOf (lval->e_tptr));
+
+                   /* Check for pointer arithmetic */
+                   if (IsPtr (lhst) && IsInt (rhst)) {
+               /* Left is pointer, right is int, must scale rhs */
+               lval2.e_const *= PSizeOf (lhst);
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+           } else if (IsInt (lhst) && IsPtr (rhst)) {
+               /* Left is int, right is pointer, must scale lhs (ptr only) */
+                       g_scale (CF_INT | CF_CONST, PSizeOf (rhst));
+                       /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+               lval->e_tptr = lval2.e_tptr;
+                   } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer addition */
+               flags = typeadjust (lval, &lval2, 1);
+                   } else {
+                       /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+           }
+
+           /* Generate code for the add */
+                   g_inc (flags | CF_CONST, lval2.e_const);
+
+           /* Result is in primary register */
+           lval->e_flags = E_MEXPR;
+           lval->e_test &= ~E_CC;
+
+       } else {
+
+           /* lhs and rhs are not constant. Get the rhs type. */
+           rhst = lval2.e_tptr;
+
+           /* Check for pointer arithmetic */
+           if (IsPtr (lhst) && IsInt (rhst)) {
+               /* Left is pointer, right is int, must scale rhs */
+               g_scale (CF_INT, PSizeOf (lhst));
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+           } else if (IsInt (lhst) && IsPtr (rhst)) {
+               /* Left is int, right is pointer, must scale lhs */
+               g_tosint (TypeOf (rhst));       /* Make sure, TOS is int */
+               g_swap (CF_INT);                /* Swap TOS and primary */
+               g_scale (CF_INT, PSizeOf (rhst));
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+               lval->e_tptr = lval2.e_tptr;
+                   } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer addition */
+                       flags = typeadjust (lval, &lval2, 0);
+           } else {
+                       /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+           }
+
+           /* Generate code for the add */
+                   g_add (flags, 0);
+
+           /* Result is in primary register */
+                   lval->e_flags = E_MEXPR;
+           lval->e_test &= ~E_CC;
+
+               }
+
+    }
+}
+
+
+
+static void parsesub (int k, struct expent* lval)
+/* Parse an expression with the binary minus operator. lval contains the
+ * unprocessed left hand side of the expression and will contain the
+ * result of the expression on return.
+ */
+{
+    struct expent lval2;
+    unsigned flags;            /* Operation flags */
+    type* lhst;                        /* Type of left hand side */
+    type* rhst;                        /* Type of right hand side */
+    CodeMark Mark1;            /* Save position of output queue */
+    CodeMark Mark2;            /* Another position in the queue */
+    int rscale;                /* Scale factor for the result */
+
+
+    /* Skip the MINUS token */
+    gettok ();
+
+    /* Get the left hand side type, initialize operation flags */
+    lhst = lval->e_tptr;
+    flags = 0;
+    rscale = 1;                        /* Scale by 1, that is, don't scale */
+
+    /* Remember the output queue position, then bring the value onto the stack */
+    Mark1 = GetCodePos ();
+    exprhs (CF_NONE, k, lval);         /* --> primary register */
+    Mark2 = GetCodePos ();
+    g_push (TypeOf (lhst), 0); /* --> stack */
+
+    /* Parse the right hand side */
+    if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+       /* The right hand side is constant. Get the rhs type. */
+               rhst = lval2.e_tptr;
+
+       /* Check left hand side */
+       if (k == 0 && lval->e_flags & E_MCONST) {
+
+           /* Both sides are constant, remove generated code */
+           RemoveCode (Mark1);
+           pop (TypeOf (lhst));        /* Clean up the stack */
+
+           /* Check for pointer arithmetic */
+           if (IsPtr (lhst) && IsInt (rhst)) {
+               /* Left is pointer, right is int, must scale rhs */
+               lval->e_const -= lval2.e_const * PSizeOf (lhst);
+               /* Operate on pointers, result type is a pointer */
+           } else if (IsPtr (lhst) && IsPtr (rhst)) {
+               /* Left is pointer, right is pointer, must scale result */
+               if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+                   Error (ERR_INCOMPATIBLE_POINTERS);
+               } else {
+                   lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst);
+               }
+               /* Operate on pointers, result type is an integer */
+               lval->e_tptr = type_int;
+           } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer subtraction */
+                       typeadjust (lval, &lval2, 1);
+               lval->e_const -= lval2.e_const;
+           } else {
+               /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+           }
+
+           /* Result is constant, condition codes not set */
+           lval->e_flags = E_MCONST;
+           lval->e_test &= ~E_CC;
+
+       } else {
+
+           /* Left hand side is not constant, right hand side is.
+            * Remove pushed value from stack.
+            */
+           RemoveCode (Mark2);
+           pop (TypeOf (lhst));
+
+           if (IsPtr (lhst) && IsInt (rhst)) {
+               /* Left is pointer, right is int, must scale rhs */
+                       lval2.e_const *= PSizeOf (lhst);
+               /* Operate on pointers, result type is a pointer */
+               flags = CF_PTR;
+           } else if (IsPtr (lhst) && IsPtr (rhst)) {
+               /* Left is pointer, right is pointer, must scale result */
+               if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+                   Error (ERR_INCOMPATIBLE_POINTERS);
+               } else {
+                   rscale = PSizeOf (lhst);
+               }
+               /* Operate on pointers, result type is an integer */
+               flags = CF_PTR;
+               lval->e_tptr = type_int;
+           } else if (IsInt (lhst) && IsInt (rhst)) {
+               /* Integer subtraction */
+                       flags = typeadjust (lval, &lval2, 1);
+           } else {
+               /* OOPS */
+               Error (ERR_OP_NOT_ALLOWED);
+           }
+
+           /* Do the subtraction */
+           g_dec (flags | CF_CONST, lval2.e_const);
+
+           /* If this was a pointer subtraction, we must scale the result */
+           if (rscale != 1) {
+               g_scale (flags, -rscale);
+           }
+
+           /* Result is in primary register */
+           lval->e_flags = E_MEXPR;
+           lval->e_test &= ~E_CC;
+
+       }
+
+    } else {
+
+       /* Right hand side is not constant. Get the rhs type. */
+       rhst = lval2.e_tptr;
+
+               /* Check for pointer arithmetic */
+       if (IsPtr (lhst) && IsInt (rhst)) {
+           /* Left is pointer, right is int, must scale rhs */
+           g_scale (CF_INT, PSizeOf (lhst));
+           /* Operate on pointers, result type is a pointer */
+           flags = CF_PTR;
+       } else if (IsPtr (lhst) && IsPtr (rhst)) {
+           /* Left is pointer, right is pointer, must scale result */
+           if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+               Error (ERR_INCOMPATIBLE_POINTERS);
+           } else {
+               rscale = PSizeOf (lhst);
+           }
+           /* Operate on pointers, result type is an integer */
+           flags = CF_PTR;
+           lval->e_tptr = type_int;
+       } else if (IsInt (lhst) && IsInt (rhst)) {
+           /* Integer subtraction. If the left hand side descriptor says that
+            * the lhs is const, we have to remove this mark, since this is no
+            * longer true, lhs is on stack instead.
+            */
+           if (lval->e_flags == E_MCONST) {
+               lval->e_flags = E_MEXPR;
+           }
+           /* Adjust operand types */
+           flags = typeadjust (lval, &lval2, 0);
+       } else {
+           /* OOPS */
+           Error (ERR_OP_NOT_ALLOWED);
+       }
+
+       /* Generate code for the sub (the & is a hack here) */
+       g_sub (flags & ~CF_CONST, 0);
+
+       /* If this was a pointer subtraction, we must scale the result */
+       if (rscale != 1) {
+           g_scale (flags, -rscale);
+       }
+
+       /* Result is in primary register */
+       lval->e_flags = E_MEXPR;
+       lval->e_test &= ~E_CC;
+    }
+}
+
+
+
+static int hie8 (struct expent* lval)
+/* Process + and - binary operators. */
+{
+    int k = hie9 (lval);
+    while (curtok == PLUS || curtok == MINUS) {
+
+               if (curtok == PLUS) {
+                   parseadd (k, lval);
+               } else {
+                   parsesub (k, lval);
+               }
+               k = 0;
+    }
+    return k;
+}
+
+
+
+
+static int hie7 (struct expent *lval)
+/* Parse << and >>. */
+{
+    static GenDesc* hie7_ops [] = {
+               &GenASL, &GenASR, 0
+    };
+    int UsedGen;
+
+    return hie_internal (hie7_ops, lval, hie8, &UsedGen);
+}
+
+
+
+static int hie6 (struct expent *lval)
+/* process greater-than type comparators */
+{
+    static GenDesc* hie6_ops [] = {
+       &GenLT, &GenLE, &GenGE, &GenGT, 0
+    };
+    return hie_compare (hie6_ops, lval, hie7);
+}
+
+
+
+static int hie5 (struct expent *lval)
+{
+    static GenDesc* hie5_ops[] = {
+               &GenEQ, &GenNE, 0
+    };
+    return hie_compare (hie5_ops, lval, hie6);
+}
+
+
+
+static int hie4 (struct expent* lval)
+/* Handle & (bitwise and) */
+{
+    static GenDesc* hie4_ops [] = {
+               &GenAND, 0
+    };
+    int UsedGen;
+
+    return hie_internal (hie4_ops, lval, hie5, &UsedGen);
+}
+
+
+
+static int hie3 (struct expent *lval)
+/* Handle ^ (bitwise exclusive or) */
+{
+    static GenDesc* hie3_ops [] = {
+               &GenXOR, 0
+    };
+    int UsedGen;
+
+    return hie_internal (hie3_ops, lval, hie4, &UsedGen);
+}
+
+
+
+static int hie2 (struct expent *lval)
+/* Handle | (bitwise or) */
+{
+    static GenDesc* hie2_ops [] = {
+               &GenOR, 0
+    };
+    int UsedGen;
+
+    return hie_internal (hie2_ops, lval, hie3, &UsedGen);
+}
+
+
+
+static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp)
+/* Process "exp && exp" */
+{
+    int k;
+    int lab;
+    struct expent lval2;
+
+    k = hie2 (lval);
+    if (curtok == DAMP) {
+
+               /* Tell our caller that we're evaluating a boolean */
+               *BoolOp = 1;
+
+               /* Get a label that we will use for false expressions */
+               lab = GetLabel ();
+
+               /* If the expr hasn't set condition codes, set the force-test flag */
+               if ((lval->e_test & E_CC) == 0) {
+                   lval->e_test |= E_FORCETEST;
+               }
+
+               /* Load the value */
+               exprhs (CF_FORCECHAR, k, lval);
+
+               /* Generate the jump */
+               g_falsejump (CF_NONE, lab);
+
+               /* Parse more boolean and's */
+               while (curtok == DAMP) {
+
+                   /* Skip the && */
+           gettok ();
+
+           /* Get rhs */
+           k = hie2 (&lval2);
+           if ((lval2.e_test & E_CC) == 0) {
+               lval2.e_test |= E_FORCETEST;
+           }
+           exprhs (CF_FORCECHAR, k, &lval2);
+
+                   /* Do short circuit evaluation */
+           if (curtok == DAMP) {
+               g_falsejump (CF_NONE, lab);
+                   } else {
+                       /* Last expression - will evaluate to true */
+                       g_truejump (CF_NONE, TrueLab);
+                   }
+               }
+
+               /* Define the false jump label here */
+               g_defloclabel (lab);
+
+               /* Define the label */
+               lval->e_flags = E_MEXPR;
+               lval->e_test |= E_CC;   /* Condition codes are set */
+               k = 0;
+    }
+    return k;
+}
+
+
+
+static int hieOr (struct expent *lval)
+/* Process "exp || exp". */
+{
+    int k;
+    struct expent lval2;
+    int BoolOp = 0;            /* Did we have a boolean op? */
+    int AndOp;                 /* Did we have a && operation? */
+    unsigned TrueLab;          /* Jump to this label if true */
+    unsigned DoneLab;
+
+    /* Get a label */
+    TrueLab = GetLabel ();
+
+    /* Call the next level parser */
+    k = hieAnd (lval, TrueLab, &BoolOp);
+
+    /* Any boolean or's? */
+    if (curtok == DBAR) {
+
+       /* If the expr hasn't set condition codes, set the force-test flag */
+               if ((lval->e_test & E_CC) == 0) {
+           lval->e_test |= E_FORCETEST;
+       }
+
+       /* Get first expr */
+       exprhs (CF_FORCECHAR, k, lval);
+
+               /* For each expression jump to TrueLab if true. Beware: If we
+        * had && operators, the jump is already in place!
+        */
+       if (!BoolOp) {
+                   g_truejump (CF_NONE, TrueLab);
+       }
+
+               /* Remember that we had a boolean op */
+       BoolOp = 1;
+
+       /* while there's more expr */
+               while (curtok == DBAR) {
+
+                   /* skip the || */
+           gettok ();
+
+                   /* Get a subexpr */
+           AndOp = 0;
+           k = hieAnd (&lval2, TrueLab, &AndOp);
+                   if ((lval2.e_test & E_CC) == 0) {
+               lval2.e_test |= E_FORCETEST;
+           }
+           exprhs (CF_FORCECHAR, k, &lval2);
+
+                   /* If there is more to come, add shortcut boolean eval.
+            * Beware: If we had && operators, the jump is already
+            * in place!
+            */
+#if    0
+/* Seems this sometimes generates wrong code */
+           if (curtok == DBAR && !AndOp) {
+               g_truejump (CF_NONE, TrueLab);
+                   }
+#else
+           g_truejump (CF_NONE, TrueLab);
+#endif
+       }
+       lval->e_flags = E_MEXPR;
+       lval->e_test |= E_CC;                   /* Condition codes are set */
+       k = 0;
+    }
+
+    /* If we really had boolean ops, generate the end sequence */
+    if (BoolOp) {
+       DoneLab = GetLabel ();
+       g_getimmed (CF_INT | CF_CONST, 0, 0);   /* Load FALSE */
+               g_falsejump (CF_NONE, DoneLab);
+       g_defloclabel (TrueLab);
+       g_getimmed (CF_INT | CF_CONST, 1, 0);   /* Load TRUE */
+       g_defloclabel (DoneLab);
+    }
+    return k;
+}
+
+
+
+static int hieQuest (struct expent *lval)
+/* Parse "lvalue ? exp : exp" */
+{
+    int k;
+    int labf;
+    int labt;
+    struct expent lval2;               /* Expression 2 */
+    struct expent lval3;               /* Expression 3 */
+    type* type2;               /* Type of expression 2 */
+    type* type3;               /* Type of expression 3 */
+    type* rtype;               /* Type of result */
+    CodeMark Mark1;            /* Save position in output code */
+    CodeMark Mark2;            /* Save position in output code */
+
+
+
+    k = hieOr (lval);
+    if (curtok == QUEST) {
+       gettok ();
+       if ((lval->e_test & E_CC) == 0) {
+           /* Condition codes not set, force a test */
+           lval->e_test |= E_FORCETEST;
+       }
+       exprhs (CF_NONE, k, lval);
+       labf = GetLabel ();
+       g_falsejump (CF_NONE, labf);
+
+       /* Parse second and third expression */
+       expression1 (&lval2);
+       labt = GetLabel ();
+       ConsumeColon ();
+       g_jump (labt);
+       g_defloclabel (labf);
+       expression1 (&lval3);
+
+       /* Check if any conversions are needed, if so, do them.
+        * Conversion rules for ?: expression are:
+        *   - if both expressions are int expressions, default promotion
+        *     rules for ints apply.
+        *   - if both expressions are pointers of the same type, the
+        *     result of the expression is of this type.
+        *   - if one of the expressions is a pointer and the other is
+        *     a zero constant, the resulting type is that of the pointer
+        *     type.
+        *   - all other cases are flagged by an error.
+        */
+       type2 = lval2.e_tptr;
+       type3 = lval3.e_tptr;
+       if (IsInt (type2) && IsInt (type3)) {
+
+           /* Get common type */
+           rtype = promoteint (type2, type3);
+
+           /* Convert the third expression to this type if needed */
+           g_typecast (TypeOf (rtype), TypeOf (type3));
+
+           /* Setup a new label so that the expr3 code will jump around
+            * the type cast code for expr2.
+            */
+                   labf = GetLabel ();         /* Get new label */
+           Mark1 = GetCodePos ();      /* Remember current position */
+           g_jump (labf);              /* Jump around code */
+
+           /* The jump for expr2 goes here */
+           g_defloclabel (labt);
+
+           /* Create the typecast code for expr2 */
+           Mark2 = GetCodePos ();      /* Remember position */
+           g_typecast (TypeOf (rtype), TypeOf (type2));
+
+           /* If the typecast did not produce code, remove the jump,
+            * otherwise output the label.
+            */
+           if (GetCodePos() == Mark2) {
+               RemoveCode (Mark1);     /* Remove code */
+           } else {
+               /* We have typecast code, output label */
+               g_defloclabel (labf);
+               labt = 0;               /* Mark other label as invalid */
+           }
+
+       } else if (IsPtr (type2) && IsPtr (type3)) {
+           /* Must point to same type */
+           if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) {
+               Error (ERR_INCOMPATIBLE_TYPES);
+           }
+           /* Result has the common type */
+           rtype = lval2.e_tptr;
+       } else if (IsPtr (type2) && IsNullPtr (&lval3)) {
+           /* Result type is pointer, no cast needed */
+           rtype = lval2.e_tptr;
+       } else if (IsNullPtr (&lval2) && IsPtr (type3)) {
+           /* Result type is pointer, no cast needed */
+           rtype = lval3.e_tptr;
+       } else {
+           Error (ERR_INCOMPATIBLE_TYPES);
+           rtype = lval2.e_tptr;               /* Doesn't matter here */
+       }
+
+       /* If we don't have the label defined until now, do it */
+       if (labt) {
+           g_defloclabel (labt);
+       }
+
+       /* Setup the target expression */
+               lval->e_flags = E_MEXPR;
+       lval->e_tptr = rtype;
+       k = 0;
+    }
+    return k;
+}
+
+
+
+static void opeq (GenDesc* Gen, struct expent *lval, int k)
+/* Process "op=" operators. */
+{
+    struct expent lval2;
+    unsigned flags;
+    CodeMark Mark;
+    int MustScale;
+
+    gettok ();
+    if (k == 0) {
+       Error (ERR_LVALUE_EXPECTED);
+       return;
+    }
+
+    /* Determine the type of the lhs */
+    flags = TypeOf (lval->e_tptr);
+    MustScale = (Gen->Func == g_add || Gen->Func == g_sub) &&
+               lval->e_tptr [0] == T_PTR;
+
+    /* Get the lhs address on stack (if needed) */
+    PushAddr (lval);
+
+    /* Fetch the lhs into the primary register if needed */
+    exprhs (CF_NONE, k, lval);
+
+    /* Bring the lhs on stack */
+    Mark = GetCodePos ();
+    g_push (flags, 0);
+
+    /* Evaluate the rhs */
+    if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
+       /* The resulting value is a constant. If the generator has the NOPUSH
+        * flag set, don't push the lhs.
+        */
+       if (Gen->Flags & GEN_NOPUSH) {
+           RemoveCode (Mark);
+           pop (flags);
+       }
+               if (MustScale) {
+           /* lhs is a pointer, scale rhs */
+           lval2.e_const *= SizeOf (lval->e_tptr+1);
+       }
+
+       /* If the lhs is character sized, the operation may be later done
+        * with characters.
+        */
+       if (SizeOf (lval->e_tptr) == 1) {
+           flags |= CF_FORCECHAR;
+       }
+
+       /* Special handling for add and sub - some sort of a hack, but short code */
+       if (Gen->Func == g_add) {
+           g_inc (flags | CF_CONST, lval2.e_const);
+       } else if (Gen->Func == g_sub) {
+           g_dec (flags | CF_CONST, lval2.e_const);
+       } else {
+                   Gen->Func (flags | CF_CONST, lval2.e_const);
+       }
+    } else {
+       /* rhs is not constant and already in the primary register */
+               if (MustScale) {
+           /* lhs is a pointer, scale rhs */
+                   g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
+       }
+
+       /* If the lhs is character sized, the operation may be later done
+        * with characters.
+        */
+       if (SizeOf (lval->e_tptr) == 1) {
+           flags |= CF_FORCECHAR;
+       }
+
+       /* Adjust the types of the operands if needed */
+               Gen->Func (g_typeadjust (flags, TypeOf (lval2.e_tptr)), 0);
+    }
+    store (lval);
+    lval->e_flags = E_MEXPR;
+}
+
+
+
+static void addsubeq (GenDesc* Gen, struct expent *lval, int k)
+/* Process the += and -= operators */
+{
+    struct expent lval2;
+    unsigned flags;
+    int MustScale;
+
+
+    if (k == 0) {
+       Error (ERR_LVALUE_EXPECTED);
+       return;
+    }
+
+
+    /* We're currently only able to handle some adressing modes */
+    if ((lval->e_flags & E_MGLOBAL) == 0 &&    /* Global address? */
+       (lval->e_flags & E_MLOCAL) == 0  &&     /* Local address? */
+               (lval->e_flags & E_MCONST) == 0) {      /* Constant address? */
+       /* Use generic routine */
+               opeq (Gen, lval, k);
+       return;
+    }
+
+    /* Skip the operator */
+    gettok ();
+
+    /* Check if we have a pointer expression and must scale rhs */
+    MustScale = (lval->e_tptr [0] == T_PTR);
+
+    /* Determine the code generator flags */
+    flags = TypeOf (lval->e_tptr) | CF_FORCECHAR;
+
+    /* Evaluate the rhs */
+    if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
+       /* The resulting value is a constant. */
+               if (MustScale) {
+           /* lhs is a pointer, scale rhs */
+           lval2.e_const *= SizeOf (lval->e_tptr+1);
+       }
+       flags |= CF_CONST;
+    } else {
+       /* rhs is not constant and already in the primary register */
+               if (MustScale) {
+           /* lhs is a pointer, scale rhs */
+                   g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
+       }
+    }
+
+    /* If the lhs is character sized, the operation may be later done
+     * with characters.
+     */
+    if (SizeOf (lval->e_tptr) == 1) {
+       flags |= CF_FORCECHAR;
+    }
+
+    /* Output apropriate code */
+    if (lval->e_flags & E_MGLOBAL) {
+       /* Static variable */
+       flags |= GlobalModeFlags (lval->e_flags);
+       if (Gen->Tok == PASGN) {
+           g_addeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
+       } else {
+                   g_subeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
+       }
+    } else if (lval->e_flags & E_MLOCAL) {
+       /* ref to localvar */
+       if (Gen->Tok == PASGN) {
+           g_addeqlocal (flags, lval->e_const, lval2.e_const);
+       } else {
+           g_subeqlocal (flags, lval->e_const, lval2.e_const);
+       }
+    } else if (lval->e_flags & E_MCONST) {
+       /* ref to absolute address */
+       flags |= CF_ABSOLUTE;
+       if (Gen->Tok == PASGN) {
+           g_addeqstatic (flags, lval->e_const, 0, lval2.e_const);
+       } else {
+                   g_subeqstatic (flags, lval->e_const, 0, lval2.e_const);
+       }
+    } else if (lval->e_flags & E_MEXPR) {
+               /* Address in a/x. */
+       if (Gen->Tok == PASGN) {
+                   g_addeqind (flags, lval->e_const, lval2.e_const);
+       } else {
+                   g_subeqind (flags, lval->e_const, lval2.e_const);
+       }
+    } else {
+               Internal ("Invalid addressing mode");
+    }
+
+    /* Expression is in the primary now */
+    lval->e_flags = E_MEXPR;
+}
+
+
+
+static void Assignment (struct expent* lval)
+/* Parse an assignment */
+{
+    int k;
+    struct expent lval2;
+    unsigned flags;
+    type* ltype = lval->e_tptr;
+
+    /* cc65 does not have full support for handling structs by value. Since
+     * assigning structs is one of the more useful operations from this
+     * familiy, allow it here.
+     */
+    if (IsStruct (ltype)) {
+
+               /* Bring the address of the lhs into the primary and push it */
+       exprhs (0, 0, lval);
+       g_push (CF_PTR | CF_UNSIGNED, 0);
+
+       /* Get the expression on the right of the '=' into the primary */
+       k = hie1 (&lval2);
+       if (k) {
+           /* Get the address */
+           exprhs (0, 0, &lval2);
+       } else {
+           /* We need an lvalue */
+           Error (ERR_LVALUE_EXPECTED);
+       }
+
+       /* Push the address (or whatever is in ax in case of errors) */
+       g_push (CF_PTR | CF_UNSIGNED, 0);
+
+       /* Check for equality of the structs */
+       if (!EqualTypes (ltype, lval2.e_tptr)) {
+           Error (ERR_INCOMPATIBLE_TYPES);
+       }
+
+       /* Load the size of the struct into the primary */
+       g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, SizeOf (ltype), 0);
+
+       /* Call the memcpy function */
+       g_call (CF_FIXARGC, "memcpy", 4);
+
+    } else {
+
+       /* Get the address on stack if needed */
+       PushAddr (lval);
+
+       /* No struct, setup flags for the load */
+       flags = SizeOf (ltype) == 1? CF_FORCECHAR : CF_NONE;
+
+       /* Get the expression on the right of the '=' into the primary */
+       if (evalexpr (flags, hie1, &lval2) == 0) {
+           /* Constant expression. Adjust the types */
+           assignadjust (ltype, &lval2);
+           /* Put the value into the primary register */
+           lconst (flags, &lval2);
+       } else {
+           /* Expression is not constant and already in the primary */
+           assignadjust (ltype, &lval2);
+       }
+
+       /* Generate a store instruction */
+       store (lval);
+
+    }
+
+    /* Value is still in primary */
+    lval->e_flags = E_MEXPR;
+}
+
+
+
+int hie1 (struct expent* lval)
+/* Parse first level of expression hierarchy. */
+{
+    int k;
+
+    k = hieQuest (lval);
+    switch (curtok) {
+
+       case RPAREN:
+       case SEMI:
+           return k;
+
+       case ASGN:
+           gettok ();
+           if (k == 0) {
+               Error (ERR_LVALUE_EXPECTED);
+           } else {
+               Assignment (lval);
+           }
+           break;
+
+       case PASGN:
+                   addsubeq (&GenPASGN, lval, k);
+           break;
+
+       case SASGN:
+                   addsubeq (&GenSASGN, lval, k);
+           break;
+
+       case MASGN:
+                   opeq (&GenMASGN, lval, k);
+           break;
+
+       case DASGN:
+                   opeq (&GenDASGN, lval, k);
+           break;
+
+       case MOASGN:
+                   opeq (&GenMOASGN, lval, k);
+           break;
+
+       case SLASGN:
+                   opeq (&GenSLASGN, lval, k);
+           break;
+
+       case SRASGN:
+                   opeq (&GenSRASGN, lval, k);
+           break;
+
+       case AASGN:
+                   opeq (&GenAASGN, lval, k);
+           break;
+
+       case XOASGN:
+                   opeq (&GenXOASGN, lval, k);
+           break;
+
+       case OASGN:
+                   opeq (&GenOASGN, lval, k);
+           break;
+
+       default:
+           return k;
+    }
+    return 0;
+}
+
+
+
+int hie0 (struct expent *lval)
+/* Parse comma operator. */
+{
+    int k;
+
+    k = hie1 (lval);
+    while (curtok == COMMA) {
+       gettok ();
+       k = hie1 (lval);
+    }
+    return k;
+}
+
+
+
+int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval)
+/* Will evaluate an expression via the given function. If the result is a
+ * constant, 0 is returned and the value is put in the lval struct. If the
+ * result is not constant, exprhs is called to bring the value into the
+ * primary register and 1 is returned.
+ */
+{
+    int k;
+
+    /* Evaluate */
+    k = f (lval);
+    if (k == 0 && lval->e_flags == E_MCONST) {
+       /* Constant expression */
+       return 0;
+    } else {
+       /* Not constant, load into the primary */
+        exprhs (flags, k, lval);
+       return 1;
+    }
+}
+
+
+
+int expr (int (*func) (), struct expent *lval)
+/* Expression parser; func is either hie0 or hie1. */
+{
+    int k;
+    int savsp;
+
+    savsp = oursp;
+
+    k = (*func) (lval);
+
+    /* Do some checks if code generation is still constistent */
+    if (savsp != oursp) {
+       if (Debug) {
+           fprintf (stderr, "oursp != savesp (%d != %d)\n", oursp, savsp);
+       } else {
+           Internal ("oursp != savsp (%d != %d)", oursp, savsp);
+       }
+    }
+    return k;
+}
+
+
+
+void expression1 (struct expent* lval)
+/* Evaluate an expression on level 1 (no comma operator) and put it into
+ * the primary register
+ */
+{
+    memset (lval, 0, sizeof (*lval));
+    exprhs (CF_NONE, expr (hie1, lval), lval);
+}
+
+
+
+void expression (struct expent* lval)
+/* Evaluate an expression and put it into the primary register */
+{
+    memset (lval, 0, sizeof (*lval));
+    exprhs (CF_NONE, expr (hie0, lval), lval);
+}
+
+
+
+void constexpr (struct expent* lval)
+/* Get a constant value */
+{
+    memset (lval, 0, sizeof (*lval));
+    if (expr (hie1, lval) != 0 || (lval->e_flags & E_MCONST) == 0) {
+       Error (ERR_CONST_EXPR_EXPECTED);
+       /* To avoid any compiler errors, make the expression a valid const */
+       lval->e_flags = E_MCONST;
+       lval->e_tptr = type_int;
+       lval->e_const = 0;
+    }
+}
+
+
+
+void intexpr (struct expent* lval)
+/* Get an integer expression */
+{
+    expression (lval);
+    if (!IsInt (lval->e_tptr)) {
+       Error (ERR_INT_EXPR_EXPECTED);
+       /* To avoid any compiler errors, make the expression a valid int */
+       lval->e_flags = E_MCONST;
+       lval->e_tptr = type_int;
+       lval->e_const = 0;
+    }
+}
+
+
+
+void boolexpr (struct expent* lval)
+/* Get a boolean expression */
+{
+    /* Read an expression */
+    expression (lval);
+
+    /* If it's an integer, it's ok. If it's not an integer, but a pointer,
+     * the pointer used in a boolean context is also ok (Ootherwise check if it's a pointer
+     * expression.
+     */
+    if (!IsInt (lval->e_tptr) && !IsPtr (lval->e_tptr)) {
+       Error (ERR_INT_EXPR_EXPECTED);
+       /* To avoid any compiler errors, make the expression a valid int */
+       lval->e_flags = E_MCONST;
+       lval->e_tptr = type_int;
+       lval->e_const = 0;
+    }
+}
+
+
+
+void test (unsigned label, int cond)
+/* Generate code to perform test and jump if false. */
+{
+    int k;
+    struct expent lval;
+
+    /* Eat the parenthesis */
+    ConsumeLParen ();
+
+    /* Prepare the expression, setup labels */
+    memset (&lval, 0, sizeof (lval));
+    lval.e_test = E_TEST;
+
+    /* Generate code to eval the expr */
+    k = expr (hie0, &lval);
+    if (k == 0 && lval.e_flags == E_MCONST) {
+       /* Constant rvalue */
+               if (cond == 0 && lval.e_const == 0) {
+           g_jump (label);
+           Warning (WARN_UNREACHABLE_CODE);
+       } else if (cond && lval.e_const) {
+           g_jump (label);
+       }
+       ConsumeRParen ();
+       return;
+    }
+
+    /* If the expr hasn't set condition codes, set the force-test flag */
+    if ((lval.e_test & E_CC) == 0) {
+       lval.e_test |= E_FORCETEST;
+    }
+
+    /* Load the value into the primary register */
+    exprhs (CF_FORCECHAR, k, &lval);
+
+    /* Check for the closing brace */
+    ConsumeRParen ();
+
+    /* Generate the jump */
+    if (cond) {
+       g_truejump (CF_NONE, label);
+    } else {
+       /* Special case (putting this here is a small hack - but hey, the
+        * compiler itself is one big hack...): If a semicolon follows, we
+        * don't have a statement and may omit the jump.
+        */
+       if (curtok != SEMI) {
+            g_falsejump (CF_NONE, label);
+       }
+    }
+}
+
+
+
+
diff --git a/src/cc65/expr.h b/src/cc65/expr.h
new file mode 100644 (file)
index 0000000..7768d35
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * expr.h
+ *
+ * Ullrich von Bassewitz, 21.06.1998
+ */
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "datatype.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Defines for the flags field of the expression descriptor */
+#define E_MREG         0x0110  /* Special: Expression is primary register */
+#define E_MGLOBAL              0x0080  /* Reference to static variable */
+#define E_MLOCAL       0x0040  /* Reference to local variable (stack offset) */
+#define E_MCONST       0x0020  /* Constant value */
+#define E_MEXPR                0x0010  /* Result is in primary register */
+#define E_MEOFFS       0x0011  /* Offset is in primary register, base on stack */
+
+#define E_MCTYPE       0x0007  /* Type of a constant */
+#define E_TCONST       0x0000  /* Constant */
+#define E_TGLAB                0x0001  /* Global label */
+#define E_TLIT         0x0002  /* Literal of some kind */
+#define E_TLOFFS       0x0003  /* Constant stack offset */
+#define E_TLLAB                0x0004  /* Local label */
+#define E_TREGISTER    0x0005  /* Register variable */
+
+/* Defines for the test field of the expression descriptor */
+#define E_CC           0x0001  /* expr has set cond codes apropos result value */
+#define E_FORCETEST            0x0002  /* if expr has NOT set CC, force a test */
+#define E_LOGL         0x0004  /* expr has left a logical value (1 or 0) in AX */
+#define E_XINV         0x0008  /* flip this bit to invert sense of test */
+#define E_TEST         0x0010  /* We're evaluating a test */
+
+/* Describe the result of an expression */
+struct expent {
+    struct SymEntry*   Sym;     /* Symbol table entry if known */
+    type*              e_tptr;  /* Type array of expression */
+    long               e_const; /* Value if expression constant */
+    unsigned           e_flags;
+    unsigned           e_test;  /* */
+    unsigned long      e_name;  /* Name or label number */
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void doasm (void);
+/* This function parses ASM statements. The syntax of the ASM directive
+ * looks like the one defined for C++ (C has no ASM directive), that is,
+ * a string literal in parenthesis.
+ */
+
+unsigned assignadjust (type* lhst, struct expent* rhs);
+/* Adjust the type of the right hand expression so that it can be assigned to
+ * the type on the left hand side. This function is used for assignment and
+ * for converting parameters in a function call. It returns the code generator
+ * flags for the operation.
+ */
+
+void exprhs (unsigned flags, int k, struct expent *lval);
+/* Put the result of an expression into the primary register */
+
+void expression1 (struct expent* lval);
+/* Evaluate an expression on level 1 (no comma operator) and put it into
+ * the primary register
+ */
+
+void expression (struct expent* lval);
+/* Evaluate an expression and put it into the primary register */
+
+int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval);
+/* Will evaluate an expression via the given function. If the result is a
+ * constant, 0 is returned and the value is put in the lval struct. If the
+ * result is not constant, exprhs is called to bring the value into the
+ * primary register and 1 is returned.
+ */
+
+void constexpr (struct expent* lval);
+/* Get a constant value */
+
+void intexpr (struct expent* lval);
+/* Get an integer expression */
+
+void boolexpr (struct expent* lval);
+/* Get a boolean expression */
+
+void test (unsigned label, int cond);
+/* Generate code to perform test and jump if false. */
+
+int hie1 (struct expent* lval);
+/* Parse first level of expression hierarchy. */
+
+int hie0 (struct expent* lval);
+/* Parse comma operator (highest level of expression hierarchy) */
+
+void DefineData (struct expent* lval);
+/* Output a data definition for the given expression */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
+
diff --git a/src/cc65/funcdesc.c b/src/cc65/funcdesc.c
new file mode 100644 (file)
index 0000000..1a1ad26
--- /dev/null
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               funcdesc.c                                 */
+/*                                                                           */
+/*          Function descriptor structure for the cc65 C compiler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "mem.h"
+#include "funcdesc.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+FuncDesc* NewFuncDesc (void)
+/* Create a new symbol table with the given name */
+{
+    /* Create a new function descriptor */
+    FuncDesc* F = xmalloc (sizeof (FuncDesc));
+
+    /* Nullify the fields */
+    F->Flags     = 0;
+    F->SymTab    = 0;
+    F->StructTab  = 0;
+    F->EnumTab   = 0;
+    F->ParamCount = 0;
+    F->ParamSize  = 0;
+
+    /* Return the new struct */
+    return F;
+}
+
+
+
+void FreeFuncDesc (FuncDesc* F)
+/* Free a function descriptor */
+{
+    /* Free the structure */
+    xfree (F);
+}
+
+
+
diff --git a/src/cc65/funcdesc.h b/src/cc65/funcdesc.h
new file mode 100644 (file)
index 0000000..fddab06
--- /dev/null
@@ -0,0 +1,85 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               funcdesc.h                                 */
+/*                                                                           */
+/*          Function descriptor structure for the cc65 C compiler           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FUNCDESC_H
+#define FUNCDESC_H
+
+
+
+/*****************************************************************************/
+/*                             struct FuncDesc                              */
+/*****************************************************************************/
+
+
+
+/* Masks for the Flags field in FuncDesc */
+#define FD_IMPLICIT            0x0001U /* Implicitly declared function  */
+#define FD_EMPTY               0x0002U /* Function with empty param list */
+#define FD_VOID_PARAM          0x0004U /* Function with a void param list */
+#define FD_ELLIPSIS            0x0008U /* Function with variable param list */
+#define FD_FASTCALL            0x0010U /* __fastcall__ function */
+
+/* Function descriptor */
+typedef struct FuncDesc FuncDesc;
+struct FuncDesc {
+    unsigned           Flags;          /* Bitmapped flags FD_... */
+    struct SymTable*   SymTab;         /* Symbol table */
+    struct SymTable*   StructTab;      /* Struct table */
+    struct SymTable*   EnumTab;        /* Enum table */
+    unsigned           ParamCount;     /* Number of parameters */
+    unsigned           ParamSize;      /* Size of the parameters */
+};
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+FuncDesc* NewFuncDesc (void);
+/* Create a new symbol table with the given name */
+
+void FreeFuncDesc (FuncDesc* E);
+/* Free a function descriptor */
+
+
+
+/* End of funcdesc.h */
+#endif
+
+
+
diff --git a/src/cc65/function.c b/src/cc65/function.c
new file mode 100644 (file)
index 0000000..f1a160b
--- /dev/null
@@ -0,0 +1,239 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               function.c                                 */
+/*                                                                           */
+/*                     Parse function entry/body/exit                       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "litpool.h"
+#include "locals.h"
+#include "mem.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "symtab.h"
+#include "function.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure that holds all data needed for function activation */
+struct Function {
+    struct SymEntry*           FuncEntry;      /* Symbol table entry */
+    type*              ReturnType;     /* Function return type */
+    struct FuncDesc*   Desc;           /* Function descriptor */
+    CodeMark           EntryCode;      /* Backpatch addr for entry code */
+    unsigned           LocalMax;       /* Total space for locals */
+    unsigned                   LocalSize;      /* Current space for locals */
+    unsigned           RetLab;         /* Return code label */
+};
+
+/* Pointer to current function */
+Function* CurrentFunc = 0;
+
+
+
+/*****************************************************************************/
+/*                                          code                                    */
+/*****************************************************************************/
+
+
+
+static Function* NewFunction (struct SymEntry* Sym)
+/* Create a new function activation structure and return it */
+{
+    /* Allocate a new structure */
+    Function* F = xmalloc (sizeof (Function));
+
+    /* Initialize the fields */
+    F->FuncEntry  = Sym;
+    F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
+    F->Desc      = DecodePtr (Sym->Type + 1);
+    F->EntryCode  = GetCodePos ();
+    F->LocalMax          = 0;
+    F->LocalSize  = 0;
+    F->RetLab    = GetLabel ();
+
+    /* Return the new structure */
+    return F;
+}
+
+
+
+static void FreeFunction (Function* F)
+/* Free a function activation structure */
+{
+    xfree (F);
+}
+
+
+
+const char* GetFuncName (const Function* F)
+/* Return the name of the current function */
+{
+    return F->FuncEntry->Name;
+}
+
+
+
+unsigned GetParamSize (const Function* F)
+/* Return the parameter size for the current function */
+{
+    return F->Desc->ParamSize;
+}
+
+
+
+type* GetReturnType (Function* F)
+/* Get the return type for the function */
+{
+    return F->ReturnType;
+}
+
+
+
+int HasVoidReturn (const Function* F)
+/* Return true if the function does not have a return value */
+{
+    return IsVoid (F->ReturnType);
+}
+
+
+
+unsigned GetRetLab (const Function* F)
+/* Return the return jump label */
+{
+    return F->RetLab;
+}
+
+
+
+unsigned AllocLocalSpace (Function* F, unsigned Size)
+/* Allocate space for the function locals, return stack offset */
+{
+    /* Remember the current offset */
+    unsigned Offs = F->LocalSize;
+
+    /* Add the size */
+    F->LocalSize += Size;
+    if (F->LocalSize > F->LocalMax) {
+       F->LocalMax = F->LocalSize;
+    }
+
+    /* Return the offset */
+    return Offs;
+}
+
+
+
+void FreeLocalSpace (Function* F, unsigned Size)
+/* Free space allocated for function locals */
+{
+    F->LocalSize -= Size;
+}
+
+
+
+void NewFunc (SymEntry* Func)
+/* Parse argument declarations and function body. */
+{
+    int isbrk;
+
+    /* Get the function descriptor from the function entry */
+    FuncDesc* D = DecodePtr (Func->Type+1);
+
+    /* Allocate the function activation record for the function */
+    CurrentFunc = NewFunction (Func);
+
+    /* Reenter the lexical level */
+    ReenterFunctionLevel (D);
+
+    /* Function body now defined */
+    Func->Flags |= SC_DEF;
+
+    /* C functions cannot currently have __fastcall__ calling conventions */
+    if (IsFastCallFunc (Func->Type)) {
+       Error (ERR_FASTCALL);
+    }
+
+    /* Need a starting curly brace */
+    if (curtok != LCURLY) {
+       Error (ERR_LCURLY_EXPECTED);
+    }
+
+    /* Setup register variables */
+    InitRegVars ();
+
+    /* Switch to the code segment and generate function entry code */
+    g_usecode ();
+    g_enter (TypeOf (Func->Type), Func->Name, GetParamSize (CurrentFunc));
+
+    /* Parse the function body */
+    oursp = 0;
+    isbrk = compound ();
+
+    /* If the function did not end with an return statement, create exit code */
+    if (!isbrk) {
+#if 0
+       /* If the function has a return type, flag an error */
+       if (!voidfunc) {
+           Error (ERR_MUST_RETURN_VALUE);
+       }
+#endif
+       RestoreRegVars (0);
+        g_leave (CF_NONE, 0);
+    }
+
+    /* Dump literal data created by the function */
+    DumpLiteralPool ();
+
+    /* Cleanup register variables */
+    DoneRegVars ();
+
+    /* Leave the lexical level */
+    LeaveFunctionLevel ();
+
+    /* Reset the current function pointer */
+    FreeFunction (CurrentFunc);
+    CurrentFunc = 0;
+}
+
+
+
diff --git a/src/cc65/function.h b/src/cc65/function.h
new file mode 100644 (file)
index 0000000..fed098b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * function.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure that holds all data needed for function activation */
+typedef struct Function Function;
+
+/* Function activation data for current function (or NULL) */
+extern Function* CurrentFunc;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+const char* GetFuncName (const Function* F);
+/* Return the name of the current function */
+
+unsigned GetParamSize (const Function* F);
+/* Return the parameter size for the current function */
+
+type* GetReturnType (Function* F);
+/* Get the return type for the function */
+
+int HasVoidReturn (const Function* F);
+/* Return true if the function does not have a return value */
+
+unsigned GetRetLab (const Function* F);
+/* Return the return jump label */
+
+unsigned AllocLocalSpace (Function* F, unsigned Size);
+/* Allocate space for the function locals, return stack offset  */
+
+void FreeLocalSpace (Function* F, unsigned Size);
+/* Free space allocated for function locals */
+
+void NewFunc (struct SymEntry* Func);
+/* Parse argument declarations and function body. */
+
+
+
+/* End of function.h */
+#endif
+
+
+
diff --git a/src/cc65/global.c b/src/cc65/global.c
new file mode 100644 (file)
index 0000000..81d26b8
--- /dev/null
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*                Global variables for the cc65 C compiler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+unsigned char Target           = TGT_NONE; /* Target system */
+unsigned char ANSI             = 0;        /* Strict ANSI flag */
+unsigned char WriteableStrings = 0;        /* Literal strings are r/w */
+unsigned char NoWarn           = 0;        /* Suppress warnings */
+unsigned char Optimize         = 0;        /* Optimize flag */
+unsigned char FavourSize       = 1;        /* Favour size over speed */
+unsigned char InlineStdFuncs   = 0;        /* Inline some known functions */
+unsigned char EnableRegVars    = 0;        /* Enable register variables */
+unsigned char AllowRegVarAddr  = 0;        /* Allow taking addresses of register vars */
+unsigned char RegVarsToCallStack= 0;               /* Save reg variables on call stack */
+unsigned char LocalsAreStatic  = 0;        /* Make local variables static */
+unsigned char SignedChars      = 0;        /* Make characters signed by default */
+unsigned char Verbose          = 0;        /* Verbose flag */
+unsigned char IncSource                = 0;        /* Include source as comments */
+unsigned char DebugInfo                = 0;        /* Add debug info to the obj */
+unsigned char Debug            = 0;        /* Debug mode */
+
+
+
+
+                                          
diff --git a/src/cc65/global.h b/src/cc65/global.h
new file mode 100644 (file)
index 0000000..c6eaef7
--- /dev/null
@@ -0,0 +1,88 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*                Global variables for the cc65 C compiler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Supported systems */
+#define TGT_NONE       0
+#define TGT_ATARI      1
+#define TGT_C64                2
+#define TGT_C128       3
+#define TGT_ACE                4
+#define TGT_PLUS4      5
+#define TGT_CBM610     6
+#define TGT_PET                7
+#define TGT_NES                8
+#define TGT_APPLE2     9
+#define TGT_GEOS       10
+#define TGT_COUNT      11
+
+
+
+extern unsigned char   Target;                 /* Target system */
+extern unsigned char   ANSI;                   /* Strict ANSI flag */
+extern unsigned char   WriteableStrings;       /* Literal strings are r/w */
+extern unsigned char   NoWarn;                 /* Suppress warnings */
+extern unsigned char   Optimize;               /* Optimize flag */
+extern unsigned char   FavourSize;             /* Favour size over speed */
+extern unsigned char    InlineStdFuncs;                /* Inline some known functions */
+extern unsigned char   EnableRegVars;          /* Enable register variables */
+extern unsigned char   AllowRegVarAddr;        /* Allow taking addresses of register vars */
+extern unsigned char   RegVarsToCallStack;     /* Save reg variables on call stack */
+extern unsigned char   LocalsAreStatic;        /* Make local variables static */
+extern unsigned char   SignedChars;            /* Make characters signed by default */
+extern unsigned char   Verbose;                /* Verbose flag */
+extern unsigned char   IncSource;              /* Include source as comments */
+extern unsigned char   DebugInfo;              /* Add debug info to the obj */
+extern unsigned char   Debug;                  /* Debug mode */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
+
diff --git a/src/cc65/goto.c b/src/cc65/goto.c
new file mode 100644 (file)
index 0000000..b186370
--- /dev/null
@@ -0,0 +1,91 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 goto.c                                   */
+/*                                                                           */
+/*             Goto and label handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "codegen.h"
+#include "error.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "goto.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void DoGoto (void)
+/* Process a goto statement. */
+{
+    /* Eat the "goto" */
+    gettok ();
+
+    /* Label name must follow */
+    if (curtok != IDENT) {
+
+               Error (ERR_IDENT_EXPECTED);
+
+    } else {
+
+       /* Add a new label symbol if we don't have one until now */
+       SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
+
+       /* Jump to the label */
+       g_jump (Entry->V.Label);
+    }
+
+    /* Eat the label name */
+    gettok ();
+}
+
+
+
+void DoLabel (void)
+/* Define a label. */
+{
+    /* Add a label symbol */
+    SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF);
+
+    /* Emit the jump label */
+    g_defloclabel (Entry->V.Label);
+
+    /* Eat the ident and colon */
+    gettok ();
+    gettok ();
+}
+
+
+
diff --git a/src/cc65/goto.h b/src/cc65/goto.h
new file mode 100644 (file)
index 0000000..4492b1e
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 goto.h                                   */
+/*                                                                           */
+/*             Goto and label handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GOTO_H
+#define GOTO_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void DoGoto (void);
+/* Process a goto statement. */
+
+void DoLabel (void);
+/* Define a goto label. */
+
+
+
+/* End of goto.h */
+#endif
+
+
+
diff --git a/src/cc65/hashstr.c b/src/cc65/hashstr.c
new file mode 100644 (file)
index 0000000..23b7121
--- /dev/null
@@ -0,0 +1,60 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                hashstr.c                                 */
+/*                                                                           */
+/*                        Hash function for strings                         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "hashstr.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S)
+/* Return a hash value for the given string */
+{
+    unsigned L, H;
+
+    /* Do the hash */
+    H = L = 0;
+    while (*S) {
+       H = ((H << 3) ^ ((unsigned char) *S++)) + L++;
+    }
+    return H;
+}
+
+
+
diff --git a/src/cc65/hashstr.h b/src/cc65/hashstr.h
new file mode 100644 (file)
index 0000000..af7f279
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                hashstr.h                                 */
+/*                                                                           */
+/*                        Hash function for strings                         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef HASHSTR_H
+#define HASHSTR_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S);
+/* Return a hash value for the given string */
+
+
+
+/* End of hashstr.h */
+
+#endif
+
+
+
diff --git a/src/cc65/ident.c b/src/cc65/ident.c
new file mode 100644 (file)
index 0000000..615997a
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 ident.c                                  */
+/*                                                                           */
+/*                Identifier handling for the cc65 compiler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <ctype.h>
+
+#include "ident.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int IsIdent (char c)
+/* Return true if the given char may start an identifier */
+{
+    return (isalpha (c) || c == '_');
+}
+
+
+
diff --git a/src/cc65/ident.h b/src/cc65/ident.h
new file mode 100644 (file)
index 0000000..f4db625
--- /dev/null
@@ -0,0 +1,71 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 ident.h                                  */
+/*                                                                           */
+/*                Identifier handling for the cc65 compiler                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef IDENT_H
+#define IDENT_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Maximum length of an identifier and the corresponding char array */
+#define MAX_IDENTLEN   64
+#define        IDENTSIZE       (MAX_IDENTLEN+1)
+
+/* Variable that holds an identifer */
+typedef char ident [IDENTSIZE];
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int IsIdent (char c);
+/* Return true if the given char may start an identifier */
+
+
+
+/* End of ident.h */
+#endif
+
+
+
diff --git a/src/cc65/include.c b/src/cc65/include.c
new file mode 100644 (file)
index 0000000..2488d71
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * include.c - Include file handling for cc65
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mem.h"
+#include "include.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+static char* SysIncludePath  = 0;
+static char* UserIncludePath = 0;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+static char* Add (char* Orig, char* New)
+/* Create a new path from Orig and New, delete Orig, return the result */
+{
+    unsigned Len, NewLen;
+    char* NewPath;
+
+    /* Check for a trailing path separator and remove it */
+    NewLen = strlen (New);
+    if (NewLen > 0 && (New [NewLen-1] == '\\' || New [NewLen-1] == '/')) {
+       New [--NewLen] = '\0';
+    }
+
+    /* Calculate the length of the combined paths */
+    if (Orig) {
+               Len = strlen (Orig) + NewLen;
+    } else {
+       Len = NewLen;
+    }
+
+    /* Allocate memory for the new string */
+    NewPath = xmalloc (Len + 2);
+
+    /* Copy the strings */
+    if (Orig) {
+       strcpy (NewPath, Orig);
+    } else {
+       NewPath [0] = '\0';
+    }
+    strcat (NewPath, New);
+    strcat (NewPath, ";");
+
+    /* Delete the original path */
+    xfree (Orig);
+
+    /* Return the new path */
+    return NewPath;
+}
+
+
+
+static char* Find (char* Path, char* File)
+/* Search for a file in a list of directories. If found, return the complete
+ * name including the path in a malloced data area, if not found, return 0.
+ */
+{
+    char* P;
+    unsigned Count;
+    int Max;
+    char PathName [FILENAME_MAX];
+
+    /* Initialize variables */
+    Max = sizeof (PathName) - strlen (File) - 2;
+    if (Max < 0) {
+       return 0;
+    }
+    P = Path;
+
+    /* Handle a NULL pointer as replacement for an empty string */
+    if (P == 0) {
+       P = "";
+    }
+
+    /* Start the search */
+    while (*P) {
+        /* Copy the next path element into the buffer */
+       Count = 0;
+       while (*P != '\0' && *P != ';' && Count < Max) {
+           PathName [Count++] = *P++;
+       }
+
+       /* Add a path separator and the filename */
+       if (Count) {
+           PathName [Count++] = '/';
+       }
+       strcpy (PathName + Count, File);
+
+       /* Check if this file exists */
+       if (access (PathName, R_OK) == 0) {
+           /* The file exists */
+           return xstrdup (PathName);
+       }
+
+       /* Skip a list separator if we have one */
+       if (*P == ';') {
+           ++P;
+       }
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+void AddIncludePath (char* NewPath, unsigned Where)
+/* Add a new include path to the existing one */
+{
+    /* Allow a NULL path */
+    if (NewPath) {
+       if (Where & INC_SYS) {
+           SysIncludePath = Add (SysIncludePath, NewPath);
+       }
+       if (Where & INC_USER) {
+           UserIncludePath = Add (UserIncludePath, NewPath);
+       }
+    }
+}
+
+
+
+char* FindInclude (char* Name, unsigned Where)
+/* Find an include file. Return a pointer to a malloced area that contains
+ * the complete path, if found, return 0 otherwise.
+ */
+{
+    if (Where & INC_SYS) {
+       /* Search in the system include directories */
+       return Find (SysIncludePath, Name);
+    }
+    if (Where & INC_USER) {
+       /* Search in the user include directories */
+       return Find (UserIncludePath, Name);
+    }
+    return 0;
+}
+
+
+
diff --git a/src/cc65/include.h b/src/cc65/include.h
new file mode 100644 (file)
index 0000000..e8131b3
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * include.h - Include file handling for cc65
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ */
+
+
+
+#ifndef INCLUDE_H
+#define INCLUDE_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+#define INC_SYS                0x0001          /* Add to system include path */
+#define INC_USER       0x0002          /* Add to user include path */
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void AddIncludePath (char* NewPath, unsigned Where);
+/* Add a new include path to the existing one */
+
+char* FindInclude (char* Name, unsigned Where);
+/* Find an include file. Return a pointer to a malloced area that contains
+ * the complete path, if found, return 0 otherwise.
+ */
+
+
+
+/* End of include.h */
+#endif
+
+
+
diff --git a/src/cc65/io.c b/src/cc65/io.c
new file mode 100644 (file)
index 0000000..517aa95
--- /dev/null
@@ -0,0 +1,184 @@
+
+/* C I/O functions */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "asmcode.h"
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "codegen.h"
+#include "optimize.h"
+#include "io.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Input line stuff */
+char linebuf [LINESIZE];
+char* line = linebuf;
+char* lptr = 0;
+
+/* Input file table and number of open input files */
+struct filent filetab[MAXFILES];
+int ifile = 0;
+
+/* Current input file stream data */
+FILE* inp = 0;
+char* fin = 0;
+unsigned ln = 0;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int nch (void)
+/* Get the next char in input stream (the one behind the current one) */
+{
+    if (*lptr == '\0') {
+       return 0;
+    } else {
+       return lptr[1] & 0xFF;
+    }
+}
+
+
+
+int cgch (void)
+/* Get the current character in the input stream and advance line
+ * pointer (unless already at end of line).
+ */
+{
+    if (*lptr == '\0') {
+       return (0);
+    } else {
+       return (*lptr++ & 0xFF);
+    }
+}
+
+
+
+int gch (void)
+/* Get the current character in the input stream and advance line
+ * pointer (no end of line check is performed).
+ */
+{
+    return (*lptr++ & 0xFF);
+}
+
+
+
+void kill (void)
+/* Reset input line pointer, clear input line */
+{
+    lptr = line;
+    *lptr = '\0';
+}
+
+
+
+static void CloseInclude (void)
+/* Close an include file and switch to the higher level file. Set inp to NULL
+ * if this was the main file.
+ */
+{
+    struct filent* pftab;
+
+    /* Close the file */
+    fclose(inp);
+
+    /* Leave the include file */
+    if (ifile > 0) {
+       xfree (fin);
+       inp = (pftab = &filetab[--ifile])->f_iocb;
+       ln = pftab->f_ln;
+       fin = pftab->f_name;
+    } else {
+       inp = 0;
+    }
+}
+
+
+
+int readline (void)
+/* Get a line from the current input.  Returns -1 on end of file. */
+{
+    unsigned   Len;
+    unsigned   Part;
+    unsigned   Start;
+    int                Done;
+
+    /* Setup the line */
+    kill ();
+
+    /* If there is no file open, bail out */
+    if (inp == 0) {
+       return 0;
+    }
+
+    /* Read lines until we get one with real contents */
+    Len = 0;
+    Done = 0;
+    while (!Done && Len < LINESIZE) {
+
+               while (fgets (line + Len, LINESIZE - Len, inp) == 0) {
+
+           /* eof */
+           kill ();
+
+           /* Leave the current file */
+           CloseInclude ();
+
+           /* If this was the last file, bail out */
+           if (inp == 0) {
+               return 0;
+           }
+               }
+
+       /* We got a new line */
+       ++ln;
+
+       /* Remove the trailing newline if we have one */
+       Part = strlen (line + Len);
+       Start = Len;
+       Len += Part;
+       while (Len > 0 && line [Len-1] == '\n') {
+           --Len;
+       }
+       line [Len] = '\0';
+
+       /* Output the source line in the generated assembler file
+        * if requested.
+        */
+       if (IncSource && line[Start] != '\0') {
+           AddCodeLine ("; %s", line+Start);
+       }
+
+       /* Check if we have a line continuation character at the end. If not,
+        * we're done.
+        */
+       if (Len > 0 && line[Len-1] == '\\') {
+           line[Len-1] = '\n';         /* Replace by newline */
+       } else {
+           Done = 1;
+       }
+    }
+
+    /* Got a line */
+    return 1;
+}
+
+
+
diff --git a/src/cc65/io.h b/src/cc65/io.h
new file mode 100644 (file)
index 0000000..aa83670
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * io.h
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#ifndef IO_H
+#define IO_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Maximum length of an input line and the corresponding char array */
+#define LINEMAX                4095
+#define LINESIZE       LINEMAX+1
+
+/* Maximum number of nested input files */
+#define MAXFILES       16
+
+/* Input line stuff */
+extern char linebuf [LINESIZE];
+extern char* line;
+extern char* lptr;
+
+/* File table entry */
+struct filent {
+    FILE* f_iocb;
+    char* f_name;
+    int   f_ln;
+};
+
+/* Input file table and number of open input files */
+extern struct filent filetab[MAXFILES];
+extern int ifile;
+
+/* Current input file stream data */
+extern FILE* inp;              /* Input file stream */
+extern char* fin;              /* Input file name */
+extern unsigned ln;            /* Line number */
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void kill (void);
+/* Reset input line pointer, clear input line */
+
+int nch (void);
+/* Get the next char in input stream (the one behind the current one) */
+
+int cgch (void);
+/* Get the current character in the input stream and advance line
+ * pointer (unless already at end of line).
+ */
+
+int gch (void);
+/* Get the current character in the input stream and advance line
+ * pointer (no end of line check is performed).
+ */
+
+int readline (void);
+/* Get a line from the current input.  Returns -1 on end of file. */
+
+
+
+/* End of io.h */
+
+#endif
+
+
+
diff --git a/src/cc65/litpool.c b/src/cc65/litpool.c
new file mode 100644 (file)
index 0000000..65c896d
--- /dev/null
@@ -0,0 +1,182 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                litpool.c                                 */
+/*                                                                           */
+/*             Literal string handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "asmlabel.h"
+#include "check.h"
+#include "ctrans.h"
+#include "codegen.h"
+#include "error.h"
+#include "global.h"
+#include "litpool.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+#define LITPOOL_SIZE           4096                    /* Max strings per function */
+static unsigned char LiteralPool[LITPOOL_SIZE]; /* The literal pool */
+static unsigned LiteralOffs    = 0;            /* Current pool offset */
+static unsigned LiteralSpace           = 0;            /* Space used (stats only) */
+
+unsigned LiteralLabel                  = 1;            /* Pool asm label */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void TranslateLiteralPool (unsigned Offs)
+/* Translate the literals starting from the given offset into the target
+ * charset.
+ */
+{
+    while (Offs < LiteralOffs) {
+       LiteralPool[Offs] = ctrans (LiteralPool[Offs]);
+       ++Offs;
+    }
+}
+
+
+
+void DumpLiteralPool (void)
+/* Dump the literal pool */
+{
+    /* if nothing there, exit... */
+    if (LiteralOffs == 0) {
+       return;
+    }
+
+    /* Switch to the data segment */
+    if (WriteableStrings) {
+       g_usedata ();
+    } else {
+               g_userodata ();
+    }
+
+    /* Define the label */
+    g_defloclabel (LiteralLabel);
+
+    /* Translate the buffer contents into the target charset */
+    TranslateLiteralPool (0);
+
+    /* Output the buffer data */
+    g_defbytes (LiteralPool, LiteralOffs);
+
+    /* Switch back to the code segment */
+    g_usecode ();
+
+    /* Reset the buffer */
+    LiteralSpace += LiteralOffs;       /* Count literal bytes emitted */
+    LiteralLabel  = GetLabel ();               /* Get a new pool label */
+    LiteralOffs          = 0;
+}
+
+
+
+unsigned GetLiteralOffs (void)
+/* Return the current offset into the literal pool */
+{
+    return LiteralOffs;
+}
+
+
+
+void ResetLiteralOffs (unsigned Offs)
+/* Reset the offset into the literal pool to some earlier value, effectively
+ * removing values from the pool.
+ */
+{
+    CHECK (Offs <= LiteralOffs);
+    LiteralOffs = Offs;
+}
+
+
+
+void AddLiteralChar (char C)
+/* Add one character to the literal pool */
+{
+    if (LiteralOffs >= LITPOOL_SIZE) {
+       Fatal (FAT_OUT_OF_STRSPACE);
+    }
+    LiteralPool[LiteralOffs++] = C;
+}
+
+
+
+unsigned AddLiteral (const char* S)
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool
+ */
+{
+    /* Remember the starting offset */
+    unsigned Start = LiteralOffs;
+
+    /* Copy the string doing a range check */
+    do {
+       AddLiteralChar (*S);
+    } while (*S++);
+
+    /* Return the starting offset */
+    return Start;
+}
+
+
+
+const char* GetLiteral (unsigned Offs)
+/* Get a pointer to the literal with the given offset in the pool */
+{
+    CHECK (Offs < LiteralOffs);
+    return &LiteralPool[Offs];
+}
+
+
+
+void PrintLiteralStats (FILE* F)
+/* Print statistics about the literal space used */
+{
+    fprintf (F, "Literal space used: %d bytes\n", LiteralSpace);
+}
+
+
+
diff --git a/src/cc65/litpool.h b/src/cc65/litpool.h
new file mode 100644 (file)
index 0000000..f168d89
--- /dev/null
@@ -0,0 +1,93 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                litpool.h                                 */
+/*                                                                           */
+/*             Literal string handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LITPOOL_H
+#define LITPOOL_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+extern unsigned LiteralLabel;          /* Pool asm label */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void TranslateLiteralPool (unsigned Offs);
+/* Translate the literals starting from the given offset into the target
+ * charset.
+ */
+
+void DumpLiteralPool (void);
+/* Dump the literal pool */
+
+unsigned GetLiteralOffs (void);
+/* Return the current offset into the literal pool */
+
+void ResetLiteralOffs (unsigned Offs);
+/* Reset the offset into the literal pool to some earlier value, effectively
+ * removing values from the pool.
+ */
+
+void AddLiteralChar (char C);
+/* Add one character to the literal pool */
+
+unsigned AddLiteral (const char* S);
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool for this string.
+ */
+
+const char* GetLiteral (unsigned Offs);
+/* Get a pointer to the literal with the given offset in the pool */
+
+void PrintLiteralStats (FILE* F);
+/* Print statistics about the literal space used */
+
+
+
+/* End of litpool.h */
+#endif
+
+
+
diff --git a/src/cc65/locals.c b/src/cc65/locals.c
new file mode 100644 (file)
index 0000000..63b6b86
--- /dev/null
@@ -0,0 +1,469 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                locals.c                                  */
+/*                                                                           */
+/*             Local variable handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "anonname.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "declare.h"
+#include "expr.h"
+#include "function.h"  /* ## */
+#include "global.h"
+#include "mem.h"
+#include "symtab.h"
+#include "locals.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Register variable management */
+unsigned MaxRegSpace           = 6;    /* Maximum space available */
+static int RegOffs                     = 0;    /* Offset into register space */
+static const SymEntry** RegSyms        = 0;    /* The register variables */
+static unsigned RegSymCount    = 0;    /* Number of register variables */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void InitRegVars (void)
+/* Initialize register variable control data */
+{
+    /* If the register space is zero, bail out */
+    if (MaxRegSpace == 0) {
+               return;
+    }
+
+    /* The maximum number of register variables is equal to the register
+     * variable space available. So allocate one pointer per byte. This
+     * will usually waste some space but we don't need to dynamically
+     * grow the array.
+     */
+    RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
+    RegOffs = MaxRegSpace;
+}
+
+
+
+void DoneRegVars (void)
+/* Free the register variables */
+{
+    xfree (RegSyms);
+    RegSyms = 0;
+    RegOffs = MaxRegSpace;
+    RegSymCount = 0;
+}
+
+
+
+static int AllocRegVar (const SymEntry* Sym, const type* tarray)
+/* Allocate a register variable with the given amount of storage. If the
+ * allocation was successful, return the offset of the register variable in
+ * the register bank (zero page storage). If there is no register space left,
+ * return -1.
+ */
+{
+    /* Maybe register variables are disabled... */
+    if (EnableRegVars) {
+
+       /* Get the size of the variable */
+       unsigned Size = SizeOf (tarray);
+
+       /* Do we have space left? */
+       if (RegOffs >= Size) {
+
+           /* Space left. We allocate the variables from high to low addresses,
+            * so the adressing is compatible with the saved values on stack.
+            * This allows shorter code when saving/restoring the variables.
+            */
+           RegOffs -= Size;
+           RegSyms [RegSymCount++] = Sym;
+           return RegOffs;
+       }
+    }
+
+    /* No space left or no allocation */
+    return -1;
+}
+
+
+
+void DeclareLocals (void)
+/* Declare local variables and types. */
+{
+    int offs = oursp;          /* Current stack offset for variable */
+    int AutoSpace = 0;         /* Unallocated space on the stack */
+    int Size;                  /* Size of an auto variable */
+    int Reg;                   /* Register variable offset */
+    unsigned flags = 0;                /* Code generator flags */
+    int SymbolSC;                      /* Storage class for symbol */
+    int ldata = 0;                     /* Local symbol data temp storage */
+
+    /* Loop until we don't find any more variables */
+    while (1) {
+
+       /* Check variable declarations. We need to distinguish between a
+        * default int type and the end of variable declarations. So we
+        * will do the following: If there is no explicit storage class
+        * specifier *and* no explicit type given, it is assume that we
+                * have reached the end of declarations.
+        */
+       DeclSpec Spec;
+       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+               if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
+           break;
+       }
+
+       /* Accept type only declarations */
+       if (curtok == SEMI) {
+           /* Type declaration only ### Check struct/union here */
+           gettok ();
+           continue;
+       }
+
+       /* Parse a comma separated variable list */
+       while (1) {
+
+           Declaration Decl;
+
+           /* Remember the storage class for the new symbol */
+           SymbolSC = Spec.StorageClass;
+
+           /* Read the declaration */
+           ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+
+           /* If we don't have a name, this was flagged as an error earlier.
+            * To avoid problems later, use an anonymous name here.
+            */
+                   if (Decl.Ident[0] == '\0') {
+               AnonName (Decl.Ident, "param");
+           }
+
+                   if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) {
+
+               /* Get the size of the variable */
+               Size = SizeOf (Decl.Type);
+
+#if 0
+               /* Check the storage class */
+               if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) {
+
+                   /* We will store the current value of the register onto the
+                    * stack, thus making functions with register variables
+                    * reentrant. If we have pending auto variables, emit them
+                    * now.
+                    */
+                   g_usecode ();
+                   g_space (AutoSpace);
+                   oursp -= AutoSpace;
+                   AutoSpace = 0;
+
+                   /* Remember the register bank offset */
+                   ldata = Reg;
+
+                   /* Save the current register value onto the stack */
+                   g_save_regvars (Reg, Size);
+
+                   /* Allow variable initialization */
+                   if (curtok == ASGN) {
+
+                       struct expent lval;
+
+                       /* Skip the '=' */
+                       gettok ();
+
+                       /* Get the expression into the primary */
+                       expression1 (&lval);
+
+                       /* Make type adjustments if needed */
+                       assignadjust (tarray, &lval);
+
+                       /* Setup the type flags for the assignment */
+                       flags = TypeOf (tarray) | CF_REGVAR;
+                       if (Size == 1) {
+                           flags |= CF_FORCECHAR;
+                       }
+
+                               /* Store the value into the register */
+                               g_putstatic (flags, Reg, 0);
+
+                       /* Mark the variable as referenced */
+                       SymbolSC |= SC_REF;
+
+                   }
+
+                   /* Account for the stack space needed and remember the
+                    * stack offset of the save area.
+                    */
+                   offs -= Size;
+                   psym->h_lattr = offs;
+
+               } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+#endif
+               if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+
+                   /* Auto variable */
+                   if (LocalsAreStatic == 0) {
+
+                       /* Change SC in case it was register */
+                               SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
+                       if (curtok == ASGN) {
+
+                           struct expent lval;
+
+                           /* Switch to the code segment, allocate space for
+                            * uninitialized variables.
+                            */
+                           g_usecode ();
+                           g_space (AutoSpace);
+                           oursp -= AutoSpace;
+                           AutoSpace = 0;
+
+                           /* Skip the '=' */
+                           gettok ();
+
+                           /* Setup the type flags for the assignment */
+                           flags = Size == 1? CF_FORCECHAR : CF_NONE;
+
+                           /* Get the expression into the primary */
+                           if (evalexpr (flags, hie1, &lval) == 0) {
+                               /* Constant expression. Adjust the types */
+                               assignadjust (Decl.Type, &lval);
+                               flags |= CF_CONST;
+                           } else {
+                               /* Expression is not constant and in the primary */
+                               assignadjust (Decl.Type, &lval);
+                           }
+
+                           /* Push the value */
+                           g_push (flags | TypeOf (Decl.Type), lval.e_const);
+
+                           /* Mark the variable as referenced */
+                           SymbolSC |= SC_REF;
+
+                       } else {
+                           /* Non-initialized local variable. Just keep track of
+                            * the space needed.
+                            */
+                           AutoSpace += Size;
+                       }
+
+                       /* Allocate space on the stack, assign the offset */
+                       offs -= Size;
+                       ldata = offs;
+
+                   } else {
+
+                       /* Static local variables. */
+                               SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
+
+                       /* Put them into the BSS */
+                       g_usebss ();
+
+                       /* Define the variable label */
+                       g_defloclabel (ldata = GetLabel ());
+
+                       /* Reserve space for the data */
+                       g_res (Size);
+
+                       /* Allow assignments */
+                       if (curtok == ASGN) {
+
+                           struct expent lval;
+
+                           /* Switch to the code segment. */
+                           g_usecode ();
+
+                           /* Skip the '=' */
+                           gettok ();
+
+                           /* Get the expression into the primary */
+                           expression1 (&lval);
+
+                           /* Make type adjustments if needed */
+                           assignadjust (Decl.Type, &lval);
+
+                           /* Setup the type flags for the assignment */
+                           flags = TypeOf (Decl.Type);
+                           if (Size == 1) {
+                               flags |= CF_FORCECHAR;
+                           }
+
+                           /* Store the value into the variable */
+                           g_putstatic (flags, ldata, 0);
+
+                           /* Mark the variable as referenced */
+                           SymbolSC |= SC_REF;
+                       }
+                   }
+
+               } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
+
+                   /* Static data */
+                   if (curtok == ASGN) {
+
+                       /* Initialization ahead, switch to data segment */
+                       g_usedata ();
+
+                       /* Define the variable label */
+                       g_defloclabel (ldata = GetLabel ());
+
+                       /* Skip the '=' */
+                       gettok ();
+
+                       /* Allow initialization of static vars */
+                       ParseInit (Decl.Type);
+
+                       /* Mark the variable as referenced */
+                       SymbolSC |= SC_REF;
+
+                   } else {
+
+                       /* Uninitialized data, use BSS segment */
+                       g_usebss ();
+
+                       /* Define the variable label */
+                       g_defloclabel (ldata = GetLabel ());
+
+                       /* Reserve space for the data */
+                       g_res (Size);
+
+                   }
+               }
+
+           }
+
+           /* If the symbol is not marked as external, it will be defined */
+           if ((SymbolSC & SC_EXTERN) == 0) {
+               SymbolSC |= SC_DEF;
+           }
+
+           /* Add the symbol to the symbol table */
+           AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata);
+
+           if (curtok != COMMA) {
+               break;
+           }
+           gettok ();
+               }
+       if (curtok == SEMI) {
+           gettok ();
+       }
+    }
+
+    /* In case we switched away from code segment, switch back now */
+    g_usecode ();
+
+    /* Create space for locals */
+    g_space (AutoSpace);
+    oursp -= AutoSpace;
+}
+
+
+
+void RestoreRegVars (int HaveResult)
+/* Restore the register variables for the local function if there are any.
+ * The parameter tells us if there is a return value in ax, in that case,
+ * the accumulator must be saved across the restore.
+ */
+{
+    int I, J, Bytes, Offs;
+
+    /* If we don't have register variables in this function, bail out early */
+    if (RegSymCount == 0) {
+       return;
+    }
+
+    /* Save the accumulator if needed */
+    if (!HasVoidReturn (CurrentFunc) && HaveResult) {
+       g_save (CF_CHAR | CF_FORCECHAR);
+    }
+
+    /* Walk through all variables. If there are several variables in a row
+     * (that is, with increasing stack offset), restore them in one chunk.
+     */
+    I = 0;
+    while (I < RegSymCount) {
+
+       /* Check for more than one variable */
+               const SymEntry* Sym = RegSyms[I];
+       Offs  = Sym->V.Offs;
+       Bytes = SizeOf (Sym->Type);
+       J = I+1;
+
+               while (J < RegSymCount) {
+
+           /* Get the next symbol */
+           const SymEntry* NextSym = RegSyms [J];
+
+           /* Get the size */
+           int Size = SizeOf (NextSym->Type);
+
+           /* Adjacent variable? */
+           if (NextSym->V.Offs + Size != Offs) {
+               /* No */
+               break;
+           }
+
+           /* Adjacent variable */
+           Bytes += Size;
+           Offs  -= Size;
+           Sym   = NextSym;
+           ++J;
+       }
+
+       /* Restore the memory range */
+               g_restore_regvars (Offs, Sym->V.Offs, Bytes);
+
+       /* Next round */
+       I = J;
+    }
+
+    /* Restore the accumulator if needed */
+    if (!HasVoidReturn (CurrentFunc) && HaveResult) {
+       g_restore (CF_CHAR | CF_FORCECHAR);
+    }
+}
+
+
+
diff --git a/src/cc65/locals.h b/src/cc65/locals.h
new file mode 100644 (file)
index 0000000..7101494
--- /dev/null
@@ -0,0 +1,68 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                locals.h                                  */
+/*                                                                           */
+/*             Local variable handling for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LOCALS_H
+#define LOCALS_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void InitRegVars (void);
+/* Initialize register variable control data */
+
+void DoneRegVars (void);
+/* Free the register variables */
+
+void DeclareLocals (void);
+/* Declare local variables and types. */
+
+void RestoreRegVars (int HaveResult);
+/* Restore the register variables for the local function if there are any.
+ * The parameter tells us if there is a return value in ax, in that case,
+ * the accumulator must be saved across the restore.
+ */
+
+
+
+/* End of locals.h */
+#endif
+
+
+
diff --git a/src/cc65/loop.c b/src/cc65/loop.c
new file mode 100644 (file)
index 0000000..ec51dc9
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * loop.c
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#include "error.h"
+#include "mem.h"
+#include "loop.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* The root */
+static struct loopdesc* loopstack = 0;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+struct loopdesc* addloop (unsigned sp, unsigned loop, unsigned label,
+                         unsigned linc, unsigned lstat)
+/* Create and add a new loop descriptor */
+{
+    struct loopdesc* l;
+
+    /* Allocate a new struct */
+    l = xmalloc (sizeof (struct loopdesc));
+
+    /* Fill in the data */
+    l->sp              = sp;
+    l->loop            = loop;
+    l->label           = label;
+    l->linc            = linc;
+    l->lstat           = lstat;
+
+    /* Insert it into the list */
+    l->next = loopstack;
+    loopstack = l;
+
+    /* Return a pointer to the struct */
+    return l;
+}
+
+
+
+struct loopdesc* currentloop (void)
+/* Return a pointer to the descriptor of the current loop */
+{
+    if (loopstack == 0) {
+       /* Stack is empty */
+       Error (ERR_NO_ACTIVE_LOOP);
+    }
+    return loopstack;
+}
+
+
+
+void delloop (void)
+/* Remove the current loop */
+{
+    struct loopdesc* l;
+
+    l = loopstack;
+    loopstack = loopstack->next;
+    xfree (l);
+}
+
+
+
diff --git a/src/cc65/loop.h b/src/cc65/loop.h
new file mode 100644 (file)
index 0000000..b5c7561
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * loop.h
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#ifndef LOOP_H
+#define LOOP_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+struct loopdesc {
+    struct loopdesc*   next;
+    unsigned           sp;
+    unsigned           loop;
+    unsigned           label;
+    unsigned           linc;
+    unsigned           lstat;
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+struct loopdesc* addloop (unsigned sp, unsigned loop, unsigned label,
+                         unsigned linc, unsigned lstat);
+/* Create and add a new loop descriptor */
+
+struct loopdesc* currentloop (void);
+/* Return a pointer to the descriptor of the current loop */
+
+void delloop (void);
+/* Remove the current loop */
+
+
+
+/* End of loop.h */
+
+#endif
+
+
+
diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c
new file mode 100644 (file)
index 0000000..fd41abe
--- /dev/null
@@ -0,0 +1,329 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               macrotab.h                                 */
+/*                                                                           */
+/*            Preprocessor macro table for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "error.h"
+#include "hashstr.h"
+#include "mem.h"
+#include "macrotab.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* The macro hash table */
+#define MACRO_TAB_SIZE 211
+static Macro* MacroTab[MACRO_TAB_SIZE];
+
+/* A table that holds the count of macros that start with a specific character.
+ * It is used to determine quickly, if an identifier may be a macro or not
+ * without calculating the hash over the name.
+ */
+static unsigned short MacroFlagTab[256];
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+Macro* NewMacro (const char* Name)
+/* Allocate a macro structure with the given name. The structure is not
+ * inserted into the macro table.
+ */
+{
+    /* Get the length of the macro name */
+    unsigned Len = strlen(Name);
+
+    /* Allocate the structure */
+    Macro* M = xmalloc (sizeof(Macro) + Len);
+
+    /* Initialize the data */
+    M->Next       = 0;
+    M->ArgCount    = -1;       /* Flag: Not a function like macro */
+    M->MaxArgs    = 0;
+    M->FormalArgs  = 0;
+    M->ActualArgs  = 0;
+    M->Replacement = 0;
+    memcpy (M->Name, Name, Len+1);
+
+    /* Return the new macro */
+    return M;
+}
+
+
+
+void FreeMacro (Macro* M)
+/* Delete a macro definition. The function will NOT remove the macro from the
+ * table, use UndefineMacro for that.
+ */
+{
+    int I;
+
+    for (I = 0; I < M->ArgCount; ++I) {
+       xfree (M->FormalArgs[I]);
+    }
+    xfree (M->FormalArgs);
+    xfree (M->ActualArgs);
+    xfree (M->Replacement);
+    xfree (M);
+}
+
+
+
+void AddNumericMacro (const char* Name, long Val)
+/* Add a macro for a numeric constant */
+{
+    char Buf[64];
+
+    /* Make a string from the number */
+    sprintf (Buf, "%ld", Val);
+
+    /* Handle as text macro */
+    AddTextMacro (Name, Buf);
+}
+
+
+
+void AddTextMacro (const char* Name, const char* Val)
+/* Add a macro for a textual constant */
+{
+    /* Create a new macro */
+    Macro* M = NewMacro (Name);
+
+    /* Set the value as replacement text */
+    M->Replacement = xstrdup (Val);
+
+    /* Insert the macro into the macro table */
+    InsertMacro (M);
+}
+
+
+
+void InsertMacro (Macro* M)
+/* Insert the given macro into the macro table. This call will also allocate
+ * the ActualArgs parameter array.
+ */
+{
+    unsigned Hash;
+
+    /* Allocate the ActualArgs parameter array */
+    if (M->ArgCount > 0) {
+       M->ActualArgs = xmalloc (M->ArgCount * sizeof(char*));
+    }
+
+    /* Get the hash value of the macro name */
+    Hash = HashStr (M->Name) % MACRO_TAB_SIZE;
+
+    /* Insert the macro */
+    M->Next = MacroTab[Hash];
+    MacroTab[Hash] = M;
+
+    /* Increment the number of macros starting with this char */
+    MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]++;
+}
+
+
+
+int UndefineMacro (const char* Name)
+/* Search for the macro with the given name and remove it from the macro
+ * table if it exists. Return 1 if a macro was found and deleted, return
+ * 0 otherwise.
+ */
+{
+    /* Get the hash value of the macro name */
+    unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
+
+    /* Search the hash chain */
+    Macro* L = 0;
+    Macro* M = MacroTab[Hash];
+    while (M) {
+       if (strcmp (M->Name, Name) == 0) {
+
+           /* Found it */
+           if (L == 0) {
+               /* First in chain */
+               MacroTab[Hash] = M->Next;
+           } else {
+               L->Next = M->Next;
+           }
+
+           /* Decrement the number of macros starting with this char */
+           MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]--;
+
+           /* Delete the macro */
+           FreeMacro (M);
+
+           /* Done */
+           return 1;
+       }
+
+       /* Next macro */
+       L = M;
+       M = M->Next;
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+Macro* FindMacro (const char* Name)
+/* Find a macro with the given name. Return the macro definition or NULL */
+{
+    /* Get the hash value of the macro name */
+    unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
+
+    /* Search the hash chain */
+    Macro* M = MacroTab[Hash];
+    while (M) {
+       if (strcmp (M->Name, Name) == 0) {
+           /* Found it */
+           return M;
+       }
+
+       /* Next macro */
+       M = M->Next;
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+int IsMacro (const char* Name)
+/* Return true if the given name is the name of a macro, return false otherwise */
+{
+    return FindMacro(Name) != 0;
+}
+
+
+
+int MaybeMacro (unsigned char C)
+/* Return true if the given character may be the start of the name of an
+ * existing macro, return false if not.
+ */
+{
+    return (MacroFlagTab[C] > 0);
+}
+
+
+
+const char* FindMacroArg (Macro* M, const char* Arg)
+/* Search for a formal macro argument. If found, return the actual
+ * (replacement) argument. If the argument was not found, return NULL.
+ */
+{
+    int I;
+    for (I = 0; I < M->ArgCount; ++I) {
+       if (strcmp (M->FormalArgs[I], Arg) == 0) {
+           /* Found */
+           return M->ActualArgs[I];
+       }
+    }
+    /* Not found */
+    return 0;
+}
+
+
+
+void AddMacroArg (Macro* M, const char* Arg)
+/* Add a formal macro argument. */
+{
+    /* Check if we have a duplicate macro argument, but add it anyway.
+     * Beware: Don't use FindMacroArg here, since the actual argument array
+     * may not be initialized.
+     */
+    int I;
+    for (I = 0; I < M->ArgCount; ++I) {
+       if (strcmp (M->FormalArgs[I], Arg) == 0) {
+           /* Found */
+           Error (ERR_DUPLICATE_MACRO_ARG, Arg);
+           break;
+       }
+    }
+
+    /* Check if we have enough room available, otherwise expand the array
+     * that holds the formal argument list.
+     */
+    if (M->ArgCount >= M->MaxArgs) {
+       /* We must expand the array */
+       char** OldArgs = M->FormalArgs;
+       M->MaxArgs += 10;
+       M->FormalArgs = xmalloc (M->MaxArgs * sizeof(char*));
+       memcpy (M->FormalArgs, OldArgs, M->ArgCount * sizeof (char*));
+       xfree (OldArgs);
+    }
+
+    /* Add the new argument */
+    M->FormalArgs[M->ArgCount++] = xstrdup (Arg);
+}
+
+
+
+void PrintMacroStats (FILE* F)
+/* Print macro statistics to the given text file. */
+{
+    unsigned I;
+    Macro* M;
+
+    fprintf (F, "\n\nMacro Hash Table Summary\n");
+    for (I = 0; I < MACRO_TAB_SIZE; ++I) {
+               fprintf (F, "%3u : ", I);
+       M = MacroTab [I];
+       if (M) {
+           while (M) {
+               fprintf (F, "%s ", M->Name);
+               M = M->Next;
+           }
+           fprintf (F, "\n");
+       } else {
+           fprintf (F, "empty\n");
+       }
+    }
+}
+
+
+
diff --git a/src/cc65/macrotab.h b/src/cc65/macrotab.h
new file mode 100644 (file)
index 0000000..3f5bbab
--- /dev/null
@@ -0,0 +1,122 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               macrotab.h                                 */
+/*                                                                           */
+/*            Preprocessor macro table for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MACROTAB_H
+#define MACROTAB_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+typedef struct Macro_ Macro;
+struct Macro_ {
+    Macro*      Next;          /* Next macro with same hash value */
+    int                 ArgCount;      /* Number of parameters, -1 = no parens */
+    unsigned    MaxArgs;       /* Size of formal argument list */
+    char**              FormalArgs;    /* Formal argument list */
+    char const** ActualArgs;   /* Actual argument list */
+    char*               Replacement;   /* Replacement text */
+    char        Name[1];       /* Name, dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+Macro* NewMacro (const char* Name);
+/* Allocate a macro structure with the given name. The structure is not
+ * inserted into the macro table.
+ */
+
+void FreeMacro (Macro* M);
+/* Delete a macro definition. The function will NOT remove the macro from the
+ * table, use UndefineMacro for that.
+ */
+
+void AddNumericMacro (const char* Name, long Val);
+/* Add a macro for a numeric constant */
+
+void AddTextMacro (const char* Name, const char* Val);
+/* Add a macro for a textual constant */
+
+void InsertMacro (Macro* M);
+/* Insert the given macro into the macro table. This call will also allocate
+ * the ActualArgs parameter array.
+ */
+
+int UndefineMacro (const char* Name);
+/* Search for the macro with the given name and remove it from the macro
+ * table if it exists. Return 1 if a macro was found and deleted, return
+ * 0 otherwise.
+ */
+
+Macro* FindMacro (const char* Name);
+/* Find a macro with the given name. Return the macro definition or NULL */
+
+int IsMacro (const char* Name);
+/* Return true if the given name is the name of a macro, return false otherwise */
+
+int MaybeMacro (unsigned char C);
+/* Return true if the given character may be the start of the name of an
+ * existing macro, return false if not.
+ */
+
+const char* FindMacroArg (Macro* M, const char* Arg);
+/* Search for a formal macro argument. If found, return the actual
+ * (replacement) argument. If the argument was not found, return NULL.
+ */
+
+void AddMacroArg (Macro* M, const char* Arg);
+/* Add a formal macro argument. */
+
+void PrintMacroStats (FILE* F);
+/* Print macro statistics to the given text file. */
+
+
+
+/* End of macrotab.h */
+#endif
+
+
+
+
diff --git a/src/cc65/main.c b/src/cc65/main.c
new file mode 100644 (file)
index 0000000..296d297
--- /dev/null
@@ -0,0 +1,679 @@
+/* CC65 main program */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../common/version.h"
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "expr.h"
+#include "function.h"
+#include "global.h"
+#include "include.h"
+#include "io.h"
+#include "litpool.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "optimize.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Names of the target systems sorted by target name */
+static const char* TargetNames [] = {
+    "none",
+    "atari",
+    "c64",
+    "c128",
+    "ace",
+    "plus4",
+    "cbm610",
+    "pet",
+    "nes",
+    "apple2",
+    "geos",
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+static void usage (int ExitCode)
+{
+    fputs ("Usage: cc65 [options] file\n"
+          "\t-d\t\tDebug mode\n"
+          "\t-g\t\tAdd debug info to object files\n"
+          "\t-h\t\tPrint this help\n"
+          "\t-j\t\tDefault characters are signed\n"
+          "\t-o name\t\tName the output file\n"
+          "\t-tx\t\tSet target system x\n"
+          "\t-v\t\tVerbose mode\n"
+          "\t-A\t\tStrict ANSI mode\n"
+          "\t-Cl\t\tMake local variables static\n"
+          "\t-Dsym[=defn]\tDefine a symbol\n"
+          "\t-I path\t\tSet include directory\n"
+          "\t-O\t\tOptimize code\n"
+          "\t-Oi\t\tOptimize code, inline more code\n"
+          "\t-Or\t\tEnable register variables\n"
+          "\t-Os\t\tInline some known functions\n"
+          "\t-T\t\tInclude source as comment\n"
+          "\t-V\t\tPrint version number\n"
+          "\t-W\t\tSuppress warnings\n",
+          stderr);
+    exit (ExitCode);
+}
+
+
+
+static char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+    char* Arg = argv [*ArgNum];
+    if (Arg [Len] != '\0') {
+       /* Argument appended */
+       return Arg + Len;
+    } else {
+       /* Separate argument */
+       Arg = argv [*ArgNum + 1];
+       if (Arg == 0) {
+           /* End of arguments */
+           fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+           exit (EXIT_FAILURE);
+       }
+       ++(*ArgNum);
+       return Arg;
+    }
+}
+
+
+
+/* Define a CBM system */
+static void cbmsys (const char* sys)
+{
+    AddNumericMacro ("__CBM__", 1);
+    AddNumericMacro (sys, 1);
+}
+
+
+
+static int MapSys (const char* Name)
+/* Map a target name to a system code. Return -1 in case of an error */
+{
+    unsigned I;
+
+    /* Check for a numeric target */
+    if (isdigit (*Name)) {
+       int Target = atoi (Name);
+       if (Target >= 0 && Target < TGT_COUNT) {
+           return Target;
+       }
+    }
+
+    /* Check for a target string */
+    for (I = 0; I < TGT_COUNT; ++I) {
+       if (strcmp (TargetNames [I], Name) == 0) {
+           return I;
+       }
+    }
+    /* Not found */
+    return -1;
+}
+
+
+
+/* Define a target system */
+static void SetSys (const char* Sys)
+{
+    switch (Target = MapSys (Sys)) {
+
+       case TGT_NONE:
+           break;
+
+       case TGT_ATARI:
+           AddNumericMacro ("__ATARI__", 1);
+           break;
+
+       case TGT_C64:
+           cbmsys ("__C64__");
+           break;
+
+       case TGT_C128:
+           cbmsys ("__C128__");
+           break;
+
+       case TGT_ACE:
+           cbmsys ("__ACE__");
+           break;
+
+       case TGT_PLUS4:
+           cbmsys ("__PLUS4__");
+           break;
+
+       case TGT_CBM610:
+           cbmsys ("__CBM610__");
+           break;
+
+       case TGT_PET:
+           cbmsys ("__PET__");
+           break;
+
+       case TGT_NES:
+           AddNumericMacro ("__NES__", 1);
+           break;
+
+       case TGT_APPLE2:
+           AddNumericMacro ("__APPLE2__", 1);
+           break;
+
+       case TGT_GEOS:
+           /* Do not handle as a CBM system */
+           AddNumericMacro ("__GEOS__", 1);
+           break;
+
+       default:
+           fputs ("Unknown system type\n", stderr);
+           usage (EXIT_FAILURE);
+    }
+}
+
+
+
+static void InvSym (const char* Def)
+/* Print an error about an invalid macro definition and die */
+{
+    fprintf (stderr, "Invalid macro definition: `%s'\n", Def);
+    exit (EXIT_FAILURE);
+}
+
+
+
+static void DefineSym (const char* Def)
+/* Define a symbol on the command line */
+{
+    const char* P = Def;
+
+    /* The symbol must start with a character or underline */
+    if (Def [0] != '_' && !isalpha (Def [0])) {
+       InvSym (Def);
+    }
+
+    /* Check the symbol name */
+    while (isalnum (*P) || *P == '_') {
+       ++P;
+    }
+
+    /* Do we have a value given? */
+    if (*P != '=') {
+       if (*P != '\0') {
+           InvSym (Def);
+       }
+       /* No value given. Define the macro with the value 1 */
+       AddNumericMacro (Def, 1);
+    } else {
+       /* We have a value, P points to the '=' character. Since the argument
+        * is const, create a copy and replace the '=' in the copy by a zero
+        * terminator.
+                */
+       char* Q;
+       unsigned Len = strlen (Def)+1;
+       char* S = xmalloc (Len);
+       memcpy (S, Def, Len);
+       Q = S + (P - Def);
+       *Q++ = '\0';
+
+       /* Define this as a macro */
+       AddTextMacro (S, Q);
+
+       /* Release the allocated memory */
+       xfree (S);
+    }
+}
+
+
+
+static void Parse (void)
+/* Process all input text.
+ * At this level, only static declarations, defines, includes, and function
+ * definitions are legal....
+ */
+{
+    int comma;
+    SymEntry* Entry;
+
+    kill ();
+    gettok ();                 /* "prime" the pump */
+    gettok ();
+    while (curtok != CEOF) {
+
+       DeclSpec        Spec;
+       Declaration     Decl;
+       int             NeedStorage;
+
+       /* Check for an ASM statement (which is allowed also on global level) */
+       if (curtok == ASM) {
+           doasm ();
+           ConsumeSemi ();
+           continue;
+       }
+
+       /* Check for a #pragma */
+       if (curtok == PRAGMA) {
+           DoPragma ();
+           continue;
+       }
+
+               /* Read variable defs and functions */
+       ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
+
+       /* Don't accept illegal storage classes */
+       if (Spec.StorageClass == SC_AUTO || Spec.StorageClass == SC_REGISTER) {
+           Error (ERR_ILLEGAL_STORAGE_CLASS);
+           Spec.StorageClass = SC_EXTERN | SC_STATIC;
+       }
+
+       /* Check if this is only a type declaration */
+       if (curtok == SEMI) {
+           gettok ();
+           continue;
+       }
+
+               /* Check if we must reserve storage for the variable. We do
+        * this if we don't had a storage class given ("int i") or
+        * if the storage class is explicitly specified as static.
+        * This means that "extern int i" will not get storage
+        * allocated.
+        */
+       NeedStorage = (Spec.StorageClass & SC_TYPEDEF) == 0 &&
+                     ((Spec.Flags & DS_DEF_STORAGE) != 0  ||
+                     (Spec.StorageClass & (SC_STATIC | SC_EXTERN)) == SC_STATIC);
+
+       /* Read declarations for this type */
+       Entry = 0;
+       comma = 0;
+               while (1) {
+
+           unsigned SymFlags;
+
+           /* Read the next declaration */
+           ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+           if (Decl.Ident[0] == '\0') {
+               gettok ();
+               break;
+           }
+
+           /* Get the symbol flags */
+           SymFlags = Spec.StorageClass;
+           if (IsFunc (Decl.Type)) {
+               SymFlags |= SC_FUNC;
+           } else {
+               if (NeedStorage) {
+                   /* We will allocate storage, variable is defined */
+                   SymFlags |= SC_STORAGE | SC_DEF;
+               }
+           }
+
+           /* Add an entry to the symbol table */
+           Entry = AddGlobalSym (Decl.Ident, Decl.Type, SymFlags);
+
+           /* Reserve storage for the variable if we need to */
+                   if (SymFlags & SC_STORAGE) {
+
+               /* Get the size of the variable */
+               unsigned Size = SizeOf (Decl.Type);
+
+               /* Allow initialization */
+               if (curtok == ASGN) {
+
+                   /* We cannot initialize types of unknown size, or
+                    * void types in non ANSI mode.
+                    */
+                           if (Size == 0) {
+                       if (!IsVoid (Decl.Type)) {
+                           if (!IsArray (Decl.Type)) {
+                               /* Size is unknown and not an array */
+                               Error (ERR_UNKNOWN_SIZE);
+                           }
+                       } else if (ANSI) {
+                           /* We cannot declare variables of type void */
+                           Error (ERR_ILLEGAL_TYPE);
+                       }
+                   }
+
+                   /* Switch to the data segment */
+                   g_usedata ();
+
+                   /* Define a label */
+                   g_defgloblabel (Entry->Name);
+
+                   /* Skip the '=' */
+                   gettok ();
+
+                   /* Parse the initialization */
+                   ParseInit (Entry->Type);
+               } else {
+
+                   if (IsVoid (Decl.Type)) {
+                       /* We cannot declare variables of type void */
+                       Error (ERR_ILLEGAL_TYPE);
+                   } else if (Size == 0) {
+                       /* Size is unknown */
+                       Error (ERR_UNKNOWN_SIZE);
+                   }
+
+                   /* Switch to the BSS segment */
+                   g_usebss ();
+
+                   /* Define a label */
+                   g_defgloblabel (Entry->Name);
+
+                   /* Allocate space for uninitialized variable */
+                   g_res (SizeOf (Entry->Type));
+               }
+
+           }
+
+           /* Check for end of declaration list */
+           if (curtok == COMMA) {
+               gettok ();
+               comma = 1;
+           } else {
+               break;
+           }
+       }
+
+       /* Function declaration? */
+       if (IsFunc (Decl.Type)) {
+
+           /* Function */
+           if (!comma) {
+
+               if (curtok == SEMI) {
+
+                   /* Prototype only */
+                   gettok ();
+
+               } else {
+                   if (Entry) {
+                       NewFunc (Entry);
+                   }
+               }
+           }
+
+       } else {
+
+           /* Must be followed by a semicolon */
+           ConsumeSemi ();
+
+       }
+    }
+}
+
+
+
+static void Compile (void)
+/* Compiler begins execution here. inp is input fd, output is output fd. */
+{
+    char* Path;
+
+
+    /* Setup variables */
+    filetab[0].f_iocb = inp;
+    LiteralLabel = GetLabel ();
+
+    /* Add some standard paths to the include search path */
+    AddIncludePath ("", INC_USER);             /* Current directory */
+    AddIncludePath ("include", INC_SYS);
+#ifdef CC65_INC
+    /* Allow modifications of the given string by dup'ing it */
+    AddIncludePath (xstrdup (CC65_INC), INC_SYS);
+#else
+    AddIncludePath ("/usr/lib/cc65/include", INC_SYS);
+#endif
+    Path = getenv ("CC65_INC");
+    if (Path) {
+       AddIncludePath (Path, INC_SYS | INC_USER);
+    }
+
+    /* Add macros that are always defined */
+    AddNumericMacro ("__CC65__", (VER_MAJOR * 0x100) + (VER_MINOR * 0x10) + VER_PATCH);
+
+    /* Strict ANSI macro */
+    if (ANSI) {
+       AddNumericMacro ("__STRICT_ANSI__", 1);
+    }
+
+    /* Optimization macros */
+    if (Optimize) {
+       AddNumericMacro ("__OPT__", 1);
+       if (FavourSize == 0) {
+           AddNumericMacro ("__OPT_i__", 1);
+       }
+       if (EnableRegVars) {
+           AddNumericMacro ("__OPT_r__", 1);
+       }
+       if (InlineStdFuncs) {
+           AddNumericMacro ("__OPT_s__", 1);
+       }
+    }
+
+    /* Create the base lexical level */
+    EnterGlobalLevel ();
+
+    /* Generate the code generator preamble */
+    g_preamble ();
+
+    /* Ok, start the ball rolling... */
+    Parse ();
+
+    /* Dump literal pool. */
+    DumpLiteralPool ();
+
+    /* Write imported/exported symbols */
+    EmitExternals ();
+
+    if (Debug) {
+       PrintLiteralStats (stdout);
+       PrintMacroStats (stdout);
+    }
+
+    /* Leave the main lexical level */
+    LeaveGlobalLevel ();
+
+    /* Print an error report */
+    ErrorReport ();
+}
+
+
+
+int main (int argc, char **argv)
+{
+    int i;
+    char *argp;
+    char out_name [256];
+    char* p;
+
+    /* Initialize the output file name */
+    out_name [0] = '\0';
+
+    fin = NULL;
+
+    /* Parse the command line */
+    for (i = 1; i < argc; i++) {
+       if (*(argp = argv[i]) == '-') {
+           switch (argp[1]) {
+
+               case 'd':       /* debug mode */
+                   Debug = 1;
+                   break;
+
+               case 'h':
+               case '?':
+                   usage (EXIT_SUCCESS);
+                   break;
+
+               case 'g':
+                   DebugInfo = 1;
+                   break;
+
+               case 'j':
+                   SignedChars = 1;
+                   break;
+
+               case 'o':
+                   strcpy (out_name, GetArg (&i, argv, 2));
+                   break;
+
+               case 't':
+                   SetSys (GetArg (&i, argv, 2));
+                   break;
+
+               case 'v':
+                   ++Verbose;
+                   break;
+
+               case 'A':
+                   ANSI = 1;
+                   break;
+
+               case 'C':
+                   p = argp + 2;
+                   while (*p) {
+                       switch (*p++) {
+                           case 'l':
+                               LocalsAreStatic = 1;
+                               break;
+                       }
+                   }
+                   break;
+
+               case 'D':
+                   DefineSym (GetArg (&i, argv, 2));
+                   break;
+
+               case 'I':
+                   AddIncludePath (GetArg (&i, argv, 2), INC_SYS | INC_USER);
+                   break;
+
+               case 'O':
+                   Optimize = 1;
+                   p = argp + 2;
+                   while (*p) {
+                       switch (*p++) {
+                           case 'f':
+                               sscanf (p, "%lx", (long*) &OptDisable);
+                               break;
+                           case 'i':
+                               FavourSize = 0;
+                               break;
+                           case 'r':
+                               EnableRegVars = 1;
+                               break;
+                           case 's':
+                               InlineStdFuncs = 1;
+                               break;
+                       }
+                   }
+                   break;
+
+               case 'T':
+                   IncSource = 1;
+                   break;
+
+               case 'V':
+                   fprintf (stderr, "cc65 V%u.%u.%u\n",
+                            VER_MAJOR, VER_MINOR, VER_PATCH);
+                   break;
+
+               case 'W':
+                   NoWarn = 1;
+                   break;
+
+               default:
+                   fprintf (stderr, "Invalid option %s\n", argp);
+                   usage (EXIT_FAILURE);
+           }
+       } else {
+           if (fin) {
+               fprintf (stderr, "additional file specs ignored\n");
+           } else {
+               fin = xstrdup (argp);
+               inp = fopen (fin, "r");
+               if (inp == 0) {
+                   Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno));
+               }
+           }
+       }
+    }
+    if (!fin) {
+       fprintf (stderr, "%s: No input files\n", argv [0]);
+       exit (EXIT_FAILURE);
+    }
+
+    /* Create the output file name. We should really have
+     * some checks for string overflow, but I'll drop this because of the
+     * additional code size it would need (as in other places). Sigh.
+     */
+    if (out_name [0] == '\0') {
+       /* No output name given, create default */
+       strcpy (out_name, fin);
+       if ((p = strrchr (out_name, '.'))) {
+           *p = '\0';
+       }
+       strcat (out_name, ".s");
+    }
+
+    /* Go! */
+    Compile ();
+
+    /* Create the output file if we didn't had any errors */
+    if (ErrorCount == 0 || Debug) {
+
+       FILE* F;
+
+       /* Optimize the output if requested */
+       if (Optimize) {
+           OptDoOpt ();
+       }
+
+       /* Open the file */
+       F = fopen (out_name, "w");
+       if (F == 0) {
+           Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
+       }
+
+       /* Write the output to the file */
+       WriteOutput (F);
+
+       /* Close the file, check for errors */
+       if (fclose (F) != 0) {
+           remove (out_name);
+           Fatal (FAT_CANNOT_WRITE_OUTPUT);
+       }
+    }
+
+    /* Return an apropriate exit code */
+    return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
diff --git a/src/cc65/make/cc65.mak b/src/cc65/make/cc65.mak
new file mode 100644 (file)
index 0000000..6398d36
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# Makefile for CC65.COM.
+#
+
+.SUFFIXES: .o .obj .m65 .c
+
+.c.m65:
+       @echo $<
+       @cc65 -I../lib65/ -O -t4 $<
+
+.m65.obj:
+       ../ra65/ra65 -o $@ ../lib65/ace/global.m65 $<
+
+C_SRCS = code-gen.c error.c expr1.c expr2.c expr3.c function.c mem.c loop.c\
+        globlvar.c io.c scanner.c main.c optimize.c preproc.c\
+        stmt.c symtab.c util.c declare.c
+
+H_SRCS = cc65.h scanner.h error.h mem.h optimize.h code-gen.h function.h\
+         preproc.h util.h symtab.h io.h ctrans.h stmt.h declare.h loop.h\
+        expr.h
+
+M65_FILES = ccmisc.m65 extra.m65 rtextra.m65
+
+OBJS = code-gen.obj error.obj expr1.obj expr2.obj expr3.obj function.obj \
+       globlvar.obj io.obj scanner.obj main.obj\
+       optimize.obj preproc.obj stmt.obj symtab.obj declare.obj loop.obj\
+       ccmisc.obj extra.obj rtextra.obj ctrans.obj mem.obj util.obj
+
+cc65.com: $(OBJS)
+       @../ra65/link65 -t4 -m -o cc65.com ../lib65/ace/crt0.obj $(OBJS)\
+       ../lib65/ace.olb
+
+.PRECIOUS:     $(C_SRCS:.c=.m65)
+
+
+$(OBJS) : $(H_SRCS)
+
+clean :
+       rm -f $(OBJS)
+       rm -f $(C_SRCS:.c=.m65)
diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak
new file mode 100644 (file)
index 0000000..c50679a
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# Makefile for cross-compiler version of CC65.
+#
+
+
+# Default for the compiler lib search path as compiler define
+CDEFS=-DCC65_INC=\"/usr/lib/cc65/include/\"
+CFLAGS = -O2 -g -Wall $(CDEFS)
+CC=gcc
+LDFLAGS=
+
+OBJS = anonname.o      \
+       asmcode.o       \
+       asmlabel.o      \
+       asmline.o       \
+       check.o         \
+       codegen.o       \
+       ctrans.o        \
+       datatype.o      \
+       declare.o       \
+       error.o         \
+       expr.o          \
+       funcdesc.o      \
+       function.o      \
+       global.o        \
+       goto.o          \
+       hashstr.o       \
+       ident.o         \
+       include.o       \
+       io.o            \
+       litpool.o       \
+       locals.o        \
+       loop.o          \
+       macrotab.o      \
+       main.o          \
+       mem.o           \
+       optimize.o      \
+       preproc.o       \
+       pragma.o        \
+       scanner.o       \
+       stdfunc.o       \
+       stmt.o          \
+       symentry.o      \
+       symtab.o        \
+       util.o
+
+EXECS = cc65
+
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+
+cc65:  $(OBJS)
+       $(CC) $(LDFLAGS) -o cc65 $(CFLAGS) $(OBJS)
+
+clean:
+       rm -f *~ core *.map
+
+zap:   clean
+       rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
+
diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak
new file mode 100644 (file)
index 0000000..11966fd
--- /dev/null
@@ -0,0 +1,157 @@
+#
+# CC65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = anonname.obj    \
+       asmcode.obj     \
+       asmlabel.obj    \
+       asmline.obj     \
+       check.obj       \
+       codegen.obj     \
+       ctrans.obj      \
+       datatype.obj    \
+       declare.obj     \
+       error.obj       \
+       expr.obj        \
+       funcdesc.obj    \
+       function.obj    \
+       global.obj      \
+       goto.obj        \
+       hashstr.obj     \
+       ident.obj       \
+       include.obj     \
+       io.obj          \
+       litpool.obj     \
+       locals.obj      \
+       loop.obj        \
+       macrotab.obj    \
+       main.obj        \
+       mem.obj         \
+       optimize.obj    \
+       pragma.obj      \
+       preproc.obj     \
+       stmt.obj        \
+       scanner.obj     \
+       stdfunc.obj     \
+       symentry.obj    \
+       symtab.obj      \
+       util.obj
+
+
+.PRECIOUS $(OBJS:.obj=.c)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:           cc65
+
+cc65:          cc65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+cc65.exe:      $(OBJS)
+       $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE anonname.obj
+FILE asmcode.obj
+FILE asmlabel.obj
+FILE asmline.obj
+FILE check.obj
+FILE codegen.obj
+FILE ctrans.obj
+FILE datatype.obj
+FILE declare.obj
+FILE error.obj
+FILE expr.obj
+FILE funcact.obj
+FILE funcdesc.obj
+FILE function.obj
+FILE global.obj
+FILE goto.obj
+FILE hashstr.obj
+FILE ident.obj
+FILE include.obj
+FILE io.obj
+FILE litpool.obj
+FILE locals.obj
+FILE loop.obj
+FILE macrotab.obj
+FILE main.obj
+FILE mem.obj
+FILE optimize.obj
+FILE pragma.obj
+FILE preproc.obj
+FILE stmt.obj
+FILE scanner.obj
+FILE stdfunc.obj
+FILE symentry.obj
+FILE symtab.obj
+FILE util.obj
+|
+
diff --git a/src/cc65/mem.c b/src/cc65/mem.c
new file mode 100644 (file)
index 0000000..72b2291
--- /dev/null
@@ -0,0 +1,605 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                MEMCHECK.CC                                */
+/*                                                                           */
+/* (C) 1995     Ullrich von Bassewitz                                        */
+/*              Zwehrenbuehlstrasse 33                                       */
+/*              D-72070 Tuebingen                                            */
+/* EMail:       uz@ibb.schwaben.com                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+// Poor man's memory checker. Overloads the global operators new and delete
+// and does some additional checks if the variable MemCheck is set to true:
+//
+//      * Check if an allocated block is already allocated (heap corrupt)
+//      * Check if a block that should be freed is allocated
+//      * Check if there have been writes outside the blocks bounds (by
+//        adding a signature to the end)
+//      * Check if new does not provide a NULL pointer.
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef __WATCOMC__
+#  include <malloc.h>
+#endif
+
+#include "check.h"
+
+
+
+/*****************************************************************************/
+/*                                   Data                                    */
+/*****************************************************************************/
+
+
+
+typedef unsigned long u32;
+
+
+
+// Signature of a memory block
+static u32 MemSig = 0x12785634;
+
+// Switch memory checking on or off
+int MemCheck = 0;
+
+// Switch memory filling on or off
+int MemFill = 0;
+
+// Validation on each call?
+int MemValidate = 0;
+
+// Don't really free blocks
+int MemDontFree = 0;
+
+// Logfile for allocations/deallocations
+static const char* MemLogFile = 0;
+static FILE*       LogFile = 0;
+
+// Statistics
+u32 MemNewCount = 0;
+u32 MemDelCount = 0;
+u32 MemDelNULLCount = 0;
+u32 MemNewCheckCount = 0;
+u32 MemDelCheckCount = 0;
+u32 MemLargestBlock = 0;
+u32 MemUsage = 0;
+u32 MemMaxUsage = 0;
+
+// This is the fill value for memory blocks if MemFill is true. On intel
+// architectures, this is the code for "INT 3", an instruction that is
+// often used by debuggers as a breakpoint.
+unsigned char FillVal = 0xCC;
+
+
+
+/*****************************************************************************/
+/*                             struct BlockInfo                              */
+/*****************************************************************************/
+
+
+
+typedef struct {
+    unsigned char*  Ptr;
+    u32             Size;
+} BlockInfo;
+
+//
+const int FirstChunk    = 2000;
+const int Delta         = 1000;
+
+// Variables needed
+static int              IsInitialized = 0;
+static int              BlockCount = 0;
+static int              BlockLimit = 0;
+static BlockInfo*       Blocks = 0;
+
+
+
+/*****************************************************************************/
+/*                            class BlockInfoColl                            */
+/*****************************************************************************/
+
+
+
+static void MemSetCount (int NewCount)
+// Make shure, there is space for NewSize blocks in Blocks
+{
+    if (NewCount > BlockLimit) {
+        // OOPS, need realloc
+        if (BlockLimit == 0 && NewCount <= FirstChunk) {
+            BlockLimit = FirstChunk;
+        } else {
+            BlockLimit = ((NewCount / Delta) + 1) * Delta;
+        }
+        Blocks = (BlockInfo*) realloc (Blocks, BlockLimit * sizeof (BlockInfo));
+    }
+    BlockCount = NewCount;
+}
+
+
+
+static int MemSearch (const unsigned char* Ptr, int* Index)
+// Search for the block. Return 1 if the block is found (Index holds the
+// block index in this case). Return 0 if the block is not found and return
+// in Index the index where the block should be inserted.
+{
+    // do a binary search
+    int First = 0;
+    int Last = BlockCount - 1;
+    int Current;
+    int S = 0;
+
+    while (First <= Last) {
+
+        // Set current to mid of range
+        Current = (Last + First) / 2;
+
+        // Do a compare
+        if (Blocks [Current].Ptr < Ptr) {
+            First = Current + 1;
+        } else {
+            Last = Current - 1;
+            if (Blocks [Current].Ptr == Ptr) {
+                // Found.
+                S = 1;  // function result
+                // Set condition to terminate loop
+                First = Current;
+            }
+        }
+
+    }
+
+    *Index = First;
+    return S;
+}
+
+
+
+static void MemDelBlock (int Index)
+// Delete the block with the given index
+{
+    BlockCount--;
+    memmove (Blocks+Index, Blocks+Index+1, (BlockCount-Index) * sizeof (BlockInfo));
+}
+
+
+
+static void MemInsBlock (int Index, unsigned char* Ptr, u32 Size)
+{
+    // Set the new size
+    MemSetCount (BlockCount + 1);
+
+    // We can insert the element. If the item is not inserted at the end
+    // of the collection, we must create a "hole"
+    if (Index != BlockCount - 1) {
+        memmove (Blocks + Index + 1,
+                 Blocks + Index,
+                 (BlockCount - 1 - Index) * sizeof (BlockInfo));
+    }
+
+    // store the new data
+    Blocks [Index].Ptr  = Ptr;
+    Blocks [Index].Size = Size;
+}
+
+
+
+u32 MemBlocksInUse ()
+{
+    return (u32) BlockCount;
+}
+
+
+
+static void PrintContents (const void* B, unsigned Size, FILE* F)
+// Print the contents of the block
+{
+    unsigned I;
+    static const unsigned MaxPrint = 14;
+
+    const unsigned char* P = (const unsigned char*) B;
+    if (Size > MaxPrint) {
+        Size = MaxPrint;
+    }
+
+    // Two characters space
+    fprintf (F, "  ");
+
+    // Print the first few bytes in hex
+    for (I = 0; I < Size; I++) {
+        fprintf (F, "%02X ", P [I]);
+    }
+    fprintf (F, "%*s ", (MaxPrint-Size)*3, "");
+
+    // Print the bytes again in ASCII
+    for (I = 0; I < Size; I++) {
+        unsigned char C = P [I];
+        if (C < ' ' || C > 0x7E) {
+            C = '.';
+        }
+        putc (C, F);
+    }
+}
+
+
+
+void MemLogBlocksInUse (const char* Name)
+{
+    BlockInfo* Block;
+    int I;
+
+    FILE* F = fopen (Name, "w+t");
+    if (F == 0) {
+        // This is a debug function, so ignore the error
+        return;
+    }
+
+    // Get the block count and log some statistics
+    fprintf (F, "Blocks currently in use:               %8lu\n\n"
+                "Calls to operator new:                 %8lu\n"
+                "Calls to operator delete:              %8lu\n"
+                "Checked calls to new:                  %8lu\n"
+                "Checked calls to delete:               %8lu\n"
+                "Calls to delete with a NULL arg:       %8lu\n\n"
+                "Largest block allocated:               %8lu\n"
+                "Maximum memory usage:                  %8lu\n\n",
+                (unsigned long) BlockCount,
+                (unsigned long) MemNewCount,
+                (unsigned long) MemDelCount,
+                (unsigned long) MemNewCheckCount,
+                (unsigned long) MemDelCheckCount,
+                (unsigned long) MemDelNULLCount,
+                (unsigned long) MemLargestBlock,
+                (unsigned long) MemMaxUsage);
+
+    // Print a header
+    fprintf (F, "Num   Address  Size   Contents\n");
+    fprintf (F, "----------------------------------------"
+                "---------------------------------------\n");
+
+    // Log the blocks
+    Block = Blocks;
+    for (I = 0; I < BlockCount; I++, Block++) {
+
+        // Print a line describing the block (convert pointers to hex values)
+        fprintf (F, "%-5u %08lX %5lu",
+                 I, (unsigned long) Block->Ptr, (unsigned long) Block->Size);
+
+        // Print the first few bytes of the block
+        PrintContents (Block->Ptr, Block->Size, F);
+
+        // Check the block signature
+        if (memcmp (Block->Ptr + Block->Size, &MemSig, sizeof (MemSig)) != 0) {
+            // Signature overwritten
+            fprintf (F, " *** Signature overwritten ***\n");
+        } else {
+            fprintf (F, "\n");
+        }
+
+    }
+
+    // Close the file
+    fclose (F);
+}
+
+
+
+static long MemValidateBlocks ()
+// Validate all memory blocks. Return the index of a block where the
+// validation failed, otherwise return -1.
+{
+    // Validate the blocks
+    long I;
+    BlockInfo* Block = Blocks;
+    for (I = 0; I < BlockCount; I++, Block++) {
+
+        // Check the block signature
+        if (memcmp (Block->Ptr + Block->Size, &MemSig, sizeof (MemSig)) != 0) {
+            // Signature overwritten
+            return I;
+        }
+    }
+
+    // All is well...
+    return -1;
+}
+
+
+
+static void MemDone ()
+// Log the memory blocks if requested. Does *not* delete the block array
+// since the startup code may release memory after calling the exit functions
+// and in this case we will work with a freed block, if we free the block
+// array here
+{
+    // If the environment variable MEMLOGBLOCKS is set to something, use
+    // this "something" as a filename to log a list of still allocated blocks
+    const char* Name = getenv ("MEMLOGBLOCKS");
+    if (Name) {
+        MemLogBlocksInUse (Name);
+    }
+}
+
+
+
+static void MemInit ()
+// Initialize the memory checker.
+{
+    // Get the defaults for the memory checker
+    const char* Fill;
+    MemCheck    = getenv ("MEMCHECK") != 0;
+    MemValidate = getenv ("MEMVALIDATE") != 0;
+    MemDontFree = getenv ("MEMDONTFREE") != 0;
+    MemLogFile  = getenv ("MEMLOGFILE");
+    Fill        = getenv ("MEMFILL");
+    if (Fill) {
+        MemFill = 1;
+        if (isdigit (*Fill)) {
+            FillVal = atoi (Fill);
+        }
+    }
+
+    // Open the logfile if set
+    if (MemLogFile) {
+        LogFile = fopen (MemLogFile, "w+t");
+    }
+
+    // Register the exit function
+    atexit (MemDone);
+
+    // Initialized now (maybe set already)
+    IsInitialized = 1;
+}
+
+
+
+/*****************************************************************************/
+/*                           Allocate/free blocks                            */
+/*****************************************************************************/
+
+
+
+static void* MemAlloc (size_t Size)
+{
+    unsigned char* Ptr;
+
+    // Last allocated block is remembered here
+    static void* LastBlock = 0;
+
+    // Initialize the memory checker on the first call
+    if (IsInitialized == 0) {
+        MemInit ();
+    }
+
+    // Count the calls to new
+    MemNewCount++;
+
+    // Update largest block info
+    if (Size > MemLargestBlock) {
+        MemLargestBlock = Size;
+    }
+    if (MemCheck) {
+
+        int Index;
+
+        // Count the checked calls
+        MemNewCheckCount++;
+
+        // If we need to validate all blocks, do that
+        if (MemValidate) {
+            long I = MemValidateBlocks ();
+            if (I != -1) {
+                // We have a problem. Be shure to switch of MemValidate before
+                // calling FAIL, otherwise we will get an endless loop...
+                MemValidate = 0;
+                FAIL ("MemCheck: Block signature overwritten!");
+            }
+        }
+
+        // Update memory usage
+        MemUsage += Size;
+        if (MemUsage > MemMaxUsage) {
+            MemMaxUsage = MemUsage;
+        }
+
+        // Get a memory block
+        Ptr = (unsigned char*) malloc (Size + sizeof (MemSig));
+
+        // Make a signature at the end of the block
+        memcpy (Ptr + Size, &MemSig, sizeof (MemSig));
+
+        // Search for the block
+        if (MemSearch (Ptr, &Index) != 0) {
+            // An item with this key exists. This means that the heap is
+            // corrupted
+            FAIL ("MemCheck: Duplicate block!");
+        } else {
+            // The returned pointer is not in the collection of already
+            // allocated blocks, but it may point inside of an already
+            // allocated block. Check this.
+            // Note: Index is the index of the item _before the given
+            // pointer, so simply check the range of the entry with index
+            // Index.
+            if (Index > 0) {
+                // There is a block that's memory address is less than the
+                // one returned by malloc
+                const BlockInfo* BB = Blocks + Index - 1;
+                if (Ptr < BB->Ptr + BB->Size) {
+                    // Pointer points inside the block below - heap corrupted
+                    FAIL ("MemCheck: Heap corrupt!");
+                }
+            }
+
+            // Heap ok, insert the new block
+            MemInsBlock (Index, Ptr, Size);
+        }
+
+    } else {
+
+        // No memory checking. Allocate a memory block, but beware: New is
+        // defined so that "new char [0]" points to a distinct object every
+        // time it is called, so one cannot return NULL for a size of 0!
+        Ptr = (unsigned char*) malloc (Size ? Size : 1);
+
+    }
+
+    // Remember the last block
+    LastBlock = Ptr;
+
+    // Check if we got memory, fail otherwise
+    if (Ptr == 0) {
+        FAIL ("MemCheck: Out of memory");
+    }
+
+    // Fill the memory block if requested
+    if (MemFill) {
+        memset (Ptr, FillVal, Size);
+    }
+
+    // Log the allocation if requested
+    if (LogFile) {
+        // Print a line describing the block (convert pointers to hex values)
+        fprintf (LogFile, "A      %08lX %5lu",
+                 (unsigned long) Ptr, (unsigned long) Size);
+
+        // Print the first few bytes of the block
+        PrintContents (Ptr, Size, LogFile);
+        fprintf (LogFile, "\n");
+    }
+
+    // Return a pointer to the memory block
+    return Ptr;
+}
+
+
+
+static void MemFree (void* P)
+{
+    // We cannot call delete if the memory system is not initialized
+    if (IsInitialized == 0) {
+        FAIL ("MemCheck: Trying to delete a block before the first call to new!");
+    }
+
+    // Count the calls to delete
+    MemDelCount++;
+
+    // Deleting NULL pointers is always ok, nothing has to be done
+    if (P == 0) {
+        MemDelNULLCount++;
+        return;
+    }
+
+    if (MemCheck) {
+
+        int Index;
+        unsigned char* Ptr;
+
+        // Count the calls
+        MemDelCheckCount++;
+
+        // If we need to validate all blocks, do that
+        if (MemValidate) {
+            long I = MemValidateBlocks ();
+            if (I != -1) {
+                // We have a problem. Be shure to switch of MemValidate before
+                // calling FAIL, otherwise we will get an endless loop...
+                MemValidate = 0;
+                FAIL ("MemCheck: Block signature overwritten!");
+            }
+        }
+
+        // Cast the pointer
+        Ptr = (unsigned char*) P;
+
+        // Search for the block
+        if (MemSearch (Ptr, &Index) != 0) {
+
+            // The block exists.
+            BlockInfo* BI = Blocks + Index;
+
+            // Log the deallocation if requested
+            if (LogFile) {
+                // Print a line describing the block (convert pointers to hex values)
+                fprintf (LogFile, "D      %08lX %5lu",
+                         (unsigned long) BI->Ptr, (unsigned long) BI->Size);
+
+                // Print the first few bytes of the block
+                PrintContents (BI->Ptr, BI->Size, LogFile);
+                fprintf (LogFile, "\n");
+            }
+
+            // Check the signature
+            if (memcmp (Ptr + BI->Size, &MemSig, sizeof (MemSig)) != 0) {
+                // Signature overwritten
+                FAIL ("MemCheck: Block signature overwritten");
+            }
+
+            // Fill the memory block if requested
+            if (MemFill) {
+                memset (Ptr, FillVal, BI->Size);
+            }
+
+            // Should the block really be freed?
+            if (MemDontFree == 0) {
+
+                // Update memory usage
+                MemUsage -= BI->Size;
+
+                // Delete the entry
+                MemDelBlock (Index);
+
+                // Delete the memory block
+                free (P);
+
+            }
+
+        } else {
+            // Trying to free a block that is not allocated
+            FAIL ("MemCheck: Trying to free a block that is not allocated");
+        }
+    } else {
+
+        // Free the block without checks
+        free (P);
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                   Code                                    */
+/*****************************************************************************/
+
+
+
+void* xmalloc (size_t Size)
+{
+    return MemAlloc (Size);
+}
+
+
+
+void xfree (const void* P)
+{
+    MemFree ((void*)P);
+}
+
+
+
+char* xstrdup (const char* S)
+{
+    unsigned Len = strlen (S) + 1;
+    return memcpy (xmalloc (Len), S, Len);
+}
+
+
+
diff --git a/src/cc65/mem.h b/src/cc65/mem.h
new file mode 100644 (file)
index 0000000..7cbfa8c
--- /dev/null
@@ -0,0 +1,76 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.h                                   */
+/*                                                                           */
+/*             Safe memory allocation for the cc65 C compiler               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+extern size_t memmax;
+
+
+
+/*****************************************************************************/
+/*                                          code                                    */
+/*****************************************************************************/
+
+
+
+void* xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* xstrdup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+#endif
+
+
+
diff --git a/src/cc65/optimize.c b/src/cc65/optimize.c
new file mode 100644 (file)
index 0000000..3119311
--- /dev/null
@@ -0,0 +1,4182 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               optimize.c                                 */
+/*                                                                           */
+/*                  An optimizer for the cc65 C compiler                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "asmlabel.h"
+#include "asmline.h"
+#include "check.h"
+#include "error.h"
+#include "global.h"
+#include "io.h"
+#include "mem.h"
+#include "optimize.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Bitset of flags that switch the different optimizer passes */
+unsigned long OptDisable       = 0;
+
+
+
+/* Bitmapped flags for the Flags field in the Line struct */
+#define OF_CODE                0x0001          /* This line is in a code segment */
+
+/* Pointer to first code line */
+static Line*           FirstCode;
+
+/* Label list */
+static Line**          Labels = 0;     /* Pointers to label lines */
+static unsigned                LabelCount = 0; /* Count of local labels found */
+
+/* A collection of lines */
+typedef struct LineColl_ LineColl;
+struct LineColl_ {
+    unsigned   Count;                  /* Count of lines in the collection */
+    unsigned   Max;                    /* Maximum count of lines */
+    Line*      Lines[1];               /* Lines, dynamically allocated */
+};
+
+
+
+/* Calculate the element count of a table */
+#define COUNT(T)       (sizeof (T) / sizeof (T [0]))
+
+/* Macro to increment and decrement register contents if they're valid */
+#define INC(reg,val)    if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
+#define DEC(reg,val)           if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
+
+/* Defines for the conditions in a compare */
+#define CMP_EQ         0
+#define CMP_NE         1
+#define CMP_GT         2
+#define CMP_GE         3
+#define CMP_LT         4
+#define CMP_LE         5
+#define CMP_UGT                6
+#define CMP_UGE                7
+#define CMP_ULT                8
+#define CMP_ULE                9
+
+/* Defines for registers */
+#define REG_NONE       0x00
+#define REG_A          0x01
+#define REG_X          0x02
+#define REG_Y          0x04
+#define        REG_AX          (REG_A | REG_X)
+#define REG_ALL                (REG_A | REG_X | REG_Y)
+
+/* Description of the commands */
+static const struct {
+    const char*        Insn;           /* Instruction */
+    unsigned char      FullMatch;      /* Match full instuction? */
+    unsigned char      Use;            /* Registers used */
+    unsigned char      Load;           /* Registers loaded */
+} CmdDesc [] = {
+    { "\tadc\t",                 0,    REG_A,      REG_NONE      },
+    { "\tand\t",                 0,    REG_A,      REG_NONE      },
+    { "\tasl\ta",         1,           REG_A,      REG_NONE      },
+    { "\tasl\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tclc",                   1,    REG_NONE,   REG_NONE      },
+    { "\tcld",           1,    REG_NONE,   REG_NONE      },
+    { "\tcli",                   1,    REG_NONE,   REG_NONE      },
+    { "\tcmp\t",                 0,    REG_A,      REG_NONE      },
+    { "\tcpx\t",                 0,    REG_X,      REG_NONE      },
+    { "\tcpy\t",                 0,    REG_Y,      REG_NONE      },
+    { "\tdec\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tdex",                   1,    REG_X,      REG_NONE      },
+    { "\tdey",                   1,    REG_Y,      REG_NONE      },
+    { "\teor\t",                 0,    REG_A,      REG_NONE      },
+    { "\tinc\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tinx",                   1,    REG_X,      REG_NONE      },
+    { "\tiny",                   1,    REG_Y,      REG_NONE      },
+    { "\tjsr\tbool",             0,    REG_NONE,   REG_AX        },
+    { "\tjsr\tdecaxy",   1,    REG_ALL,    REG_AX        },
+    { "\tjsr\tdecax",            0,    REG_AX,     REG_AX        },
+    { "\tjsr\tldax0sp",   1,           REG_Y,      REG_AX        },
+    { "\tjsr\tldaxysp",   1,           REG_Y,      REG_AX        },
+    { "\tjsr\tpusha",            1,    REG_A,      REG_Y         },
+    { "\tjsr\tpusha0",           1,    REG_A,      REG_X | REG_Y },
+    { "\tjsr\tpushax",           1,    REG_AX,     REG_Y         },
+    { "\tjsr\tpushw0sp",  1,           REG_NONE,   REG_ALL       },
+    { "\tjsr\tpushwysp",  1,           REG_Y,      REG_ALL       },
+    { "\tjsr\ttosicmp",   1,           REG_AX,     REG_ALL       },
+    { "\tlda\t",                 0,    REG_NONE,   REG_A         },
+    { "\tldax\t",         0,           REG_NONE,   REG_AX        },
+    { "\tldx\t",                 0,    REG_NONE,   REG_X         },
+    { "\tldy\t",                 0,    REG_NONE,   REG_Y         },
+    { "\tlsr\ta",         1,           REG_A,      REG_NONE      },
+    { "\tlsr\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tnop",                   1,    REG_NONE,   REG_NONE      },
+    { "\tora\t",                 0,    REG_A,      REG_NONE      },
+    { "\tpha",                   1,    REG_A,      REG_NONE      },
+    { "\tphp",                   1,    REG_NONE,   REG_NONE      },
+    { "\tpla",                   1,    REG_NONE,   REG_A         },
+    { "\tplp",                   1,    REG_NONE,   REG_NONE      },
+    { "\trol\ta",        1,    REG_A,      REG_A         },
+    { "\trol\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tror\ta",        1,    REG_A,      REG_A         },
+    { "\tror\t",                 0,    REG_NONE,   REG_NONE      },
+    { "\tsbc\t",                 0,    REG_A,      REG_NONE      },
+    { "\tsec",           1,    REG_NONE,   REG_NONE      },
+    { "\tsed",           1,    REG_NONE,   REG_NONE      },
+    { "\tsei",           1,    REG_NONE,   REG_NONE      },
+    { "\tsta\t",                 0,    REG_A,      REG_NONE      },
+    { "\tstx\t",                 0,    REG_X,      REG_NONE      },
+    { "\tsty\t",                 0,    REG_Y,      REG_NONE      },
+    { "\ttax",                   1,    REG_A,      REG_X         },
+    { "\ttay",                   1,    REG_A,      REG_Y         },
+    { "\ttsx",                   1,    REG_NONE,   REG_X         },
+    { "\ttxa",                   1,    REG_X,      REG_A         },
+    { "\ttya",                   1,    REG_Y,      REG_A         },
+};
+
+
+
+/* Table with the compare suffixes */
+static const char CmpSuffixTab [][4] = {
+    "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
+};
+
+/* Table used to invert a condition, indexed by condition */
+static const unsigned char CmpInvertTab [] = {
+    CMP_NE, CMP_EQ,
+    CMP_LE, CMP_LT, CMP_GE, CMP_GT,
+    CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
+};
+
+/* Table to show which compares are signed (use the N flag) */
+static const char CmpSignedTab [] = {
+    0, 0, 1, 1, 1, 1, 0, 0, 0, 0
+};
+
+
+
+/* Lists of branches */
+static const char* ShortBranches [] = {
+    "\tbeq\t",
+    "\tbne\t",
+    "\tbpl\t",
+    "\tbmi\t",
+    "\tbcc\t",
+    "\tbcs\t",
+    "\tbvc\t",
+    "\tbvs\t",
+    0
+};
+static const char* LongBranches [] = {
+    "\tjeq\t",
+    "\tjne\t",
+    "\tjpl\t",
+    "\tjmi\t",
+    "\tjcc\t",
+    "\tjcs\t",
+    "\tjvc\t",
+    "\tjvs\t",
+    0
+};
+
+
+
+/*****************************************************************************/
+/*                                        Forwards                                  */
+/*****************************************************************************/
+
+
+
+static unsigned EstimateSize (Line* L);
+/* Estimate the size of an instruction */
+
+static int IsLocalLabel (const Line* L);
+/* Return true if the line is a local label line */
+
+static unsigned GetLabelNum (const char* L);
+/* Return the label number of a label line */
+
+static unsigned RVUInt1 (Line* L, LineColl* LC, unsigned Used, unsigned Unused);
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+
+
+
+/*****************************************************************************/
+/*                                       List stuff                                 */
+/*****************************************************************************/
+
+
+
+static Line* NewLineAfter (Line* LineBefore, const char* Format, ...)
+/* Create a new line, insert it after L and return it. The new line is marked
+ * as code line.
+ */
+{
+    Line* L;
+
+    /* Format the new line and add it */
+    va_list ap;
+    va_start (ap, Format);
+    L = NewCodeLineAfter (LineBefore, Format, ap);
+    va_end (ap);
+
+    /* Make the line a code line */
+    L->Flags = OF_CODE;
+
+    /* Estimate the code size */
+    L->Size = EstimateSize (L);
+
+    /* Return the new line */
+    return L;
+}
+
+
+
+static Line* NewLabelAfter (Line* L, unsigned Label)
+/* Add a new line with a definition of a local label after the line L */
+{
+    char Buf [32];
+
+    /* Create the label */
+    sprintf (Buf, "L%04X:", Label);
+
+    /* Create a new line */
+    L = NewLineAfter (L, Buf);
+
+    /* Insert this label into the label list */
+    Labels [Label] = L;
+
+    /* Return the new line */
+    return L;
+}
+
+
+
+static void FreeLine (Line* L)
+/* Remove a line from the list and free it */
+{
+    /* If this is a label line, remove it from the label list */
+    if (IsLocalLabel (L)) {
+               Labels [GetLabelNum (L->Line)] = 0;
+    }
+
+    /* Unlink the line */
+    FreeCodeLine (L);
+}
+
+
+
+static Line* ReplaceLine (Line* L, const char* Format, ...)
+/* Replace one line by another */
+{
+    unsigned Len;
+    char S [256];
+
+    /* Format the new line */
+    va_list ap;
+    va_start (ap, Format);
+    vsprintf (S, Format, ap);
+    va_end (ap);
+
+    /* Get the length of the new line */
+    Len = strlen (S);
+
+    /* We can copy the line if the old line has space enough */
+    if (Len <= L->Len) {
+
+               /* Just copy the new line, but don't update the length */
+               memcpy (L->Line, S, Len);
+               L->Line [Len] = '\0';
+
+    } else {
+
+       /* We must allocate new space */
+       Line* NewLine = xmalloc (sizeof (Line) + Len);
+
+               /* Set the values in the new struct */
+       NewLine->Flags  = L->Flags;
+       NewLine->Index  = L->Index;
+       NewLine->Size   = L->Size;              /* Hmm ... */
+       NewLine->Len    = Len;
+       memcpy (NewLine->Line, S, Len + 1);
+
+       /* Replace the old struct in the list */
+               NewLine->Next = L->Next;
+       if (NewLine->Next) {
+           NewLine->Next->Prev = NewLine;
+       } else {
+           /* Last line */
+           LastLine = NewLine;
+               }
+               NewLine->Prev = L->Prev;
+       if (NewLine->Prev) {
+           NewLine->Prev->Next = NewLine;
+       } else {
+           /* First line */
+           FirstLine = NewLine;
+       }
+
+       /* Free the old struct */
+       xfree (L);
+       L = NewLine;
+    }
+
+    /* Estimate the new size */
+    if (L->Flags & OF_CODE) {
+               L->Size = EstimateSize (L);
+    }
+
+    /* Return the line */
+    return L;
+}
+
+
+
+static Line* PrevCodeLine (Line* L)
+/* Return the previous line containing code */
+{
+    L = L->Prev;
+    while (L) {
+       if (L->Flags & OF_CODE && L->Line [0] != '+') {
+                   break;
+               }
+               L = L->Prev;
+    }
+    return L;
+}
+
+
+
+static Line* NextCodeSegLine (Line* L)
+/* Return the next line in the code segment */
+{
+    L = L->Next;
+    while (L) {
+               if (L->Flags & OF_CODE) {
+                   break;
+               }
+               L = L->Next;
+    }
+    return L;
+}
+
+
+
+static Line* NextCodeLine (Line* L)
+/* Return the next line containing code */
+{
+    L = L->Next;
+    while (L) {
+               if ((L->Flags & OF_CODE) != 0 && L->Line [0] != '+') {
+                   break;
+               }
+               L = L->Next;
+    }
+    return L;
+}
+
+
+
+static Line* NextInstruction (Line* L)
+/* Return the next line containing code, ignoring labels. */
+{
+    do {
+       L = NextCodeLine (L);
+    } while (L && (L->Line[0] == '+' || IsLocalLabel(L)));
+    return L;
+}
+
+
+
+static void FreeLines (Line* Start, Line* End)
+/* Delete all lines from Start to End, both inclusive */
+{
+    Line* L;
+    do {
+               L = Start;
+               Start = NextCodeSegLine (Start);
+               FreeLine (L);
+    } while (L != End);
+}
+
+
+
+/*****************************************************************************/
+/*                          Line Collections                                */
+/*****************************************************************************/
+
+
+
+static LineColl* NewLineColl (unsigned Size)
+/* Create a new line collection and return it */
+{
+    /* Allocate memory */
+    LineColl* LC = xmalloc (sizeof (LineColl) + sizeof (Line) * (Size-1));
+
+    /* Initialize members */
+    LC->Count = 0;
+    LC->Max   = Size;
+
+    /* Return the new collection */
+    return LC;
+}
+
+
+
+static void FreeLineColl (LineColl* LC)
+/* Delete a line collection */
+{
+    xfree (LC);
+}
+
+
+
+static int LCAddLine (LineColl* LC, Line* L)
+/* Add a line. Return 0 if no space available, return 1 otherwise */
+{
+    /* Check if there is enough space available */
+    if (LC->Count >= LC->Max) {
+       /* No room available */
+       return 0;
+    }
+
+    /* Add the line */
+    LC->Lines [LC->Count++] = L;
+
+    /* Done */
+    return 1;
+}
+
+
+
+static int LCHasLine (LineColl* LC, Line* L)
+/* Check if the given line is in the collection */
+{
+    unsigned I;
+    for (I = 0; I < LC->Count; ++I) {
+       if (LC->Lines[I] == L) {
+           return 1;
+       }
+    }
+    return 0;
+}
+
+
+
+/*****************************************************************************/
+/*                             Test a line for several things                       */
+/*****************************************************************************/
+
+
+
+static int IsLocalLabel (const Line* L)
+/* Return true if the line is a local label line */
+{
+    return (L->Line [0] == 'L' && isxdigit (L->Line [1]));
+}
+
+
+
+static int IsLabel (const Line* L)
+/* Return true if the line is a label line */
+{
+    return (L->Line [0] == 'L' && isxdigit (L->Line [1])) ||
+          (L->Line [0] == '_');;
+}
+
+
+
+static int IsHintLine (const Line* L)
+/* Return true if the line contains an optimizer hint */
+{
+    return L->Line [0] == '+';
+}
+
+
+
+static int IsSegHint (const Line* L)
+/* Return true if the given line contains a segment hint */
+{
+    return (L->Line [0] == '+' && strncmp (L->Line + 1, "seg:", 4) == 0);
+}
+
+
+
+static int IsHint (const Line* L, const char* Hint)
+/* Check if the line contains a given hint */
+{
+    return (L->Line [0] == '+' && strcmp (L->Line + 1, Hint) == 0);
+}
+
+
+
+static int IsCondJump (Line* L)
+/* Return true if the line contains a conditional jump */
+{
+    return (L->Line [0] == '\t' &&
+           (strncmp (L->Line + 1, "beq\t", 4) == 0 ||
+            strncmp (L->Line + 1, "bne\t", 4) == 0 ||
+            strncmp (L->Line + 1, "jeq\t", 4) == 0 ||
+            strncmp (L->Line + 1, "jne\t", 4) == 0));
+}
+
+
+
+static int IsXIndAddrMode (Line* L)
+/* Return true if the given line does use the X register */
+{
+    unsigned Len = strlen (L->Line);
+    return (strcmp (L->Line + Len - 3, ",x)") == 0 ||
+           strcmp (L->Line + Len - 2, ",x")  == 0);
+}
+
+
+
+static int NoXIndAddrMode (Line* L)
+/* Return true if the given line does use the X register */
+{
+    return !IsXIndAddrMode (L);
+}
+
+
+
+static int IsYIndAddrMode (Line* L)
+/* Return true if the given line does use the Y register */
+{
+    unsigned Len = strlen (L->Line);
+    return (strcmp (L->Line + Len - 2, ",y") == 0);
+}
+
+
+
+static Line* FindHint (Line* L, const char* Hint)
+/* Search for a line with the given hint */
+{
+    while (L) {
+       if (IsHint (L, Hint)) {
+           break;
+               }
+       L = L->Next;
+    }
+    return L;
+}
+
+
+
+static unsigned GetHexNum (const char* S)
+/* Get a hex number from a string */
+{
+    unsigned I = 0;
+    unsigned Val = 0;
+    while (isxdigit (S [I])) {
+       int C = (unsigned char) (S [I++]);
+       if (C >= 'A') {
+           C -= 'A' - 10;
+       } else {
+           C -= '0';
+       }
+       Val = (Val << 4) + C;
+    }
+    return Val;
+}
+
+
+
+static unsigned GetLabelNum (const char* L)
+/* Return the label number of a label line */
+{
+    CHECK (*L == 'L');
+    return GetHexNum (L+1);
+}
+
+
+
+static Line* GetTargetLine (const char* L)
+/* Get the line with the target label of a jump. L must be a pointer to the
+ * string containing the label number.
+ */
+{
+    Line* Target;
+
+    /* Get the label number of the target */
+    unsigned Label = GetLabelNum (L);
+    CHECK (Label < LabelCount);
+
+    /* Get the line with this label */
+    Target = Labels [Label];
+    CHECK (Target != 0 && (Target->Flags & OF_CODE) != 0);
+
+    /* And return it */
+    return Target;
+}
+
+
+
+static unsigned GetJumpDistance (Line* L, Line* Target)
+/* Get the distance between both lines */
+{
+    unsigned Distance = 0;
+
+    if (L != Target) {
+       if (Target->Index > L->Index) {
+           /* This is a forward jump. */
+           do {
+               L = NextCodeLine (L);
+               Distance += L->Size;
+           } while (L != Target);
+       } else {
+           /* This is a backward jump */
+           do {
+               L = PrevCodeLine (L);
+               Distance += L->Size;
+           } while (L != Target);
+       }
+    }
+
+    /* Return the calculated distance */
+    return Distance;
+}
+
+
+
+static int LineMatch (const Line* L, const char* Start)
+/* Check if the start of the line matches Start */
+{
+    return strncmp (L->Line, Start, strlen (Start)) == 0;
+}
+
+
+
+static int LineFullMatch (const Line* L, const char* Start)
+/* Check if the matches Start */
+{
+    return strcmp (L->Line, Start) == 0;
+}
+
+
+
+static int LineMatchX (const Line* L, const char** Start)
+/* Check the start of the line against a list of patterns. Return the
+ * number of the pattern that matched, or -1 in case of no match.
+ */
+{
+    unsigned I = 0;
+    while (*Start) {
+       if (LineMatch (L, *Start)) {
+           /* Found */
+           return I;
+       }
+       ++Start;
+       ++I;
+    }
+    /* Not found */
+    return -1;
+}
+
+
+
+static int LineFullMatchX (const Line* L, const char** Start)
+/* Check the the line against a list of patterns. Return the
+ * number of the pattern that matched, or -1 in case of no match.
+ */
+{
+    unsigned I = 0;
+    while (*Start) {
+       if (LineFullMatch (L, *Start)) {
+           /* Found */
+           return I;
+       }
+       ++Start;
+       ++I;
+    }
+    /* Not found */
+    return -1;
+}
+
+
+
+static int IsLoadAX (Line* L1, Line* L2)
+/* Check if the both lines load a static variable into ax. That is, both lines
+ * look like
+ *     lda     x+0
+ *     ldx     x+0+1
+ */
+{
+    return LineMatch (L1, "\tlda\t")                                   &&
+          LineMatch (L2, "\tldx\t")                                    &&
+          strncmp (L1->Line+5, L2->Line+5, strlen (L1->Line+5)) == 0   &&
+          strcmp (L2->Line+strlen(L1->Line), "+1") == 0;
+}
+
+
+
+/*****************************************************************************/
+/*                         Initial optimizer setup                          */
+/*****************************************************************************/
+
+
+
+static void FindCodeStart (void)
+/* Find and remember the first line of actual code */
+{
+    Line* L = FindHint (FirstLine, "end_of_preamble");
+    FirstCode = L? L->Next : 0;
+}
+
+
+
+static unsigned EstimateDataSize (Line* L, unsigned Chunk)
+/* Estimate the size of a .byte, .word or .dword command */
+{
+    unsigned Size = Chunk;
+    char* S = L->Line;
+    while ((S = strchr (S, ',')) != 0) {
+       Size += Chunk;
+       ++S;
+    }
+    return Size;
+}
+
+
+
+static unsigned EstimateSize (Line* L)
+/* Estimate the size of an instruction */
+{
+    static const char* Transfers [] = {
+       "\ttax",
+       "\ttay",
+       "\ttsx",
+       "\ttxa",
+       "\ttya",
+       0
+    };
+    char OpStart;
+
+    if (L->Line [0] != '\t') {
+       return 0;
+    }
+    if (LineMatch (L, "\tldax\t")) {
+       /* Immidiate load of both, A and X */
+       return 4;
+    }
+    if (LineMatch (L, "\tld")) {
+       OpStart = L->Line [5];
+       return (OpStart == '#' || OpStart == '(')? 2 : 3;
+    }
+    if (LineMatch (L, "\tst")) {
+       OpStart = L->Line [5];
+       return (OpStart == '(')? 2 : 3;
+    }
+    if (LineMatch (L, "\t.byte\t")) {
+       return EstimateDataSize (L, 1);
+    }
+    if (LineMatch (L, "\t.word\t")) {
+       return EstimateDataSize (L, 2);
+    }
+    if (LineMatch (L, "\t.dword\t")) {
+       return EstimateDataSize (L, 4);
+    }
+    if (LineMatchX (L, ShortBranches) >= 0) {
+       return 2;
+    }
+    if (LineMatchX (L, LongBranches) >= 0) {
+       return 5;
+    }
+    if (LineMatchX (L, Transfers) >= 0) {
+       return 1;
+    }
+    return 3;
+}
+
+
+
+static void MarkCodeLines (void)
+/* Mark all lines that are inside a code segment */
+{
+    int InCode = 1;
+    Line* L = FirstCode;
+    while (L) {
+               if (IsSegHint (L)) {
+           InCode = IsHint (L, "seg:code");
+               } else if (InCode && L->Line[0] != '\0') {
+           L->Flags |= OF_CODE;
+                   L->Size = EstimateSize (L);
+       }
+       L = L->Next;
+    }
+}
+
+
+
+static void CreateLabelList (void)
+/* Create a list with pointers to local labels */
+{
+    unsigned I;
+    Line* L;
+
+
+    /* Get the next label number. This is also the current label count.
+     * Make some room for more labels when optimizing code.
+     */
+    LabelCount = GetLabel () + 100;
+
+    /* Allocate memory for the array and clear it */
+    Labels = xmalloc (LabelCount * sizeof (Line*));
+    for (I = 0; I < LabelCount; ++I) {
+               Labels [I] = 0;
+    }
+
+    /* Walk through the code and insert all label lines */
+    L = FirstLine;
+    while (L) {
+               if (IsLocalLabel (L)) {
+                   unsigned LabelNum = GetLabelNum (L->Line);
+                   CHECK (LabelNum < LabelCount);
+                   Labels [LabelNum] = L;
+               }
+               L = L->Next;
+    }
+}
+
+
+
+static unsigned AllocLabel (void)
+/* Get a new label. The current code does not realloc the label list, so there
+ * must be room enough in the current list.
+ */
+{
+    unsigned I;
+
+    /* Search for a free slot, start at 1, since 0 is "no label" */
+    for (I = 1; I < LabelCount; ++I) {
+       if (Labels[I] == 0) {
+           /* Found a free slot */
+           return I;
+       }
+    }
+
+    /* No label space available */
+    Internal ("Out of label space in the optimizer");
+
+    /* Not reached */
+    return 0;
+}
+
+
+
+/*****************************************************************************/
+/*                                    Helper functions                              */
+/*****************************************************************************/
+
+
+
+static int GetNextCodeLines (Line* L, Line** Lines, unsigned Count)
+/* Get a number of code lines ignoring hints and other stuff. The function
+ * returns 1 if we got the lines and 0 if we are at the end of the code
+ * segment or if we hit a label.
+ */
+{
+    while (Count--) {
+
+       /* Get the next valid line */
+       do {
+           L = NextCodeLine (L);
+       } while (L && IsHintLine (L));
+
+       /* Did we get one? */
+       if (L == 0 || IsLabel (L)) {
+           /* Error */
+           return 0;
+       }
+
+       /* Remember the line */
+       *Lines++ = L;
+    }
+
+    /* Success */
+    return 1;
+}
+
+
+
+static int FindCond (const char* Suffix)
+/* Map a condition suffix to a code. Return the code or -1 on failure */
+{
+    int I;
+
+    /* Linear search */
+    for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
+       if (strncmp (Suffix, CmpSuffixTab [I], strlen (CmpSuffixTab[I])) == 0) {
+           /* Found */
+           return I;
+       }
+    }
+
+    /* Not found */
+    return -1;
+}
+
+
+
+static int CheckAndGetIntCmp (const Line* JSR, const Line* JMP)
+/* Helper function to check for a compare subroutine call followed by a
+ * conditional branch. Will return the condition found, or -1 if no
+ * or invalid condition.
+ */
+{
+    char Cond[5];
+    const char* Tail;
+    int C;
+
+    /* Extract the condition from the function name. */
+    if ((Cond [0] = JSR->Line [8]) == 'u') {
+       Cond [1] = JSR->Line [9];
+       Cond [2] = JSR->Line [10];
+       Cond [3] = '\0';
+       Tail = JSR->Line + 11;
+    } else {
+       Cond [1] = JSR->Line [9];
+       Cond [2] = '\0';
+       Tail = JSR->Line + 10;
+    }
+
+    /* Check if this is indeed an integer function */
+    if (strcmp (Tail, "ax") != 0) {
+       /* No! */
+       return -1;
+    }
+
+    /* Get the condition code */
+    C = FindCond (Cond);
+    if (C < 0) {
+       /* OOPS! */
+       return -1;
+    }
+
+    /* Invert the code if we jump on condition not met. */
+    if (JMP->Line [2] == 'e' && JMP->Line [3] == 'q') {
+       /* Jumps if condition false, invert condition */
+       C = CmpInvertTab [C];
+    }
+
+    /* Return the condition code */
+    return C;
+}
+
+
+
+static int TosCmpFunc (Line* L)
+/* Check if this is a call to one of the TOS compare functions (tosgtax).
+ * Return the condition code or -1 if not found.
+ */
+{
+    if (LineMatch (L, "\tjsr\ttos")                            &&
+       strcmp (L->Line+strlen(L->Line)-2, "ax") == 0) {
+
+       /* Ok, found. Get the condition. */
+               return FindCond (L->Line+8);
+
+    } else {
+
+       /* Not found */
+       return -1;
+    }
+}
+
+
+
+static int IsUnsignedCmp (int Code)
+/* Check if this is an unsigned compare */
+{
+    CHECK (Code >= 0);
+    return CmpSignedTab [Code] == 0;
+}
+
+
+
+static void InvertZJump (Line* L)
+/* Invert a jeq/jne jump */
+{
+    if (L->Line [2] == 'n' && L->Line [3] == 'e') {
+       /* This was a bne/jne */
+       L->Line [2] = 'e';
+       L->Line [3] = 'q';
+    } else {
+       /* This was (hopefully) a beq/jeq */
+       L->Line [2] = 'n';
+       L->Line [3] = 'e';
+    }
+}
+
+
+
+static int FindCmd (Line* L)
+{
+    int I;
+
+    /* Search for the known patterns */
+    for (I = 0; I < COUNT(CmdDesc); ++I) {
+       if (CmdDesc[I].FullMatch) {
+           if (LineFullMatch (L, CmdDesc[I].Insn)) {
+               /* found */
+               return I;
+           }
+       } else {
+           if (LineMatch (L, CmdDesc[I].Insn)) {
+               /* found */
+               return I;
+           }
+       }
+    }
+    /* Not found */
+    return -1;
+}
+
+
+
+static unsigned RVUInt2 (Line* L,
+                        LineColl* LC,      /* To remember visited lines */
+                        unsigned Used,     /* Definitely used registers */
+                        unsigned Unused)   /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+    int I;
+
+    /* Check the following instructions. We classifiy them into primary
+     * loads (register value not used), neutral (check next instruction),
+     * and unknown (assume register was used).
+     */
+    while (1) {
+
+       unsigned R;
+
+       /* Get the next line and follow jumps */
+       do {
+
+           /* Handle jumps to local labels (continue there) */
+                   if (LineMatch (L, "\tjmp\tL")) {
+               /* Get the target of the jump */
+               L = GetTargetLine (L->Line+5);
+           }
+
+           /* Get the next instruction line */
+                   L = NextInstruction (L);
+
+           /* Bail out if we're done */
+           if (L == 0 || IsLabel (L)) {
+               /* Something is wrong */
+               return REG_ALL;
+           }
+
+           /* Check if we had this line already. If so, bail out, if not,
+            * add it to the list of known lines.
+            */
+           if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
+               goto ExitPoint;
+           }
+
+       } while (LineMatch (L, "\tjmp\tL"));
+
+       /* Special handling for branches */
+       if (LineMatchX (L, ShortBranches) >= 0 ||
+           LineMatchX (L, LongBranches) >= 0) {
+           const char* Target = L->Line+5;
+           if (Target[0] == 'L') {
+               /* Jump to local label. Check the register usage starting at
+                * the branch target and at the code following the branch.
+                * All registers that are unused in both execution flows are
+                * returned as unused.
+                */
+               unsigned U1, U2;
+                       U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
+               U1 = RVUInt1 (L, LC, Used, Unused);
+               return U1 | U2;         /* Used in any of the branches */
+           }
+       }
+
+       /* Search for the instruction in this line */
+       I = FindCmd (L);
+
+       /* If we don't find it, assume all other registers are */
+       if (I < 0) {
+           break;
+       }
+
+       /* Evaluate the use flags, check for addressing modes */
+       R = CmdDesc[I].Use;
+       if (IsXIndAddrMode (L)) {
+           R |= REG_X;
+       } else if (IsYIndAddrMode (L)) {
+           R |= REG_Y;
+       }
+       if (R) {
+           /* Remove registers that were already new loaded */
+           R &= ~Unused;
+
+           /* Remember the remaining registers */
+           Used |= R;
+       }
+
+       /* Evaluate the load flags */
+       R = CmdDesc[I].Load;
+       if (R) {
+           /* Remove registers that were already used */
+           R &= ~Used;
+
+           /* Remember the remaining registers */
+           Unused |= R;
+               }
+
+               /* If we know about all registers, bail out */
+               if ((Used | Unused) == REG_ALL) {
+           break;
+       }
+    }
+
+ExitPoint:
+    /* Return to the caller the complement of all unused registers */
+    return ~Unused & REG_ALL;
+}
+
+
+
+static unsigned RVUInt1 (Line* L,
+                        LineColl* LC,      /* To remember visited lines */
+                        unsigned Used,     /* Definitely used registers */
+                        unsigned Unused)   /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+    /* Remember the current count of the line collection */
+    unsigned Count = LC->Count;
+
+    /* Call the worker routine */
+    unsigned R = RVUInt2 (L, LC, Used, Unused);
+
+    /* Restore the old count */
+    LC->Count = Count;
+
+    /* Return the result */
+    return R;
+}
+
+
+
+static unsigned RegValUsed (Line* Start)
+/* Check the next instructions after the one in L for register usage. If
+ * a register is used as an index, or in a store or other instruction, it
+ * is assumed to be used. If a register is loaded with a value, before it
+ * was used by one of the actions described above, it is assumed unused.
+ * If the end of the lookahead is reached, all registers that are uncertain
+ * are marked as used.
+ * The result of the search is returned.
+ */
+{
+    unsigned R;
+
+    /* Create a new line collection and enter the start line */
+    LineColl* LC = NewLineColl (256);
+    LCAddLine (LC, Start);
+
+    /* Call the recursive subfunction */
+    R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
+
+    /* Delete the line collection */
+    FreeLineColl (LC);
+
+    /* Return the registers used */
+    return R;
+}
+
+
+
+static int RegAUsed (Line* Start)
+/* Check if the value in A is used. */
+{
+    return (RegValUsed (Start) & REG_A) != 0;
+}
+
+
+
+static int RegXUsed (Line* Start)
+/* Check if the value in X is used. */
+{
+    return (RegValUsed (Start) & REG_X) != 0;
+}
+
+
+
+static int RegYUsed (Line* Start)
+/* Check if the value in Y is used. */
+{
+    return (RegValUsed (Start) & REG_Y) != 0;
+}
+
+
+
+/*****************************************************************************/
+/*                         Real optimizer routines                          */
+/*****************************************************************************/
+
+
+
+static void OptCompares1 (void)
+/* Try to optimize the integer compare subroutines. */
+{
+    Line*    L2[10];           /* Line lookahead */
+    int      Cond;             /* Condition to evaluate */
+    unsigned Label;            /* Local label number */
+    unsigned Offs;             /* Stack offset */
+    Line*    DelStart;         /* First line to delete */
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Search for compares of local byte sized variables. This looks
+        * like:
+        *
+         *     ldy     #$xx
+        *      ldx     #$00
+         *     lda     (sp),y
+         *     jsr     pushax
+         *     ldy     #$yy
+        *      ldx     #$00
+         *     lda     (sp),y
+         *     jsr     tosugtax
+        *
+        * Replace it by a direct compare:
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      ldy     #$yy
+        *      cmp     (sp),y
+        *      jsr     boolugt
+        */
+       if (LineMatch (L, "\tldy\t#$")                                  &&
+           GetNextCodeLines (L, L2, 7)                                 &&
+           LineFullMatch (L2[0], "\tldx\t#$00")                        &&
+           LineFullMatch (L2[1], "\tlda\t(sp),y")                      &&
+           LineFullMatch (L2[2], "\tjsr\tpushax")                      &&
+           LineMatch     (L2[3], "\tldy\t#$")                          &&
+           LineFullMatch (L2[4], "\tldx\t#$00")                        &&
+           LineFullMatch (L2[5], "\tlda\t(sp),y")                      &&
+           (Cond = TosCmpFunc (L2[6])) >= 0) {
+
+           /* Get the stack offset and correct it, since we will remove
+            * the pushax.
+            */
+           Offs = GetHexNum (L2[3]->Line+7) - 2;
+
+           /* Replace it */
+           L = NewLineAfter (L, "\tlda\t(sp),y");
+           L = NewLineAfter (L, "\tldy\t#$%02X", Offs);
+           L = NewLineAfter (L, "\tcmp\t(sp),y");
+           L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+           /* Remove the old cruft */
+           FreeLines (L2[0], L2[6]);
+       }
+
+       /* Compares of byte sized global variables */
+       else if (LineFullMatch (L, "\tldx\t#$00")                       &&
+                GetNextCodeLines (L, L2, 5)                            &&
+                LineMatch     (L2[0], "\tlda\t")                       &&
+                LineFullMatch (L2[1], "\tjsr\tpushax")                 &&
+                LineFullMatch (L2[2], "\tldx\t#$00")                   &&
+                LineMatch     (L2[3], "\tlda\t")                       &&
+                (Cond = TosCmpFunc (L2[4])) >= 0) {
+
+           /* Replace it */
+           if (IsXIndAddrMode (L2[0])) {
+               /* The load is X indirect, so we may not remove the load
+                * of the X register.
+                */
+               L = L2[0];
+               DelStart = L2[1];
+           } else {
+               L = ReplaceLine  (L, L2[0]->Line);
+               DelStart = L2[0];
+           }
+           L = NewLineAfter (L, "\tcmp\t%s", L2[3]->Line+5);
+           L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+           /* Remove the old cruft */
+           FreeLines (DelStart, L2[4]);
+
+       }
+
+       /* Byte sized local to global */
+               else if (LineMatch (L, "\tldy\t#$")                             &&
+                GetNextCodeLines (L, L2, 6)                            &&
+                        LineFullMatch (L2[0], "\tldx\t#$00")                   &&
+                LineFullMatch (L2[1], "\tlda\t(sp),y")                 &&
+                LineFullMatch (L2[2], "\tjsr\tpushax")                 &&
+                LineFullMatch (L2[3], "\tldx\t#$00")                   &&
+                LineMatch     (L2[4], "\tlda\t")                       &&
+                (Cond = TosCmpFunc (L2[5])) >= 0) {
+
+           /* Replace it */
+                   L = NewLineAfter (L, L2[1]->Line);
+           L = NewLineAfter (L, "\tcmp\t%s", L2[4]->Line+5);
+           L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+           /* Remove the old cruft */
+           FreeLines (L2[0], L2[5]);
+
+       }
+
+       /* Byte sized global to local */
+       else if (LineFullMatch (L, "\tldx\t#$00")                       &&
+                GetNextCodeLines (L, L2, 6)                            &&
+                LineMatch     (L2[0], "\tlda\t")                       &&
+                LineFullMatch (L2[1], "\tjsr\tpushax")                 &&
+                        LineMatch     (L2[2], "\tldy\t#$")                     &&
+                LineFullMatch (L2[3], "\tldx\t#$00")                   &&
+                LineFullMatch (L2[4], "\tlda\t(sp),y")                 &&
+                (Cond = TosCmpFunc (L2[5])) >= 0) {
+
+           /* Get the stack offset and correct it, since we will remove
+            * the pushax.
+            */
+           Offs = GetHexNum (L2[2]->Line+7) - 2;
+
+           /* Replace it */
+           if (IsXIndAddrMode (L2[0])) {
+               /* The load is X indirect, so we may not remove the load
+                * of the X register.
+                */
+               L = L2[0];
+               DelStart = L2[1];
+           } else {
+               L = ReplaceLine  (L, L2[0]->Line);
+               DelStart = L2[0];
+           }
+           L = NewLineAfter (L, "\tldy\t#$%02X", Offs);
+           L = NewLineAfter (L, "\tcmp\t(sp),y");
+           L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+           /* Remove the old cruft */
+           FreeLines (DelStart, L2[5]);
+
+       }
+
+       /* Search for unsigned compares against global variables. This looks
+        * like:
+        *
+         *     jsr     pushax
+         *     lda     _b+0
+         *     ldx     _b+0+1
+         *     jsr     tosugtax
+        *
+                * Replace that by a direct compare:
+        *
+        *      cpx     _b+0+1
+        *      bne     L
+        *      cmp     _b+0
+        * L:
+        *      jsr     boolugt
+        */
+               else if (LineFullMatch (L, "\tjsr\tpushax")                     &&
+                        GetNextCodeLines (L, L2, 3)                            &&
+                IsLoadAX (L2[0], L2[1])                                &&
+                (Cond = TosCmpFunc (L2[2])) >= 0                       &&
+                        IsUnsignedCmp (Cond)) {
+
+           /* Get a free label number */
+           Label = AllocLabel ();
+
+           /* Replace the code */
+           L = ReplaceLine  (L, "\tcpx\t%s", L2[1]->Line+5);
+           L = NewLineAfter (L, "\tbne\tL%04X", Label);
+           L = NewLineAfter (L, "\tcmp\t%s", L2[0]->Line+5);
+           L = NewLabelAfter(L, Label);
+           L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+           /* Remove the old code */
+           FreeLines (L2[0], L2[2]);
+
+       }
+
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptDeadJumps (void)
+/* Remove jumps to the following instruction */
+{
+    static const char* Jumps [] = {
+       "\tbeq\tL",
+       "\tbne\tL",
+       "\tjeq\tL",
+       "\tjne\tL",
+       "\tjmp\tL",
+       0
+    };
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Get a pointer to the next instruction line */
+       Line* NextLine = NextInstruction (L);
+
+               /* Is this line a jump? */
+       int I = LineMatchX (L, Jumps);
+       if (I >= 0) {
+           /* Yes. Get the target label, skip labels */
+                   Line* Target = NextInstruction (GetTargetLine (L->Line+5));
+
+           /* If the target label is the next line, remove the jump */
+           if (Target == NextLine) {
+               FreeLine (L);
+           }
+       }
+
+       /* Go to the next line */
+       L = NextLine;
+    }
+}
+
+
+
+static void OptLoads (void)
+/* Remove unnecessary loads of values */
+{
+    Line* L2 [10];
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Check for
+        *
+        *      ldy     #$..
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      jsr     pushax
+        *
+        * and replace it by
+        *
+        *      ldy     #$..
+        *      jsr     pushwysp
+        *
+        * or even
+        *
+        *      jsr     pushw0sp
+        *
+        * This change will cost 3 cycles (one additional jump inside the
+        * subroutine), but it saves a lot of code (6 bytes per occurrence),
+        * so we will accept the overhead. It may even be possible to rewrite
+        * the library routine to get rid of the additional overhead.
+        */
+       if (LineMatch (L, "\tldy\t#$")                  &&
+           GetNextCodeLines (L, L2, 5)                 &&
+           LineFullMatch (L2 [0], "\tlda\t(sp),y")     &&
+           LineFullMatch (L2 [1], "\ttax")             &&
+           LineFullMatch (L2 [2], "\tdey")             &&
+           LineFullMatch (L2 [3], "\tlda\t(sp),y")     &&
+           LineFullMatch (L2 [4], "\tjsr\tpushax")) {
+
+           /* Found - replace it */
+           if (LineFullMatch (L, "\tldy\t#$01")) {
+               /* Word at offset zero */
+               FreeLine (L);
+                       L = ReplaceLine (L2 [4], "\tjsr\tpushw0sp");
+           } else {
+               ReplaceLine (L2 [4], "\tjsr\tpushwysp");
+           }
+
+           /* Delete the remaining lines */
+           FreeLines (L2 [0], L2 [3]);
+       }
+
+       /* Check for
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      ldy     #$yy
+        *      jsr     ldauidx
+        *
+        * and replace it by
+        *
+        *      ldy     #$xx
+        *      ldx     #$yy
+        *      jsr     ldauiysp
+        *
+        * or even
+        *
+        *      jsr     ldaui0sp
+        *
+        * This change will cost 2 cycles, but it saves a lot of code (6 bytes
+        * per occurrence), so we will accept the overhead. It may even be
+        * possible to rewrite the library routine to get rid of the additional
+        * overhead.
+        */
+       if (LineMatch (L, "\tldy\t#$")                  &&
+           GetNextCodeLines (L, L2, 6)                 &&
+           LineFullMatch (L2 [0], "\tlda\t(sp),y")     &&
+           LineFullMatch (L2 [1], "\ttax")             &&
+           LineFullMatch (L2 [2], "\tdey")             &&
+           LineFullMatch (L2 [3], "\tlda\t(sp),y")     &&
+                   LineMatch     (L2 [4], "\tldy\t#$")         &&
+           LineFullMatch (L2 [5], "\tjsr\tldauidx")) {
+
+           /* Found - replace it */
+                   L2 [4]->Line [3] = 'x';             /* Change to ldx */
+           if (LineFullMatch (L, "\tldy\t#$01")) {
+               /* Word at offset zero */
+               FreeLine (L);
+               L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp");
+           } else {
+                       ReplaceLine (L2 [5], "\tjsr\tldauiysp");
+           }
+
+           /* Delete the remaining lines */
+           FreeLines (L2 [0], L2 [3]);
+       }
+
+       /* Search for:
+        *
+                *      lda     (sp),y
+        *      jsr     pusha
+        *
+                * And replace by
+        *
+                *      jsr     pushaysp
+        */
+               if (LineFullMatch (L, "\tlda\t(sp),y")          &&
+           GetNextCodeLines (L, L2, 1)                 &&
+           LineFullMatch (L2 [0], "\tjsr\tpusha")) {
+
+           /* Found, replace it */
+           L = ReplaceLine (L, "\tjsr\tpushaysp");
+           FreeLine (L2 [0]);
+       }
+
+               /* All other patterns start with this one: */
+       if (!LineFullMatch (L, "\tldx\t#$00")) {
+           /* Next line */
+           goto NextLine;
+       }
+
+       /* Search for:
+        *
+        *      ldx     #$00
+        *      jsr     pushax
+        *
+        * and replace it by:
+        *
+        *      jsr     pusha0
+        *
+        */
+               if (GetNextCodeLines (L, L2, 1)                 &&
+                   LineFullMatch (L2 [0], "\tjsr\tpushax")) {
+
+           /* Replace the subroutine call */
+                   L = ReplaceLine (L, "\tjsr\tpusha0");
+
+           /* Remove the unnecessary line */
+           FreeLine (L2[0]);
+       }
+
+       /* Search for:
+        *
+        *      ldx     #$00
+        *      lda     ...
+        *      jsr     pushax
+        *
+        * and replace it by:
+        *
+        *      lda     ...
+        *      jsr     pusha0
+        *
+        */
+               else if (GetNextCodeLines (L, L2, 2)                    &&
+                LineMatch (L2 [0], "\tlda\t")                  &&
+                LineFullMatch (L2 [1], "\tjsr\tpushax")) {
+
+           /* Be sure, X is not used in the load */
+           if (NoXIndAddrMode (L2 [0])) {
+
+               /* Replace the subroutine call */
+               L2 [1] = ReplaceLine (L2 [1], "\tjsr\tpusha0");
+
+               /* Remove the unnecessary load */
+               FreeLine (L);
+
+               /* L must be valid */
+               L = L2 [0];
+           }
+
+       }
+
+       /* Search for:
+        *
+        *      ldx     #$00
+        *      lda     ...
+        *      cmp     #$..
+        *
+        * and replace it by:
+        *
+        *      lda     ...
+        *      cmp     #$..
+        */
+               else if (GetNextCodeLines (L, L2, 2)            &&
+                LineMatch (L2 [0], "\tlda\t")          &&
+                LineMatch (L2 [1], "\tcmp\t#$")) {
+
+           /* Be sure, X is not used in the load */
+           if (NoXIndAddrMode (L2 [0])) {
+
+               /* Remove the unnecessary load */
+               FreeLine (L);
+
+               /* L must be valid */
+               L = L2 [0];
+           }
+       }
+
+       /* Search for:
+        *
+        *      ldx     #$00
+        *      lda     ...
+        *      jsr     bnega
+        *
+        * and replace it by:
+        *
+        *      lda     ...
+        *      jsr     bnega
+        */
+       else if (GetNextCodeLines (L, L2, 2)            &&
+                LineMatch (L2 [0], "\tlda\t")          &&
+                        LineFullMatch (L2 [1], "\tjsr\tbnega")) {
+
+           /* Be sure, X is not used in the load */
+           if (NoXIndAddrMode (L2 [0])) {
+
+               /* Remove the unnecessary load */
+               FreeLine (L);
+
+               /* L must be valid */
+               L = L2 [0];
+           }
+       }
+
+NextLine:
+       /* Go to the next line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptRegLoads (void)
+/* Remove unnecessary loads of registers */
+{
+    unsigned Deletions;
+    Line* L;
+    Line* Lx;
+
+    /* Repeat this until there is nothing more to delete */
+    do {
+       Deletions = 0;
+       L = FirstCode;
+       while (L) {
+
+           int Delete = 0;
+
+           /* Search for a load of X and check if the value is used later */
+           if (LineMatch (L, "\tldx\t")                &&
+               !RegXUsed (L)                           &&
+               !IsCondJump (NextInstruction (L))) {
+
+               /* Remember to delete this line */
+               Delete = 1;
+           }
+
+           /* Search for a load of A and check if the value is used later */
+           else if (LineMatch (L, "\tlda\t")           &&
+                      !RegAUsed (L)                    &&
+                      !IsCondJump (NextInstruction (L))) {
+
+               /* Remember to delete this line */
+               Delete = 1;
+           }
+
+           /* Search for a load of Y and check if the value is used later */
+           else if (LineMatch (L, "\tldy\t")           &&
+                              !RegYUsed (L)                    &&
+                      !IsCondJump (NextInstruction (L))) {
+
+               /* Remember to delete this line */
+               Delete = 1;
+           }
+
+           /* Go to the next line, delete the current if requested */
+                   Lx = L;
+           L = NextCodeLine (L);
+           if (Delete) {
+               FreeLine (Lx);
+               ++Deletions;
+           }
+       }
+    } while (Deletions > 0);
+}
+
+
+
+static int OptPtrOps1 (Line** Start)
+/* Optimize several pointer and array constructs - subfunction 1 */
+{
+    Line* L2[15];
+    Line** L3;
+    unsigned NeedLoad;
+    unsigned LinesToRemove;
+    unsigned Inc;
+    unsigned Done;
+    unsigned Offs;
+
+    /* Use a local variable for the working line */
+    Line* L = *Start;
+
+    /* Search for (23B/XXT)
+     *
+     *         lda     _b+0
+     *         ldx     _b+0+1
+     *         sta     regsave
+     *         stx     regsave+1
+     *         jsr     incax1
+     *         sta     _b+0
+     *         stx     _b+0+1
+     *         lda     regsave
+     *         ldx     regsave+1
+     *
+     * and replace it by something like (24B/26T)
+     *
+     *         lda     _b+0
+     *         sta     regsave
+     *         clc
+     *         adc     #$01
+     *         sta     _b+0
+     *         lda     _b+0+1
+     *         sta     regsave+1
+     *         adc     #$00
+     *         sta     _b+0+1
+     *         tax
+     *         lda     regsave
+     */
+    if (!LineMatch (L, "\tlda\t")                              ||
+               !GetNextCodeLines (L, L2, 4)                            ||
+       !IsLoadAX (L, L2 [0])                                   ||
+       !LineFullMatch (L2[1], "\tsta\tregsave")                ||
+       !LineFullMatch (L2[2], "\tstx\tregsave+1")) {
+
+       /* Not found */
+       return 0;
+    }
+
+    /* */
+    if (LineMatch (L2[3], "\tjsr\tincax")) {
+               /* Get next code lines */
+               if (GetNextCodeLines (L2[3], &L2[4], 4) == 0) {
+                   /* Cannot get lines */
+                   return 0;
+               }
+               Inc = GetHexNum (L2[3]->Line+10);
+               L3 = &L2[4];
+       LinesToRemove = 8;
+    } else {
+       /* Get next code lines */
+       if (GetNextCodeLines (L2[3], &L2[4], 7) == 0) {
+           /* Cannot get lines */
+           return 0;
+       }
+       if (LineFullMatch (L2[3], "\tclc")                      &&
+           LineMatch (L2[4], "\tadc\t#$")                      &&
+           LineFullMatch (L2[5], "\tbcc\t*+3")                 &&
+           LineFullMatch (L2[6], "\tinx")) {
+           /* Inlined increment */
+           Inc = GetHexNum (L2[4]->Line+7);
+           L3 = &L2[7];
+           LinesToRemove = 11;
+       } else {
+           /* Not found */
+           return 0;
+       }
+    }
+
+    /* Check for the remainder */
+    if (!LineMatch (L3[0], "\tsta\t")                          ||
+       strcmp (L3[0]->Line+5, L->Line+5) != 0                  ||
+       !LineMatch (L3[1], "\tstx\t")                           ||
+       strcmp (L3[1]->Line+5, L2[0]->Line+5) != 0              ||
+       !LineFullMatch (L3[2], "\tlda\tregsave")                ||
+       !LineFullMatch (L3[3], "\tldx\tregsave+1")) {
+
+       /* Not found */
+       return 0;
+    }
+
+    /* Check if AX is actually used following the code above. If not,
+     * we don't need to load A/X from regsave. Since X will never by
+     * used without A, check just for A.
+     */
+    NeedLoad = 1;
+    if (!RegAUsed (L3[3])) {
+       /* We don't need to load regsave */
+       NeedLoad = 0;
+    }
+
+    /* Special code for register variables */
+    Done = 0;
+    if (LineMatch (L, "\tlda\tregbank+")       &&
+               GetNextCodeLines (L3[3], &L3[4], 1)     &&
+       Inc == 1) {
+
+       /* Remember the offset into the register bank */
+       char Reg[20];
+       strcpy (Reg, L->Line+5);
+
+       /* Check for several special sequences */
+       if (LineFullMatch (L3[4], "\tjsr\tldaui")) {
+           /* Load char indirect */
+           L = ReplaceLine  (L, "\tldx\t#$00");
+           L = NewLineAfter (L, "\tlda\t(%s,x)", Reg);
+           L = NewLineAfter (L, "\tinc\t%s", Reg);
+           L = NewLineAfter (L, "\tbne\t*+4");
+           L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+           Done = 1;
+           ++LinesToRemove;
+       } else if (LineFullMatch (L3[4], "\tsta\tptr1")         &&
+                  GetNextCodeLines (L3[4], &L3[5], 3)          &&
+                  LineFullMatch (L3[5], "\tstx\tptr1+1")       &&
+                  LineFullMatch (L3[6], "\tldx\t#$00")         &&
+                  LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) {
+
+           /* Load char indirect, inlined */
+           L = ReplaceLine  (L, "\tldx\t#$00");
+           L = NewLineAfter (L, "\tlda\t(%s,x)", Reg);
+           L = NewLineAfter (L, "\tinc\t%s", Reg);
+           L = NewLineAfter (L, "\tbne\t*+4");
+           L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+           Done = 1;
+           LinesToRemove += 4;
+
+       } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) {
+           if (GetNextCodeLines (L3[4], &L3[5], 2)             &&
+               LineMatch        (L3[5], "\tlda\t")             &&
+               LineFullMatch    (L3[6], "\tjsr\tstaspp")) {
+
+               /* Store to pointer */
+               L = ReplaceLine  (L, L3[5]->Line);
+               L = NewLineAfter (L, "\tldy\t#$00");
+               L = NewLineAfter (L, "\tsta\t(%s),y", Reg);
+               L = NewLineAfter (L, "\tinc\t%s", Reg);
+               L = NewLineAfter (L, "\tbne\t*+4");
+               L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+
+               Done = 1;
+               LinesToRemove += 3;
+
+           } else if (GetNextCodeLines (L3[4], &L3[5], 3)      &&
+                      LineMatch     (L3[5], "\tldy\t#$")       &&
+                      LineFullMatch (L3[6], "\tlda\t(sp),y")   &&
+                      LineFullMatch (L3[7], "\tjsr\tstaspp")) {
+
+               /* Beware: We have to correct the stack offset, since we will
+                * remove the pushax instruction!
+                */
+               Offs = GetHexNum (L3[5]->Line+7) - 2;
+
+               /* Store to pointer */
+               L = ReplaceLine  (L, "\tldy\t#$%02X", Offs);
+               L = NewLineAfter (L, "\tldx\t#$00");
+               L = NewLineAfter (L, "\tlda\t(sp),y");
+               L = NewLineAfter (L, "\tsta\t(%s,x)", Reg);
+               L = NewLineAfter (L, "\tinc\t%s", Reg);
+               L = NewLineAfter (L, "\tbne\t*+4");
+               L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+
+               Done = 1;
+               LinesToRemove += 4;
+           }
+       }
+    }
+
+    if (Done == 0) {
+
+       /* No register variable - insert the first part of the code */
+       if (NeedLoad) {
+           L = NewLineAfter (L, "\tsta\tptr1");
+       }
+       L = NewLineAfter (L, "\tclc");
+       L = NewLineAfter (L, "\tadc\t#$%02X", Inc);
+       L = NewLineAfter (L, "\tsta\t%s", L3[0]->Line+5);
+       L = NewLineAfter (L, "\tlda\t%s", L3[1]->Line+5);
+       if (NeedLoad) {
+           L = NewLineAfter (L, "\tsta\tptr1+1");
+       }
+       L = NewLineAfter (L, "\tadc\t#$00");
+       L = NewLineAfter (L, "\tsta\t%s", L3[1]->Line+5);
+
+       /* Check if we must really load the old value into a/x or if the
+        * code may be replaced by something else.
+        */
+       if (GetNextCodeLines (L3[3], &L3[4], 1)) {
+           if (LineFullMatch (L3[4], "\tjsr\tldaui")) {
+               /* Load char indirect */
+               L = NewLineAfter (L, "\tldx\t#$00");
+               L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+               NeedLoad = 0;
+               ++LinesToRemove;
+           } else if (LineFullMatch (L3[4], "\tsta\tptr1")             &&
+                      GetNextCodeLines (L3[4], &L3[5], 3)              &&
+                      LineFullMatch (L3[5], "\tstx\tptr1+1")           &&
+                      LineFullMatch (L3[6], "\tldx\t#$00")             &&
+                      LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) {
+
+               /* Load char indirect, inlined */
+               L = NewLineAfter (L, "\tldx\t#$00");
+               L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+               NeedLoad = 0;
+               LinesToRemove += 4;
+
+           } else if (LineFullMatch (L3[4], "\tjsr\tldaxi")) {
+               /* Load word indirect */
+               L = NewLineAfter (L, "\tldy\t#$01");
+               L = NewLineAfter (L, "\tlda\t(ptr1),y");
+               L = NewLineAfter (L, "\ttax");
+               L = NewLineAfter (L, "\tdey");
+               L = NewLineAfter (L, "\tlda\t(ptr1),y");
+               NeedLoad = 0;
+               ++LinesToRemove;
+
+           } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) {
+               if (GetNextCodeLines (L3[4], &L3[5], 2)                 &&
+                   LineMatch            (L3[5], "\tlda\t")             &&
+                   LineFullMatch        (L3[6], "\tjsr\tstaspp")) {
+
+                   /* Store to pointer */
+                   L = NewLineAfter (L, L3[5]->Line);
+                   L = NewLineAfter (L, "\tldy\t#$00");
+                   L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+                   NeedLoad = 0;
+                   LinesToRemove += 3;
+               } else if (GetNextCodeLines (L3[4], &L3[5], 3)          &&
+                          LineMatch     (L3[5], "\tldy\t#$")           &&
+                          LineFullMatch (L3[6], "\tlda\t(sp),y")       &&
+                          LineFullMatch (L3[7], "\tjsr\tstaspp")) {
+
+                   /* Beware: We have to correct the stack offset, since we will
+                    * remove the pushax instruction!
+                    */
+                   sprintf (L3[5]->Line+7, "%02X", GetHexNum (L3[5]->Line+7)-2);
+
+                   /* Store to pointer */
+                   L = NewLineAfter (L, L3[5]->Line);
+                   L = NewLineAfter (L, L3[6]->Line);
+                   L = NewLineAfter (L, "\tldy\t#$00");
+                   L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+                   NeedLoad = 0;
+                   LinesToRemove += 4;
+               }
+
+           }
+       }
+
+       /* If we need to load a/x, add the code */
+       if (NeedLoad) {
+           L = NewLineAfter (L, "\ttax");
+           L = NewLineAfter (L, "\tlda\tptr1");
+       }
+    }
+
+    /* Remove the code that is no longer needed */
+    FreeLines (L2[0], L2[LinesToRemove-1]);
+
+    /* Return the new line and success */
+    *Start = NextCodeLine (L);
+    return 1;
+}
+
+
+
+static int OptPtrOps2 (Line** Start)
+/* Optimize several pointer and array constructs - subfunction 2 */
+{
+    Line* L2[25];
+    Line** L3;
+    unsigned NeedLoad;
+    unsigned LinesToRemove;
+    unsigned Inc;
+    unsigned Offs;
+
+
+    /* Use a local variable for the working line */
+    Line* L = *Start;
+
+    /* Same as subfunction 1 but for local variables. */
+    if (LineMatch (L, "\tldy\t#$") == 0) {
+       return 0;
+    }
+
+    /* Get the stack offset. The offset points to the high byte, correct that. */
+    Offs = GetHexNum (L->Line+7) - 1;
+
+    /* Check for the actual sequences */
+    if (GetNextCodeLines (L, L2, 7)                            &&
+       LineFullMatch (L2[0], "\tjsr\tldaxysp")                 &&
+       LineFullMatch (L2[1], "\tsta\tregsave")                 &&
+       LineFullMatch (L2[2], "\tstx\tregsave+1")               &&
+       LineMatch     (L2[3], "\tjsr\tincax")) {
+
+       /* Non inlined version */
+       Inc = GetHexNum (L2[3]->Line+10);
+
+       /* Check for stack offset zero */
+               if (LineFullMatch (L2[4], "\tjsr\tstax0sp")             &&
+           LineFullMatch (L2[5], "\tlda\tregsave")             &&
+           LineFullMatch (L2[6], "\tldx\tregsave+1")) {
+
+           LinesToRemove = 7;
+
+       } else if (GetNextCodeLines (L2[6], &L2[7], 1)          &&
+                  LineMatch     (L2[4], "\tldy\t#$")           &&
+                  GetHexNum     (L2[4]->Line+7) == Offs        &&
+                  LineFullMatch (L2[5], "\tjsr\tstaxysp")      &&
+                  LineFullMatch (L2[6], "\tlda\tregsave")      &&
+                  LineFullMatch (L2[7], "\tldx\tregsave+1")) {
+
+           LinesToRemove = 8;
+
+       } else {
+           /* Not found */
+           return 0;
+       }
+
+    } else if (GetNextCodeLines (L, L2, 13)                            &&
+              LineFullMatch (L2[0], "\tlda\t(sp),y")           &&
+              LineFullMatch (L2[1], "\ttax")                   &&
+              LineFullMatch (L2[2], "\tdey")                   &&
+              LineFullMatch (L2[3], "\tlda\t(sp),y")           &&
+              LineFullMatch (L2[4], "\tsta\tregsave")          &&
+              LineFullMatch (L2[5], "\tstx\tregsave+1")        &&
+              LineFullMatch (L2[6], "\tclc")                   &&
+              LineMatch     (L2[7], "\tadc\t#$")               &&
+              LineFullMatch (L2[8], "\tbcc\t*+3")              &&
+              LineFullMatch (L2[9], "\tinx")) {
+
+       /* Inlined version */
+       Inc = GetHexNum (L2[7]->Line+7);
+
+       /* Check for stack offset zero */
+               if (LineFullMatch (L2[10], "\tjsr\tstax0sp")            &&
+           LineFullMatch (L2[11], "\tlda\tregsave")            &&
+           LineFullMatch (L2[12], "\tldx\tregsave+1")) {
+
+           LinesToRemove = 13;
+
+       } else if (GetNextCodeLines (L2[12], &L2[13], 1)        &&
+                  LineMatch     (L2[10], "\tldy\t#$")          &&
+                  GetHexNum     (L2[10]->Line+7) == Offs       &&
+                  LineFullMatch (L2[11], "\tjsr\tstaxysp")     &&
+                  LineFullMatch (L2[12], "\tlda\tregsave")     &&
+                  LineFullMatch (L2[13], "\tldx\tregsave+1")) {
+
+           LinesToRemove = 14;
+
+       } else {
+           /* Not found */
+           return 0;
+       }
+    } else {
+       /* Not found */
+       return 0;
+    }
+
+    /* Get a pointer to the last line of the preceding sequence */
+    L3 = &L2[LinesToRemove-1];
+
+    /* Check if AX is actually used following the code above. If not,
+     * we don't need to load A/X from regsave. Since X will never by
+     * used without A, check just for A.
+     */
+    NeedLoad = 1;
+    if (!RegAUsed (L3[0])) {
+       /* We don't need to load regsave */
+       NeedLoad = 0;
+    }
+
+    /* Replace the ldy instruction, offset must point to the low byte */
+    sprintf (L->Line+7, "%02X", Offs);
+
+    /* Insert the first part of the code */
+    L = NewLineAfter (L, "\tlda\t(sp),y");
+    if (NeedLoad) {
+       L = NewLineAfter (L, "\tsta\tptr1");
+    }
+    L = NewLineAfter (L, "\tclc");
+    L = NewLineAfter (L, "\tadc\t#$%02X", Inc);
+    L = NewLineAfter (L, "\tsta\t(sp),y");
+    L = NewLineAfter (L, "\tiny");
+    L = NewLineAfter (L, "\tlda\t(sp),y");
+    if (NeedLoad) {
+       L = NewLineAfter (L, "\tsta\tptr1+1");
+    }
+    L = NewLineAfter (L, "\tadc\t#$00");
+    L = NewLineAfter (L, "\tsta\t(sp),y");
+
+    /* Check if we must really load the old value into a/x or if the
+     * code may be replaced by something else.
+     */
+    if (GetNextCodeLines (L3[0], &L3[1], 1)) {
+       if (LineFullMatch (L3[1], "\tjsr\tldaui")) {
+           /* Load char indirect */
+           L = NewLineAfter (L, "\tldx\t#$00");
+           L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+           NeedLoad = 0;
+           ++LinesToRemove;
+       } else if (LineFullMatch (L3[1], "\tsta\tptr1")         &&
+                  GetNextCodeLines (L3[1], &L3[2], 3)          &&
+                  LineFullMatch (L3[2], "\tstx\tptr1+1")       &&
+                  LineFullMatch (L3[3], "\tldx\t#$00")         &&
+                  LineFullMatch (L3[4], "\tlda\t(ptr1,x)")) {
+
+           /* Load char indirect, inlined */
+           L = NewLineAfter (L, "\tldx\t#$00");
+           L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+           NeedLoad = 0;
+           LinesToRemove += 4;
+
+       } else if (LineFullMatch (L3[1], "\tjsr\tldaxi")) {
+           /* Load word indirect */
+           L = NewLineAfter (L, "\tldy\t#$01");
+           L = NewLineAfter (L, "\tlda\t(ptr1),y");
+           L = NewLineAfter (L, "\ttax");
+           L = NewLineAfter (L, "\tdey");
+           L = NewLineAfter (L, "\tlda\t(ptr1),y");
+           NeedLoad = 0;
+                   ++LinesToRemove;
+
+               } else if (LineFullMatch (L3[1], "\tjsr\tpushax")) {
+           if (GetNextCodeLines (L3[1], &L3[2], 2)             &&
+               LineMatch        (L3[2], "\tlda\t")             &&
+               LineFullMatch    (L3[3], "\tjsr\tstaspp")) {
+
+               /* Store to pointer */
+               L = NewLineAfter (L, L3[2]->Line);
+               L = NewLineAfter (L, "\tldy\t#$00");
+               L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+               NeedLoad = 0;
+               LinesToRemove += 3;
+           } else if (GetNextCodeLines (L3[1], &L3[2], 3)      &&
+                      LineMatch     (L3[2], "\tldy\t#$")       &&
+                      LineFullMatch (L3[3], "\tlda\t(sp),y")   &&
+                      LineFullMatch (L3[4], "\tjsr\tstaspp")) {
+
+               /* Beware: We have to correct the stack offset, since we will
+                * remove the pushax instruction!
+                */
+               sprintf (L3[2]->Line+7, "%02X", GetHexNum (L3[2]->Line+7)-2);
+
+               /* Store to pointer */
+               L = NewLineAfter (L, L3[2]->Line);
+               L = NewLineAfter (L, L3[3]->Line);
+               L = NewLineAfter (L, "\tldy\t#$00");
+               L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+               NeedLoad = 0;
+               LinesToRemove += 4;
+           }
+       }
+
+    }
+
+    /* If we need to load a/x, add the code */
+    if (NeedLoad) {
+       L = NewLineAfter (L, "\ttax");
+       L = NewLineAfter (L, "\tlda\tptr1");
+    }
+
+    /* Remove the code that is no longer needed */
+    FreeLines (L2[0], L2[LinesToRemove-1]);
+
+    /* Return the new line and success */
+    *Start = NextCodeLine (L);
+    return 1;
+}
+
+
+
+static void OptPtrOps (void)
+/* Optimize several pointer and array constructs */
+{
+    Line* L2 [10];
+
+    Line* L = FirstCode;
+    while (L) {
+
+               if (OptPtrOps1 (&L)) {
+           continue;
+       } else if (OptPtrOps2 (&L)) {
+           continue;
+       }
+
+               /* Search for the following sequence:
+        *
+        *      lda     regsave
+        *      ldx     regsave+1
+        *      jsr     pushax
+        *      lda     #$..
+        *      jsr     staspp
+        *
+        * and replace it by:
+        *
+        *      lda     #$..
+        *      ldy     #$00
+        *      sta     (regsave),y
+        *
+        */
+               else if (LineFullMatch (L, "\tlda\tregsave")            && /* Match on start */
+                        GetNextCodeLines (L, L2, 4)                    && /* Fetch next lines */
+                        LineFullMatch (L2 [0], "\tldx\tregsave+1")     && /* Match line 2 ... */
+                LineFullMatch (L2 [1], "\tjsr\tpushax")        &&
+                        LineMatch (L2 [2], "\tlda\t#$")                &&
+                        LineFullMatch (L2 [3], "\tjsr\tstaspp")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, L2 [2]->Line);             /* lda #$.. */
+           L2 [0] = ReplaceLine (L2 [0], "\tldy\t#$00");
+           L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y");
+
+           /* Free the remaining lines */
+           FreeLines (L2 [2], L2 [3]);
+       }
+
+               /* Search for the following sequence:
+        *
+        *      lda     regsave
+        *      ldx     regsave+1
+        *      jsr     ldaui
+        *
+        * and replace it by:
+        *
+        *      ldx     #$00
+        *      lda     (regsave,x)
+        *
+        */
+               else if (LineFullMatch (L, "\tlda\tregsave")        && /* Match on start */
+                        GetNextCodeLines (L, L2, 2)                && /* Fetch next lines */
+                        LineFullMatch (L2 [0], "\tldx\tregsave+1") && /* Match line 2 ... */
+                LineFullMatch (L2 [1], "\tjsr\tldaui")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, "\tldx\t#$00");
+           L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)");
+
+           /* Free the remaining lines */
+           FreeLine (L2 [1]);
+       }
+
+       /*
+        * Search for the following sequence:
+        *
+        *      lda     regsave
+        *      ldx     regsave+1
+        *      jsr     pushax
+        *      ldx     #$high
+        *      lda     #$low
+        *      jsr     staxspp
+        *
+        * and replace it by:
+        *
+        *      ldy     #$01
+        *      lda     #$high
+        *      sta     (regsave),y
+        *      tax
+        *      dey
+        *      lda     #$low
+        *      sta     (regsave),y
+        *
+        */
+       else if (LineFullMatch (L, "\tlda\tregsave")        &&
+                        GetNextCodeLines (L, L2, 5)                &&
+                        LineFullMatch (L2 [0], "\tldx\tregsave+1") &&
+                LineFullMatch (L2 [1], "\tjsr\tpushax")    &&
+                        LineMatch (L2 [2], "\tldx\t#$")            &&
+                        LineMatch (L2 [3], "\tlda\t#$")            &&
+                        LineFullMatch (L2 [4], "\tjsr\tstaxspp")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, "\tldy\t#$01");
+           L2 [0] = ReplaceLine (L2 [0], L2 [2]->Line);
+           L2 [0]->Line [3] = 'a';
+           L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y");
+           L2 [4] = ReplaceLine (L2 [4], L2 [3]->Line);
+           L2 [2] = ReplaceLine (L2 [2], "\ttax");
+           L2 [3] = ReplaceLine (L2 [3], "\tdey");
+           L      = NewLineAfter (L2 [4], "\tsta\t(regsave),y");
+       }
+
+       /*
+        * Search for the following sequence:
+        *
+                *      lda     regsave
+        *      ldx     regsave+1
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldx     #$00
+        *      lda     (ptr1,x)
+        *
+        * and replace it by:
+        *
+        *      ldx     #$00
+        *      lda     (regsave,x)
+        *
+        */
+               else if (LineFullMatch (L, "\tlda\tregsave")        &&
+                        GetNextCodeLines (L, L2, 5)                &&
+                        LineFullMatch (L2 [0], "\tldx\tregsave+1") &&
+                        LineFullMatch (L2 [1], "\tsta\tptr1")      &&
+                        LineFullMatch (L2 [2], "\tstx\tptr1+1")    &&
+                LineFullMatch (L2 [3], "\tldx\t#$00")      &&
+                        LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, "\tldx\t#$00");
+           L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)");
+
+           /* Remove the remaining lines */
+           FreeLines (L2 [1], L2 [4]);
+       }
+
+               /* Search for the following sequence:
+        *
+        *      jsr     pushax
+        *      lda     ...
+        *      jsr     staspp
+        *
+        * and replace it by:
+        *
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      lda     ...
+        *      ldy     #$00
+        *      sta     (ptr1),y
+        *
+        */
+               else if (LineFullMatch (L, "\tjsr\tpushax")         &&
+                        GetNextCodeLines (L, L2, 2)                &&
+                        LineMatch (L2 [0], "\tlda\t")              &&
+                        LineFullMatch (L2 [1], "\tjsr\tstaspp")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, "\tsta\tptr1");
+                   L2 [1] = ReplaceLine (L2 [1], L2 [0]->Line);   /* lda ... */
+           L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1");
+           L2 [2] = NewLineAfter (L2 [1], "\tldy\t#$00");
+                   L      = NewLineAfter (L2 [2], "\tsta\t(ptr1),y");
+       }
+
+               /* Search for the following sequence:
+        *
+        *      jsr     pushax
+        *      lda     ...
+        *      ldy     #$nn
+        *      jsr     staspidx
+        *
+        * and replace it by:
+        *
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      lda     ...
+        *      ldy     #$nn
+        *      sta     (ptr1),y
+        *
+        */
+               else if (LineFullMatch (L, "\tjsr\tpushax")         &&
+                        GetNextCodeLines (L, L2, 3)                &&
+                        LineMatch (L2 [0], "\tlda\t")              &&
+                LineMatch (L2 [1], "\tldy\t#$")            &&
+                        LineFullMatch (L2 [2], "\tjsr\tstaspidx")) {
+
+           /* Found the sequence, replace it */
+           L      = ReplaceLine (L, "\tsta\tptr1");
+           L      = NewLineAfter (L, "\tstx\tptr1+1");
+                   L2 [2] = ReplaceLine (L2 [2], "\tsta\t(ptr1),y");
+       }
+
+               /* Search for the following sequence:
+        *
+        *      jsr     pushax
+        *      ldy     #$..
+        *      lda     (sp),y
+        *      jsr     staspp
+        *
+        * and replace it by:
+        *
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldy     #$..
+        *      lda     (sp),y
+        *      ldy     #$00
+        *      sta     (ptr1),y
+        *
+        * Beware: Since we remove a call to a function that changes the stack
+        * pointer, we have to adjust the stack address for the lda.
+        *
+        */
+               else if (LineFullMatch (L, "\tjsr\tpushax")         &&
+                        GetNextCodeLines (L, L2, 3)                &&
+                LineMatch (L2 [0], "\tldy\t#$")            &&
+                        LineFullMatch (L2 [1], "\tlda\t(sp),y")    &&
+                        LineFullMatch (L2 [2], "\tjsr\tstaspp")) {
+
+           /* Found the sequence, replace it. First create a new load
+            * instruction for the changed stack offset.
+            */
+           char Buf [30];
+           sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2);
+           L      = ReplaceLine (L, "\tsta\tptr1");
+                   L2 [1] = ReplaceLine (L2 [1], Buf);   /* ldy ... */
+           L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1");
+           L2 [2] = ReplaceLine (L2 [2], "\tlda\t(sp),y");
+                   L2 [3] = NewLineAfter (L2 [2], "\tldy\t#$00");
+           L      = NewLineAfter (L2 [3], "\tsta\t(ptr1),y");
+       }
+
+               /* Search for the following sequence:
+        *
+        *      jsr     pushax
+        *      ldy     #$nn
+        *      lda     (sp),y
+        *      ldy     #$mm
+        *      jsr     staspidx
+        *
+        * and replace it by:
+        *
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldy     #$nn
+        *      lda     (sp),y
+        *      ldy     #$mm
+        *      sta     (ptr1),y
+        *
+        * Beware: Since we remove a call to a function that changes the stack
+        * pointer, we have to adjust the stack address for the lda.
+        *
+        */
+               else if (LineFullMatch (L, "\tjsr\tpushax")         &&
+                        GetNextCodeLines (L, L2, 4)                &&
+                LineMatch (L2 [0], "\tldy\t#$")            &&
+                        LineFullMatch (L2 [1], "\tlda\t(sp),y")    &&
+                LineMatch (L2 [2], "\tldy\t#$")            &&
+                        LineFullMatch (L2 [3], "\tjsr\tstaspidx")) {
+
+           /* Found the sequence, replace it. First create a new load
+            * instruction for the changed stack offset.
+            */
+           char Buf [30];
+           sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2);
+           L      = ReplaceLine (L, "\tsta\tptr1");
+           L      = NewLineAfter (L, "\tstx\tptr1+1");
+                   L2 [0] = ReplaceLine (L2 [0], Buf);   /* ldy ... */
+           L2 [3] = ReplaceLine (L2 [3], "\tsta\t(ptr1),y");
+       }
+
+               /* Search for the following sequence:
+        *
+                *      ldax    _label+0
+        *      ldy     #$..
+        *      clc
+        *      adc     (sp),y
+        *      bcc     *+3
+        *      inx
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldx     #$00
+        *      lda     (ptr1,x)
+        *
+        * and replace it by:
+        *
+        *      ldy     #$..
+        *      lda     (sp),y
+        *      tay
+        *      ldx     #$00
+        *      lda     _label+0,y
+        *
+        * The load of X may be omitted if X is not used below.
+        */
+               else if (LineMatch (L, "\tldax\t_")                 &&
+                        GetNextCodeLines (L, L2, 9)                &&
+                LineMatch (L2 [0], "\tldy\t#$")            &&
+                        LineFullMatch (L2 [1], "\tclc")            &&
+                        LineFullMatch (L2 [2], "\tadc\t(sp),y")    &&
+                LineFullMatch (L2 [3], "\tbcc\t*+3")       &&
+                LineFullMatch (L2 [4], "\tinx")            &&
+                LineFullMatch (L2 [5], "\tsta\tptr1")      &&
+                LineFullMatch (L2 [6], "\tstx\tptr1+1")    &&
+                LineFullMatch (L2 [7], "\tldx\t#$00")      &&
+                LineFullMatch (L2 [8], "\tlda\t(ptr1,x)")) {
+
+           /* Found the sequence, replace it */
+           char Label [256];
+           strcpy (Label, L->Line + 6);                /* Remember the label */
+           L = ReplaceLine  (L, L2 [0]->Line);         /* ldy .. */
+           L = NewLineAfter (L, "\tlda\t(sp),y");
+                   L = NewLineAfter (L, "\ttay");
+           if (RegXUsed (L2[8])) {
+               L = NewLineAfter (L, "\tldx\t#$00");
+           }
+                   L = NewLineAfter (L, "\tlda\t%s,y", Label);
+
+           /* Remove the remaining stuff. There may be hints between the
+            * instructions, remove them too
+            */
+                   FreeLines (L2[0], L2 [8]);
+
+       }
+
+       /* Check for
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      ldy     #$yy
+        *      jsr     ldauidx
+        *
+        * and replace it by
+        *
+        *      ldy     #$xx
+        *      ldx     #$yy
+        *      jsr     ldauiysp
+        *
+        * or even
+        *
+        *      jsr     ldaui0sp
+        *
+        * This change will cost 2 cycles, but it saves a lot of code (6 bytes
+        * per occurrence), so we will accept the overhead. It may even be
+        * possible to rewrite the library routine to get rid of the additional
+        * overhead.
+        */
+               else if (LineMatch (L, "\tldy\t#$")                     &&
+                GetNextCodeLines (L, L2, 6)                    &&
+                LineFullMatch (L2 [0], "\tlda\t(sp),y")        &&
+                LineFullMatch (L2 [1], "\ttax")                &&
+                LineFullMatch (L2 [2], "\tdey")                &&
+                LineFullMatch (L2 [3], "\tlda\t(sp),y")        &&
+                        LineMatch     (L2 [4], "\tldy\t#$")            &&
+                LineFullMatch (L2 [5], "\tjsr\tldauidx")) {
+
+           /* Found - replace it */
+                   L2 [4]->Line [3] = 'x';             /* Change to ldx */
+           if (LineFullMatch (L, "\tldy\t#$01")) {
+               /* Word at offset zero */
+               FreeLine (L);
+               L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp");
+           } else {
+                       ReplaceLine (L2 [5], "\tjsr\tldauiysp");
+           }
+
+           /* Delete the remaining lines */
+           FreeLines (L2 [0], L2 [3]);
+       }
+
+       /* Check for
+        *
+                *      ldy     #$xx
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldx     #$00
+        *      lda     (ptr1,x)
+        *
+        * and replace it by
+        *
+        *      ldy     #$xx
+        *      jsr     ldau0ysp
+        *
+        * or even
+        *
+        *      jsr     ldau00sp
+        *
+        * This change will has an overhead of 10 cycles, but it saves 11(!)
+        * bytes per invocation. Maybe we should apply only if FavourSize is
+        * true?
+        */
+               else if (LineMatch (L, "\tldy\t#$")                     &&
+                GetNextCodeLines (L, L2, 8)                    &&
+                LineFullMatch (L2 [0], "\tlda\t(sp),y")        &&
+                LineFullMatch (L2 [1], "\ttax")                &&
+                LineFullMatch (L2 [2], "\tdey")                &&
+                LineFullMatch (L2 [3], "\tlda\t(sp),y")        &&
+                LineFullMatch (L2 [4], "\tsta\tptr1")          &&
+                LineFullMatch (L2 [5], "\tstx\tptr1+1")        &&
+                LineFullMatch (L2 [6], "\tldx\t#$00")          &&
+                LineFullMatch (L2 [7], "\tlda\t(ptr1,x)")) {
+
+           /* Found - replace it */
+           if (LineFullMatch (L, "\tldy\t#$01")) {
+               /* Word at offset zero */
+               FreeLine (L);
+                       L = ReplaceLine (L2 [0], "\tjsr\tldau00sp");
+           } else {
+                       ReplaceLine (L2 [0], "\tjsr\tldau0ysp");
+           }
+
+           /* Delete the remaining lines */
+           FreeLines (L2 [1], L2 [7]);
+       }
+
+       /* Next Line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptRegVars (void)
+/* Optimize register variable uses */
+{
+    Line* L2 [10];
+
+    Line* L = FirstCode;
+    while (L) {
+
+               /* Search for the following sequence:
+        *
+                *      lda     regbank+n
+        *      ldx     regbank+n+1
+        *      jsr     ldaui
+        *
+        * and replace it by:
+        *
+        *      ldx     #$00
+                *      lda     (regbank+n,x)
+        *
+        */
+               if (LineMatch (L, "\tlda\tregbank+")            && /* Match on start */
+                   GetNextCodeLines (L, L2, 2)                 && /* Fetch next lines */
+                   LineMatch (L2 [0], "\tldx\tregbank+")       && /* Match line 2 ... */
+           LineFullMatch (L2 [1], "\tjsr\tldaui")      &&
+                   L->Line [13] == L2 [0]->Line [13]           && /* Offset equal */
+           strcmp (L2 [0]->Line + 14, "+1") == 0) {
+
+           char Buf [100];
+           sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5);
+
+           /* Found the sequence, replace it */
+                   L      = ReplaceLine (L, "\tldx\t#$00");
+           L2 [0] = ReplaceLine (L2 [0], Buf);
+
+           /* Free the remaining lines */
+           FreeLine (L2 [1]);
+       }
+
+               /* Search for the following sequence:
+        *
+                *      lda     regbank+n
+        *      ldx     regbank+n+1
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldx     #$00
+        *      lda     (ptr1,x)
+        *
+        * and replace it by:
+        *
+        *      ldx     #$00
+                *      lda     (regbank+n,x)
+        *
+        */
+               else if (LineMatch (L, "\tlda\tregbank+")        && /* Match on start */
+                        GetNextCodeLines (L, L2, 5)             && /* Fetch next lines */
+                        LineMatch (L2 [0], "\tldx\tregbank+")   && /* Match line 2 ... */
+                        L->Line [13] == L2 [0]->Line [13]       && /* Offset equal */
+                strcmp (L2 [0]->Line + 14, "+1") == 0   &&
+                LineFullMatch (L2 [1], "\tsta\tptr1")   &&
+                LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+                LineFullMatch (L2 [3], "\tldx\t#$00")   &&
+                LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) {
+
+           char Buf [100];
+           sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5);
+
+           /* Found the sequence, replace it */
+                   L      = ReplaceLine (L, "\tldx\t#$00");
+           L2 [0] = ReplaceLine (L2 [0], Buf);
+
+           /* Free the remaining lines */
+           FreeLines (L2 [1], L2 [4]);
+       }
+
+               /* Search for the following sequence:
+        *
+                *      lda     regbank+n
+        *      ldx     regbank+n+1
+        *      ldy     #$..
+        *      jsr     ldauidx
+        *
+        * and replace it by:
+        *
+        *      ldy     #$..
+        *      ldx     #$00
+                *      lda     (regbank+n),y
+        *
+        */
+               else if (LineMatch (L, "\tlda\tregbank+")        && /* Match on start */
+                        GetNextCodeLines (L, L2, 3)             && /* Fetch next lines */
+                        LineMatch (L2 [0], "\tldx\tregbank+")   && /* Match line 2 ... */
+                        L->Line [13] == L2 [0]->Line [13]       && /* Offset equal */
+                strcmp (L2 [0]->Line + 14, "+1") == 0   &&
+                LineMatch (L2 [1], "\tldy\t#$")         &&
+                LineFullMatch (L2 [2], "\tjsr\tldauidx")) {
+
+           char Buf [100];
+           sprintf (Buf, "\tlda\t(%s),y", L->Line + 5);
+
+           /* Found the sequence, replace it */
+                   L      = ReplaceLine (L, L2 [1]->Line);
+           L2 [0] = ReplaceLine (L2 [0], "\tldx\t#$00");
+           L2 [1] = ReplaceLine (L2 [1], Buf);
+
+           /* Free the remaining lines */
+           FreeLine (L2 [2]);
+       }
+
+               /* Search for the following sequence:
+        *
+                *      lda     regbank+n
+        *      ldx     regbank+n+1
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      lda     ...
+        *      ldy     #$mm
+        *      sta     (ptr1),y
+        *
+        * and replace it by:
+        *
+        *      lda     ...
+        *      ldy     #$mm
+                *      sta     (regbank+n),y
+        *
+        * The source form is not generated by the parser but by the optimizer.
+        */
+               else if (LineMatch (L, "\tlda\tregbank+")        && /* Match on start */
+                        GetNextCodeLines (L, L2, 6)             && /* Fetch next lines */
+                        LineMatch (L2 [0], "\tldx\tregbank+")   && /* Match line 2 ... */
+                        L->Line [13] == L2 [0]->Line [13]       && /* Offset equal */
+                strcmp (L2 [0]->Line + 14, "+1") == 0   &&
+                LineFullMatch (L2 [1], "\tsta\tptr1")   &&
+                LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+                LineMatch (L2 [3], "\tlda\t")           &&
+                LineMatch (L2 [4], "\tldy\t#$")         &&
+                LineMatch (L2 [5], "\tsta\t(ptr1),y")) {
+
+           char Buf [100];
+           sprintf (Buf, "\tsta\t(%s),y", L->Line + 5);
+
+           /* Found the sequence, replace it */
+                   L2 [5] = ReplaceLine (L2 [5], Buf);
+
+           /* Free the remaining lines */
+           FreeLines (L, L2 [2]);
+
+           /* Make the line pointer valid again */
+           L = L2 [5];
+       }
+
+               /* Search for the following sequence:
+        *
+                *      lda     regbank+n
+        *      ldx     regbank+n+1
+        *      sta     ptr1
+        *      stx     ptr1+1
+        *      ldy     #$mm
+        *      lda     (sp),y
+        *      ldy     #$ll
+        *      sta     (ptr1),y
+        *
+        * and replace it by:
+        *
+        *      ldy     #$mm
+        *      lda     (sp),y
+        *      ldy     #$ll
+                *      sta     (regbank+n),y
+        *
+        * The source form is not generated by the parser but by the optimizer.
+        */
+               else if (LineMatch (L, "\tlda\tregbank+")        && /* Match on start */
+                        GetNextCodeLines (L, L2, 7)             && /* Fetch next lines */
+                        LineMatch (L2 [0], "\tldx\tregbank+")   && /* Match line 2 ... */
+                        L->Line [13] == L2 [0]->Line [13]       && /* Offset equal */
+                strcmp (L2 [0]->Line + 14, "+1") == 0   &&
+                LineFullMatch (L2 [1], "\tsta\tptr1")   &&
+                LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+                LineMatch (L2 [3], "\tldy\t#$")         &&
+                LineFullMatch (L2 [4], "\tlda\t(sp),y") &&
+                LineMatch (L2 [5], "\tldy\t#$")         &&
+                LineMatch (L2 [6], "\tsta\t(ptr1),y")) {
+
+           char Buf [100];
+           sprintf (Buf, "\tsta\t(%s),y", L->Line + 5);
+
+           /* Found the sequence, replace it */
+                   L2 [6] = ReplaceLine (L2 [6], Buf);
+
+           /* Free the remaining lines */
+           FreeLines (L, L2 [2]);
+
+           /* Make the line pointer valid again */
+           L = L2 [6];
+       }
+
+       /* Next Line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptDoubleJumps (void)
+/* Remove/rearrange jumps that jump to other jumps */
+{
+    static const char* Jumps [] = {
+       "\tjeq\tL",
+       "\tjne\tL",
+       "\tbeq\tL",
+       "\tbne\tL",
+       "\tjmp\tL",
+       0
+    };
+
+    unsigned D;
+
+    Line* L = FirstCode;
+    while (L) {
+
+       int I;
+
+       /* Is this a jump? */
+               while ((I = LineMatchX (L, Jumps)) >= 0) {
+
+           /* Yes. Get the target label */
+           Line* Target = GetTargetLine (L->Line + 5);
+
+           /* Target points to the label itself. Skip lines until we reach
+            * one that is not a label.
+            */
+                   Target = NextInstruction (Target);
+
+           /* Be sure, this line is not the same as the one the jump is
+            * in (this happens if there is an empty loop).
+            */
+           if (Target == L) {
+               break;
+           }
+           D = 0;
+           if (LineMatch (Target, "\tjmp\t")) {
+
+               /* The target is itself a jump. If this is a short branch, get
+                * the final target and check if it is in reach. Bail out if
+                * not.
+                */
+               if (L->Line[1] == 'b') {
+                   Line* FinalTarget = GetTargetLine (Target->Line+5);
+                   FinalTarget = NextInstruction (FinalTarget);
+                   if ((D = GetJumpDistance (L, FinalTarget)) >= 123) {
+                       break;
+                   }
+               }
+
+               /* Make sure the jump does indeed point to another label.
+                * It may happen that this is not the case for some endless
+                * loop (while(1) and similar).
+                */
+               if (strcmp (L->Line+5, Target->Line+5) == 0) {
+                   /* Same label, bail out */
+                   break;
+               }
+
+               /* Use the label in the original jump instead */
+               L = ReplaceLine (L, "%.5s%s", L->Line, Target->Line+5);
+
+                   } else if (I < 2 && LineMatch (Target, Jumps [I])) {
+
+               /* Conditional jump. Use final label */
+               strcpy (L->Line+5, Target->Line+5);
+
+           } else {
+               break;
+           }
+       }
+
+       /* Next line */
+               L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptJumpRTS (void)
+/* Replace jumps to an RTS by an RTS */
+{
+    Line* L = FirstCode;
+    while (L) {
+       /* Is this a jump to a numbered label? */
+       if (LineMatch (L, "\tjmp\t") && L->Line [5] == 'L' && isdigit (L->Line [6])) {
+
+           /* Yes. Get the target label */
+           Line* Target = GetTargetLine (L->Line+5);
+
+           /* Target points to the label itself. Get the next line */
+           Target = NextCodeLine (Target);
+                   if (LineFullMatch (Target, "\trts")) {
+               /* Replace the jump by an RTS */
+               L = ReplaceLine (L, "\trts");
+           }
+       }
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptBoolTransforms (void)
+/* Try to remove the boolean transformation subroutines where they aren't
+ * necessary.
+ */
+{
+    Line* L2 [2];
+    unsigned Label;
+    const char* BranchTarget;
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Search for a boolean transformer followed by a conditional jump. */
+               if (LineMatch (L, "\tjsr\tbool") &&
+           GetNextCodeLines (L, L2, 1) &&
+           IsCondJump (L2 [0])) {
+
+           /* Make the boolean transformer unnecessary by changing the
+            * the conditional jump to evaluate the condition flags that
+            * are set after the compare directly. Note: jeq jumps if
+            * the condition is not met, jne jumps if the condition is met.
+            */
+
+           /* Get the condition code */
+           int Cond = FindCond (L->Line + 9);
+           if (Cond < 0) {
+               /* OOPS! */
+               goto NextLine;
+           }
+
+           /* Invert the code if we jump on condition not met. */
+                   if (L2[0]->Line [2] == 'e' && L2[0]->Line [3] == 'q') {
+               /* Jumps if condition false, invert condition */
+               Cond = CmpInvertTab [Cond];
+           }
+
+           /* For easier reading, get a pointer to the jump target */
+                   BranchTarget = L2[0]->Line+5;
+
+           /* Check if we can replace the jump (sometimes we would need two
+            * conditional jumps, we will not handle that for now since it
+            * has some complications - both jumps may be far jumps for
+            * example making the jumps more costly than the bool transformer
+            * subroutine). If we cannot replace the jump, bail out.
+            */
+           switch (Cond) {
+
+               case CMP_EQ:
+                   L = ReplaceLine (L, "\tjeq\t%s", BranchTarget);
+                   break;
+
+               case CMP_NE:
+                   L = ReplaceLine (L, "\tjne\t%s", BranchTarget);
+                   break;
+
+               case CMP_GT:
+                   Label = AllocLabel ();
+                   L = ReplaceLine  (L, "\tbeq\tL%04X", Label);
+                   L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+                   L = NewLabelAfter(L, Label);
+                   break;
+
+               case CMP_GE:
+                   L = ReplaceLine (L, "\tjpl\t%s", BranchTarget);
+                   break;
+
+               case CMP_LT:
+                   L = ReplaceLine (L, "\tjmi\t%s", BranchTarget);
+                   break;
+
+               case CMP_LE:
+                           L = ReplaceLine  (L, "\tjeq\t%s", BranchTarget);
+                   L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+                   break;
+
+               case CMP_UGT:
+                   Label = AllocLabel ();
+                   L = ReplaceLine  (L, "\tbeq\tL%04X", Label);
+                   L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+                   L = NewLabelAfter(L, Label);
+                   break;
+
+               case CMP_UGE:
+                           L = ReplaceLine (L, "\tjcs\t%s", BranchTarget);
+                   break;
+
+               case CMP_ULT:
+                           L = ReplaceLine (L, "\tjcc\t%s", BranchTarget);
+                   break;
+
+               case CMP_ULE:
+                           L = ReplaceLine (L, "\tjeq\t%s", BranchTarget);
+                           L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+                   break;
+
+               default:
+                   Internal ("Unknown jump condition: %u", Cond);
+
+           }
+
+           /* Remove the old stuff */
+           FreeLine (L2[0]);
+
+       }
+
+NextLine:
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptCompares2 (void)
+/* Try to optimize the integer compare subroutines. */
+{
+    Line* L2[10];
+    unsigned Label;
+    const char* BranchTarget;
+    int C;
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Search for
+        *
+        *      lda     x
+        *      ldx     x+1
+        *      cpx     #$00
+        *      bne     *+4
+        *      cmp     #$00
+        *      jne/jeq ...
+        *
+        * and replace it by
+        *
+        *      lda     x
+        *      ora     x+1
+        *      jne/jeq ...
+        */
+       if (LineMatch (L, "\tlda\t")                                    &&
+           GetNextCodeLines (L, L2, 5)                                 &&
+           IsLoadAX (L, L2[0])                                         &&
+           LineFullMatch (L2[1], "\tcpx\t#$00")                        &&
+           LineFullMatch (L2[2], "\tbne\t*+4")                         &&
+           LineFullMatch (L2[3], "\tcmp\t#$00")                        &&
+           IsCondJump (L2[4])) {
+
+           /* Replace the load of X by an ora */
+           L2[0]->Line[1] = 'o';
+           L2[0]->Line[2] = 'r';
+           L2[0]->Line[3] = 'a';
+
+           /* Remove unneeded stuff */
+           FreeLines (L2[1], L2[3]);
+
+       }
+
+       /* Same for local variables: Replace
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      cpx     #$00
+        *      bne     *+4                                                                                  cmp     #$00
+        *      cmp     #$00
+        *      jne/jeq ...
+        *
+        * by
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+                *      dey
+        *      ora     (sp),y
+        *      jne/jeq ...
+        */
+               else if (LineMatch (L, "\tldy\t#$")                             &&
+                GetNextCodeLines (L, L2, 8)                            &&
+                LineFullMatch (L2[0], "\tlda\t(sp),y")                 &&
+                LineFullMatch (L2[1], "\ttax")                         &&
+                LineFullMatch (L2[2], "\tdey")                         &&
+                LineFullMatch (L2[3], "\tlda\t(sp),y")                 &&
+                LineFullMatch (L2[4], "\tcpx\t#$00")                   &&
+                LineFullMatch (L2[5], "\tbne\t*+4")                    &&
+                LineFullMatch (L2[6], "\tcmp\t#$00")                   &&
+                IsCondJump (L2[7])) {
+
+           /* Replace the second load by an ora */
+           L2[3]->Line[1] = 'o';
+           L2[3]->Line[2] = 'r';
+           L2[3]->Line[3] = 'a';
+
+           /* Remove unneeded stuff */
+           FreeLine (L2[1]);
+           FreeLines (L2[4], L2[6]);
+
+       }
+
+               /* Search for the call to a compare subroutine followed by a
+                * conditional jump.
+        */
+               else if (LineMatch (L, "\tjsr\ttos")                            &&
+                       (L2[0] = NextCodeLine (L)) != 0                         &&
+               IsCondJump (L2[0])) {
+
+                   /* Extract the condition from the function name and branch */
+           C = CheckAndGetIntCmp (L, L2[0]);
+           if (C < 0) {
+               /* Something is wrong */
+               goto NextLine;
+           }
+
+           /* Replace the subroutine call by a cheaper one */
+           L = ReplaceLine (L, "\tjsr\ttosicmp");
+
+           /* For easier reading, get a pointer to the jump target */
+           BranchTarget = L2[0]->Line+5;
+
+           /* Check if we can replace the jump (sometimes we would need two
+            * conditional jumps, we will not handle that for now since it
+            * has some complications - both jumps may be far jumps for
+            * example making the jumps more costly than the bool transformer
+            * subroutine). If we cannot replace the jump, bail out.
+            */
+           switch (C) {
+
+               case CMP_EQ:
+                   L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+                   break;
+
+               case CMP_NE:
+                   L = NewLineAfter (L, "\tjne\t%s", BranchTarget);
+                   break;
+
+               case CMP_GT:
+                   Label = AllocLabel ();
+                   L = NewLineAfter (L, "\tbeq\tL%04X", Label);
+                   L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+                   L = NewLabelAfter(L, Label);
+                   break;
+
+               case CMP_GE:
+                   L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+                   break;
+
+               case CMP_LT:
+                   L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+                   break;
+
+               case CMP_LE:
+                           L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+                   L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+                   break;
+
+               case CMP_UGT:
+                   Label = AllocLabel ();
+                   L = NewLineAfter (L, "\tbeq\tL%04X", Label);
+                           L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+                   L = NewLabelAfter(L, Label);
+                   break;
+
+               case CMP_UGE:
+                   L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+                   break;
+
+               case CMP_ULT:
+                   L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+                   break;
+
+               case CMP_ULE:
+                           L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+                   L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+                   break;
+
+               default:
+                   Internal ("Unknown jump condition: %u", C);
+
+           }
+
+           /* Remove the old stuff */
+           FreeLine (L2[0]);
+       }
+
+NextLine:
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptTests (void)
+/* Remove unnecessary tests */
+{
+    Line* L2 [2];
+
+    const char* BitOps [] = {
+       "\tand\t",
+       "\tora\t",
+       "\teor\t",
+       0
+    };
+
+    /* Search for lda/tay/jne or lda/tay/jeq, remove the tay.
+     * Search for
+     *         lda ...
+     *  cmp #$00
+     *  jne/jeq
+     * Remove the cmp.
+     */
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Search for lda/tay/jne or lda/tay/jeq, remove the tay.
+        * Search for
+        *      lda/and/ora/eor
+                *      cmp     #$00
+        *      jne/jeq ...
+        * Remove the cmp.
+        */
+               if ((LineMatch (L, "\tlda\t")               ||
+            LineMatch (L, "\tand\t")               ||
+            LineMatch (L, "\tora\t")               ||
+            LineMatch (L, "\teor\t"))                  &&
+           GetNextCodeLines (L, L2, 2)                 &&
+           (LineFullMatch (L2 [0], "\ttay")        ||
+            LineFullMatch (L2 [0], "\tcmp\t#$00"))     &&
+           IsCondJump (L2 [1])) {
+
+           /* We can remove the tay */
+           FreeLine (L2 [0]);
+
+       }
+
+       /* Search for
+        *
+        *      and     ...
+        *      tax
+        *      jeq/jne
+        *
+        * and remove the tax.
+        */
+               else if (LineMatchX (L, BitOps) >= 0            &&
+                GetNextCodeLines (L, L2, 2)            &&
+                LineFullMatch (L2[0], "\ttax")         &&
+                IsCondJump (L2[1])) {
+
+           /* Remove the tax including a hint line of there is one */
+           if (LineFullMatch (L2[0]->Prev, "+forcetest")) {
+               FreeLine (L2[0]->Prev);
+           }
+           FreeLine (L2[0]);
+
+           /* If the line before L loads X, this is useless and may be removed */
+           L2[0] = PrevCodeLine (L);
+           if (LineFullMatch (L2[0], "\tldx\t#$00")) {
+               FreeLine (L2[0]);
+           }
+
+       }
+
+       /* Search for the sequence
+        *
+        *      stx     xx
+        *      stx     tmp1
+        *      ora     tmp1
+        *
+        * and replace it by
+        *
+        *      stx     xx
+        *      ora     xx
+        */
+       else if (LineMatch (L, "\tstx\t")               &&
+                GetNextCodeLines (L, L2, 2)            &&
+                        LineFullMatch (L2[0], "\tstx\ttmp1")   &&
+                LineFullMatch (L2[1], "\tora\ttmp1")) {
+
+           /* Found, replace it */
+           L = NewLineAfter (L, "\tora\t%s", L->Line+5);
+
+           /* Remove remaining stuff */
+           FreeLines (L2[0], L2[1]);
+
+       }
+
+
+       /* Next line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptNeg (void)
+/* Optimize the "bnegax/jeq" and "bnegax/jne" sequences */
+{
+    Line* L2 [10];
+
+    Line* L = FirstCode;
+    while (L) {
+
+       /* Search for the sequence:
+        *
+        *      lda     ...
+        *      jsr     bnega
+        *      jeq/jne ...
+        *
+        * and replace it by:
+        *
+        *      lda     ...
+        *      jne/jeq ...
+        */
+               if (LineMatch (L, "\tlda\t")                    && /* Match on start */
+                   GetNextCodeLines (L, L2, 2)                 && /* Fetch next lines */
+                   LineFullMatch (L2 [0], "\tjsr\tbnega")      &&
+                   IsCondJump (L2 [1])) {
+
+           /* Found the sequence, replace it */
+           FreeLine (L2 [0]);
+           InvertZJump (L2 [1]);
+
+       }
+
+       /* Search for the sequence:
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      tax
+        *      dey
+        *      lda     (sp),y
+        *      jsr     bnegax
+        *      jne/jeq ...
+        *
+        * and replace it by
+        *
+        *      ldy     #$xx
+        *      lda     (sp),y
+        *      dey
+        *      ora     (sp),y
+        *      jeq/jne ...
+        */
+       else if (LineMatch (L, "\tldy\t#$")                     &&
+                GetNextCodeLines (L, L2, 6)                    &&
+                LineFullMatch (L2[0], "\tlda\t(sp),y")         &&
+                LineFullMatch (L2[1], "\ttax")                 &&
+                LineFullMatch (L2[2], "\tdey")                 &&
+                LineFullMatch (L2[3], "\tlda\t(sp),y")         &&
+                LineFullMatch (L2[4], "\tjsr\tbnegax")         &&
+                IsCondJump    (L2[5])) {
+
+           L2[1] = ReplaceLine (L2[1], "\tdey");
+           L2[2] = ReplaceLine (L2[2], "\tora\t(sp),y");
+           FreeLines (L2[3], L2[4]);
+           InvertZJump (L2[5]);
+
+       }
+
+       /* Search for the sequence:
+        *
+        *      lda     xx
+        *      ldx     xx+1
+        *      jsr     bnegax
+        *      jne/jeq ...
+        *
+        * and replace it by
+        *
+        *      lda     xx
+        *      ora     xx+1
+        *      jeq/jne ...
+        */
+               else if (LineMatch (L, "\tlda\t")                       &&
+                GetNextCodeLines (L, L2, 3)                    &&
+                IsLoadAX (L, L2[0])                            &&
+                        LineFullMatch (L2[1], "\tjsr\tbnegax")         &&
+                IsCondJump    (L2[2])) {
+
+           /* Replace the load of X by ora */
+           L2[0]->Line[1] = 'o';
+           L2[0]->Line[2] = 'r';
+           L2[0]->Line[3] = 'a';
+                   FreeLine (L2[1]);
+           InvertZJump (L2[2]);
+
+       }
+
+       /* Search for the sequence:
+        *
+        *      jsr     _xxx
+        *      jsr     bnega(x)
+        *      jeq/jne ...
+        *
+        * and replace it by:
+        *
+        *      jsr     _xxx
+        *      <boolean test>
+        *      jne/jeq ...
+        */
+               else if (LineMatch (L, "\tjsr\t_")              && /* Match on start */
+                        GetNextCodeLines (L, L2, 2)            &&
+                        LineMatch (L2 [0], "\tjsr\tbnega")     &&
+                        IsCondJump (L2 [1])) {
+
+           if (LineFullMatch (L2 [0], "\tjsr\tbnega")) {
+               /* Byte sized */
+               L2 [0] = ReplaceLine (L2 [0], "\ttax"); /* Test a */
+           } else {
+               /* Word sized */
+               L2 [0] = ReplaceLine (L2 [0], "\tstx\ttmp1");
+               NewLineAfter (L2 [0], "\tora\ttmp1");
+           }
+
+           /* Invert the jump */
+           InvertZJump (L2 [1]);
+
+       }
+
+       /* Next line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptTriples (void)
+/* Replace code triples */
+{
+    static const char* Pat1 [] = {
+       "\tjsr\tldaxysp",
+       "\tjsr\tldax0sp",
+       "\tjsr\tldaysp",
+       "\tjsr\tleaysp",
+       "\tjsr\tldaxi",
+       0
+    };
+    static const char* Pat2 [] = {
+       "\tjsr\tpushax",
+       "\tjsr\tpushax",
+       "\tjsr\tpushax",
+       "\tjsr\tpushax",
+       "\tjsr\tpushax",
+       0
+    };
+    static const char* Replace [] = {
+       "\tjsr\tpushwysp",
+               "\tjsr\tpushw0sp",
+       "\tjsr\tpushbysp",
+       "\tjsr\tpleaysp",
+       "\tjsr\tpushw",
+    };
+
+    Line* L = FirstCode;
+    while (L) {
+       int I = LineFullMatchX (L, Pat1);
+       if (I >= 0) {
+           /* We found the first match, get the next line */
+           Line* L2 = NextCodeLine (L);
+           if (L2 && LineFullMatch (L2, Pat2 [I])) {
+               /* Found. Replace by the short call */
+               FreeLine (L2);
+               L = ReplaceLine (L, Replace [I]);
+           }
+       }
+       /* Next line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static Line* OptOneBlock (Line* L)
+/* Optimize the register contents inside one basic block */
+{
+    static const char* Compares [] = {
+       "\tjsr\ttoseq00",   "\tjsr\ttoseqa0",   "\tjsr\ttoseqax",
+       "\tjsr\ttoseqeax",  "\tjsr\ttosne00",   "\tjsr\ttosnea0",
+       "\tjsr\ttosneax",   "\tjsr\ttosneeax",  "\tjsr\ttoslt00",
+       "\tjsr\ttoslta0",   "\tjsr\ttosltax",   "\tjsr\ttosult00",
+               "\tjsr\ttosulta0",  "\tjsr\ttosultax",  "\tjsr\ttoslteax",
+       "\tjsr\ttosulteax", "\tjsr\ttosle00",   "\tjsr\ttoslea0",
+       "\tjsr\ttosleax",   "\tjsr\ttosule00",  "\tjsr\ttosulea0",
+       "\tjsr\ttosuleax",  "\tjsr\ttosleeax",  "\tjsr\ttosuleeax",
+       "\tjsr\ttosgt00",   "\tjsr\ttosgta0",   "\tjsr\ttosgtax",
+       "\tjsr\ttosugt00",  "\tjsr\ttosugta0",  "\tjsr\ttosugtax",
+       "\tjsr\ttosgteax",  "\tjsr\ttosugteax", "\tjsr\ttosge00",
+       "\tjsr\ttosgea0",   "\tjsr\ttosgeax",   "\tjsr\ttosuge00",
+               "\tjsr\ttosugea0",  "\tjsr\ttosugeax",  "\tjsr\ttosgeeax",
+       "\tjsr\ttosugeeax",
+       0
+    };
+
+    static const char* MakeBool [] = {
+       "\tjsr\tbooleq",    "\tjsr\tboolne",    "\tjsr\tboollt",
+               "\tjsr\tboolle",    "\tjsr\tboolgt",    "\tjsr\tboolge",
+               "\tjsr\tboolult",   "\tjsr\tboolule",   "\tjsr\tboolugt",
+       "\tjsr\tbooluge",
+       0
+    };
+
+    int A = -1;                        /* Contents of A register */
+    int X = -1;                        /* Contents of X register */
+    int Y = -1;                        /* Contents of Y register */
+    Line* L2;
+    unsigned NewVal;
+    int Delete;
+
+    while (L && !IsLabel (L)) {
+
+       /* Handle all instructions. All instructions not tested here have
+        * no effects on the register contents.
+        */
+       Delete = 0;
+       if (L->Line [0] == '+') {
+           /* This is a hint */
+           if (LineMatch (L, "+a:")) {
+               /* Information about a */
+               switch (L->Line [3]) {
+                           case '!':   A = -1;                         break;
+                   case '=':   A = GetHexNum (L->Line + 4);    break;
+               }
+           } else if (LineMatch (L, "+x:")) {
+               /* The code generator tells something about the x register */
+               switch (L->Line [3]) {
+                   case '!':   X = -1;                         break;
+                   case '=':   X = GetHexNum (L->Line + 4);    break;
+               }
+           } else if (LineMatch (L, "+y:")) {
+               /* Information about the y register */
+               switch (L->Line [3]) {
+                           case '!':   Y = -1;                         break;
+                   case '=':   Y = GetHexNum (L->Line + 4);    break;
+               }
+           }
+               } else if (LineMatch (L, "\tadc\t")) {
+           A = -1;
+       } else if (LineMatch (L, "\tand\t")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\tasl\ta")) {
+           if (A != -1) {
+               A = (A << 1) & 0xFF;
+           }
+       } else if (LineFullMatch (L, "\tdex")) {
+           DEC (X, 1);
+       } else if (LineFullMatch (L, "\tdey")) {
+           DEC (Y, 1);
+       } else if (LineMatch (L, "\teor")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\tinx")) {
+           INC (X, 1);
+       } else if (LineFullMatch (L, "\tiny")) {
+           INC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\taddeq0sp")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\taddeqysp")) {
+           /* We know about this function */
+           A = X = -1;
+           INC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\tbnega")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tbnegax")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tbnegeax")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tincax1")) {
+           /* We know about this function */
+           A = X = -1;
+       } else if (LineFullMatch (L, "\tjsr\tincax2")) {
+           /* We know about this function */
+           A = X = -1;
+       } else if (LineFullMatch (L, "\tjsr\tladdeq")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 3;
+       } else if (LineFullMatch (L, "\tjsr\tladdeqb")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 3;
+       } else if (LineFullMatch (L, "\tjsr\tldau00sp")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldau0ysp")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+           DEC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\tldaui")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldaui0sp")) {
+           A = -1;
+                   Y = X;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldauidx")) {
+           /* We know about this function */
+           A = -1;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldauiysp")) {
+           /* We know about this function */
+           A = -1;
+           Y = X;
+           X = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldax0sp")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldaxi")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldaxidx")) {
+           /* We know about this function */
+           A = X = -1;
+           DEC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\tldaxysp")) {
+           /* We know about this function */
+           A = X = -1;
+           DEC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\tldeaxi")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tldeaxidx")) {
+           /* We know about this function */
+           A = X = -1;
+           DEC (Y, 3);
+               } else if (LineFullMatch (L, "\tjsr\tlsubeq")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 3;
+               } else if (LineFullMatch (L, "\tjsr\tlsubeqb")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 3;
+       } else if (LineFullMatch (L, "\tjsr\tpush0")) {
+           /* We know about this function */
+           A = 0;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush1")) {
+           /* We know about this function */
+           A = 1;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush2")) {
+           /* We know about this function */
+           A = 2;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush3")) {
+           /* We know about this function */
+           A = 3;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush4")) {
+           /* We know about this function */
+           A = 4;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush5")) {
+           /* We know about this function */
+           A = 5;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush6")) {
+           /* We know about this function */
+           A = 6;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpush7")) {
+           /* We know about this function */
+           A = 7;
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpusha")) {
+           /* We know about this function */
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tpusha0")) {
+           /* We know about this function */
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpusha0")) {
+           /* We know about this function
+            * If X is already zero, we may call pushax instead and save two
+            * cycles.
+            */
+           if (X == 0) {
+               L = ReplaceLine (L, "\tjsr\tpushax");
+           }
+           X = 0;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushax")) {
+           /* We know about this function */
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushc0")) {
+           /* We know about this function */
+           A = 0;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tpushc1")) {
+           /* We know about this function */
+           A = 1;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tpushc2")) {
+           /* We know about this function */
+           A = 2;
+           Y = 0;
+       } else if (LineFullMatch (L, "\tjsr\tpushw")) {
+           /* We know about this function (calls pushax) */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushw0sp")) {
+           /* We know about this function(calls pushax)  */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushwidx")) {
+           /* We know about this function (calls pushax) */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tpushwysp")) {
+           /* We know about this function (calls pushax) */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tstaspp")) {
+           /* We know about this function */
+           Y = -1;
+       } else if (LineFullMatch (L, "\tjsr\tstaxspp")) {
+           /* We know about this function */
+           Y = -1;
+       } else if (LineFullMatch (L, "\tjsr\tstax0sp")) {
+           /* We know about this function */
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tstaxysp")) {
+           /* We know about this function */
+           INC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\tsubeq0sp")) {
+           /* We know about this function */
+           A = X = -1;
+           Y = 1;
+       } else if (LineFullMatch (L, "\tjsr\tsubeqysp")) {
+           /* We know about this function */
+           A = X = -1;
+           INC (Y, 1);
+       } else if (LineFullMatch (L, "\tjsr\ttosicmp")) {
+           /* We know about this function */
+           A = X = -1;
+                   Y = 0;
+       } else if (LineFullMatchX (L, Compares) >= 0) {
+           A = Y = -1;
+           X = 0;
+       } else if (LineFullMatchX (L, MakeBool) >= 0) {
+           A = -1;
+           X = 0;
+       } else if (LineMatch (L, "\tjsr\t")) {
+           /* Subroutine call, forget all register information */
+           A = X = Y = -1;
+       } else if (LineMatch (L, "\tlda\t")) {
+                   if (!RegAUsed (L) && !IsCondJump (NextInstruction (L))) {
+               /* The value loaded is not used later, remove it */
+               Delete = 1;
+           } else if (LineMatch (L, "\tlda\t(")) {
+               if (IsXIndAddrMode (L)) {
+                   /* lda (zp,x) - if Y and X are both zero, replace by
+                    * load indirect y and save one cycle in some cases.
+                    */
+                   if (X == 0 && Y == 0) {
+                       char Buf [256];
+                       const char* S = L->Line + 6;
+                       char* T = Buf + 6;
+                       strcpy (Buf, "\tlda\t(");
+                       while (*S != ',') {
+                           *T++ = *S++;
+                       }
+                       *T++ = ')';
+                       *T++ = ',';
+                       *T++ = 'y';
+                       *T   = '\0';
+                       L = ReplaceLine (L, Buf);
+                   }
+               }
+               /* In any case invalidate A */
+               A = -1;
+           } else if (LineMatch (L, "\tlda\t#$")) {
+               /* Immidiate load into A */
+               NewVal = GetHexNum (L->Line + 7);
+               if (NewVal == A) {
+                   /* Load has no effect */
+                   Delete = 1;
+               } else if (NewVal == X) {
+                   /* Requested value is already in X */
+                   L = ReplaceLine (L, "\ttxa");
+               } else if (NewVal == Y) {
+                   /* Requested value is already in Y */
+                   L = ReplaceLine (L, "\ttya");
+               }
+               /* Anyway, the new value is now in A */
+               A = NewVal;
+           } else {
+               /* Memory load into A */
+               A = -1;
+           }
+       } else if (LineMatch (L, "\tldax\t")) {
+           /* Memory load into A and X */
+           A = X = -1;
+       } else if (LineMatch (L, "\tldx\t")) {
+                   if (!RegXUsed (L) && !IsCondJump (NextInstruction (L))) {
+               /* The value loaded is not used later, remove it */
+               Delete = 1;
+           } else if (LineMatch (L, "\tldx\t#$")) {
+               /* Immidiate load into X */
+               NewVal = GetHexNum (L->Line + 7);
+               if (NewVal == X) {
+                   /* Load has no effect */
+                   Delete = 1;
+               } else if (NewVal == A) {
+                   /* Requested value is already in A */
+                   L = ReplaceLine (L, "\ttax");
+               } else if (X != -1 && NewVal == ((X + 1) & 0xFF)) {
+                   /* Requested value is one more than current contents */
+                   L = ReplaceLine (L, "\tinx");
+               } else if (X != -1 && NewVal == ((X - 1) & 0xFF)) {
+                   /* Requested value is one less than current contents */
+                   L = ReplaceLine (L, "\tdex");
+               }
+               /* Anyway, the new value is now in X */
+               X = NewVal;
+           } else {
+               /* Memory load into X */
+               X = -1;
+           }
+       } else if (LineMatch (L, "\tldy\t")) {
+                   if (!RegYUsed (L) && !IsCondJump (NextInstruction (L))) {
+               /* The value loaded is not used later, remove it */
+               Delete = 1;
+           } else if (LineMatch (L, "\tldy\t#$")) {
+               /* Immidiate load into Y */
+               NewVal = GetHexNum (L->Line + 7);
+               if (NewVal == Y) {
+                   /* Load has no effect */
+                   Delete = 1;
+               } else if (NewVal == A) {
+                   /* Requested value is already in A */
+                   L = ReplaceLine (L, "\ttay");
+               } else if (Y != -1 && NewVal == ((Y + 1) & 0xFF)) {
+                   /* Requested value is one more than current contents */
+                   L = ReplaceLine (L, "\tiny");
+               } else if (Y != -1 && NewVal == ((Y - 1) & 0xFF)) {
+                   /* Requested value is one less than current contents */
+                   L = ReplaceLine (L, "\tdey");
+               }
+               /* Anyway, the new value is now in Y */
+               Y = NewVal;
+           } else {
+               /* Memory load into Y */
+               Y = -1;
+           }
+       } else if (LineFullMatch (L, "\tlsr\ta")) {
+           if (A != -1) {
+               A >>= 1;
+           }
+       } else if (LineMatch (L, "\tora\t#$")) {
+           if (A != -1) {
+               A |= GetHexNum (L->Line + 7);
+           }
+       } else if (LineMatch (L, "\tora\t")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\tpla")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\trol\ta")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\tror\ta")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\trts")) {
+           A = X = Y = -1;
+       } else if (LineFullMatch (L, "\trti")) {
+           A = X = Y = -1;
+       } else if (LineMatch (L, "\tsbc\t")) {
+           A = -1;
+       } else if (LineFullMatch (L, "\ttax")) {
+           if (A != -1 && X == A) {
+               /* Load has no effect */
+               Delete = 1;
+           } else {
+                       X = A;
+           }
+       } else if (LineFullMatch (L, "\ttay")) {
+           if (A != -1 && Y == A) {
+               /* Load has no effect */
+               Delete = 1;
+           } else {
+               Y = A;
+           }
+       } else if (LineFullMatch (L, "\ttsx")) {
+           X = -1;
+       } else if (LineFullMatch (L, "\ttxa")) {
+           if (X != -1 && A == X) {
+               /* Load has no effect */
+               Delete = 1;
+           } else {
+               A = X;
+           }
+       } else if (LineFullMatch (L, "\ttya")) {
+           if (Y != -1 && A == Y) {
+               /* Load has no effect */
+               Delete = 1;
+           } else {
+               A = Y;
+           }
+       }
+
+       /* Set to next line, handle deletions */
+       L2 = NextCodeSegLine (L);
+       if (Delete) {
+           FreeLine (L);
+       }
+       L = L2;
+
+    }
+    if (L) {
+       /* Skip the label */
+       L = NextCodeSegLine (L);
+    }
+    return L;
+}
+
+
+
+static void OptBlocks (void)
+/* Optimize the register contents inside basic blocks */
+{
+    Line* L = FirstCode;
+    while (L) {
+       L = OptOneBlock (L);
+    }
+}
+
+
+
+static void OptJumps (void)
+/* Optimize jumps */
+{
+    static const char* Jumps [] = {
+       "\tjeq\tL",
+       "\tjne\tL",
+       "\tjmi\tL",
+       "\tjpl\tL",
+       "\tjcs\tL",
+       "\tjcc\tL",
+       0
+    };
+
+    Line* L = FirstCode;
+    while (L) {
+       int I = LineMatchX (L, Jumps);
+       if (I >= 0) {
+           Line* Target = GetTargetLine (L->Line+5);
+                   if (Target->Index > L->Index) {
+               /* This is a forward jump. Backward jumps are handled
+                * automagically by the assembler.
+                */
+               unsigned Distance = GetJumpDistance (L, Target);
+                       if (Distance < 123) {           /* Safety */
+                   L->Line [1] = 'b';          /* Make a short branch */
+                   L->Size = 2;                /* Set new size */
+               }
+           }
+       }
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+static void OptRTS (void)
+/* Change sequences of jsr XXX/rts to jmp XXX */
+{
+    Line* L = FirstCode;
+    while (L) {
+               if (LineMatch (L, "\tjsr\t")) {
+           /* This is a jsr, get the next instruction */
+           Line* L2 = NextCodeLine (L);
+                   if (L2 && LineFullMatch (L2, "\trts")) {
+               /* We found a sequence */
+               FreeLine (L2);
+                       L->Line [2] = 'm';
+               L->Line [3] = 'p';
+           }
+       }
+       /* Try the next line */
+       L = NextCodeLine (L);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void OptOnePass (unsigned long Flag, void (*F) (void))
+/* Call one optimizer pass if enabled */
+{
+    if ((OptDisable & Flag) == 0) {
+       F ();
+    } else if (Verbose || Debug) {
+       printf ("Optimizer pass %04lX skipped\n", Flag);
+    }
+}
+
+
+
+void OptDoOpt (void)
+/* Run the optimizer over the collected stuff */
+{
+    /* Find and remember the first line of code */
+    FindCodeStart ();
+
+    /* Mark all lines inside the code segment */
+    MarkCodeLines ();
+
+    /* Create a list of all local labels for fast access */
+    CreateLabelList ();
+
+    /* Ok, now start the real optimizations */
+
+    /* Optimize compares - first step */
+    OptOnePass (0x0001, OptCompares1);
+
+    /* Remove dead jumps */
+    OptOnePass (0x0002, OptDeadJumps);
+
+    /* Remove unnecessary loads */
+    OptOnePass (0x0004, OptLoads);
+
+    /* Remove unnecessary register loads */
+    OptOnePass (0x0008, OptRegLoads);
+
+    /* Optimize stores through pointers */
+    OptOnePass (0x0010, OptPtrOps);
+
+    /* Optimize use of register variables */
+    OptOnePass (0x0020, OptRegVars);
+
+    /* Remove jump cascades - must be used before OptNeg */
+    OptOnePass (0x0040, OptDoubleJumps);
+
+    /* Remove unnecessary boolean negates */
+    OptOnePass (0x0080, OptNeg);
+
+    /* Replace jumps to an RTS by an RTS */
+    OptOnePass (0x0100, OptJumpRTS);
+
+    /* Optimize boolean transforms */
+    OptOnePass (0x0200, OptBoolTransforms);
+
+    /* Optimize compares */
+    OptOnePass (0x0400, OptCompares2);
+
+    /* Remove unnecessary tests */
+    OptOnePass (0x0800, OptTests);
+
+    /* Optimize several triples */
+    OptOnePass (0x1000, OptTriples);
+
+    /* Optimize basic blocks */
+    OptOnePass (0x2000, OptBlocks);
+
+    /* Remove unnecessary register loads (another pass) */
+    OptOnePass (0x0008, OptRegLoads);
+
+    /* Optimize jumps */
+    OptOnePass (0x4000, OptJumps);
+
+    /* Optimize jsr/rts sequences */
+    OptOnePass (0x8000, OptRTS);
+}
+
+
+
diff --git a/src/cc65/optimize.h b/src/cc65/optimize.h
new file mode 100644 (file)
index 0000000..503ccba
--- /dev/null
@@ -0,0 +1,68 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               optimize.h                                 */
+/*                                                                           */
+/*                  An optimizer for the cc65 C compiler                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OPTIMIZE_H
+#define OPTIMIZE_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Bitset of flags that switch the different optimizer passes */
+extern unsigned long OptDisable;
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void OptDoOpt (void);
+/* Run the optimizer over the collected stuff */
+
+
+
+/* End of optimize.h */
+
+#endif
+
+
+
diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c
new file mode 100644 (file)
index 0000000..2a0f746
--- /dev/null
@@ -0,0 +1,199 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                pragma.c                                  */
+/*                                                                           */
+/*                 Pragma handling for the cc65 C compiler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "error.h"
+#include "io.h"
+#include "litpool.h"
+#include "symtab.h"
+#include "preproc.h"
+#include "scanner.h"
+#include "codegen.h"
+#include "expr.h"
+#include "pragma.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Tokens for the #pragmas */
+enum {
+    PR_BSSSEG,
+    PR_CODESEG,
+    PR_DATASEG,
+    PR_REGVARADDR,
+    PR_RODATASEG,
+    PR_SIGNEDCHARS,
+    PR_STATICLOCALS,
+    PR_ZPSYM,
+    PR_ILLEGAL
+};
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+static void StringPragma (void (*Func) (const char*))
+/* Handle a pragma that expects a string parameter */
+{
+    if (curtok != SCONST) {
+       Error (ERR_STRLIT_EXPECTED);
+    } else {
+       /* Get the string */
+       const char* Name = GetLiteral (curval);
+
+               /* Call the given function with the string argument */
+       Func (Name);
+
+       /* Reset the string pointer, removing the string from the pool */
+       ResetLiteralOffs (curval);
+    }
+
+    /* Skip the string (or error) token */
+    gettok ();
+}
+
+
+
+static void FlagPragma (unsigned char* Flag)
+/* Handle a pragma that expects a boolean paramater */
+{
+    /* Read a constant expression */
+    struct expent val;
+    constexpr (&val);
+
+    /* Store the value into the flag parameter */
+    *Flag = val.e_const;
+}
+
+
+
+void DoPragma (void)
+/* Handle pragmas */
+{
+    static const struct tok_elt Pragmas [] = {
+       {       "bssseg",       PR_BSSSEG       },
+               {       "codeseg",      PR_CODESEG      },
+       {       "dataseg",      PR_DATASEG      },
+               {       "regvaraddr",   PR_REGVARADDR   },
+       {       "rodataseg",    PR_RODATASEG    },
+       {       "signedchars",  PR_SIGNEDCHARS  },
+       {       "staticlocals", PR_STATICLOCALS },
+       {       "zpsym",        PR_ZPSYM        },
+       {       0,              PR_ILLEGAL      },
+    };
+
+    int Pragma;
+
+    /* Skip the token itself */
+    gettok ();
+
+    /* Identifier must follow */
+    if (curtok != IDENT) {
+       Error (ERR_IDENT_EXPECTED);
+       return;
+    }
+
+    /* Do we know this pragma? */
+    Pragma = searchtok (CurTok.Ident, Pragmas);
+    if (Pragma == PR_ILLEGAL) {
+       /* According to the ANSI standard, we're not allowed to generate errors
+        * for unknown pragmas, however, we're allowed to warn - and we will
+        * do so. Otherwise one typo may give you hours of bug hunting...
+        */
+       Warning (WARN_UNKNOWN_PRAGMA);
+       return;
+    }
+
+    /* Skip the identifier and check for an open paren */
+    gettok ();
+    ConsumeLParen ();
+
+    /* Switch for the different pragmas */
+    switch (Pragma) {
+
+       case PR_BSSSEG:
+           StringPragma (g_bssname);
+           break;
+
+       case PR_CODESEG:
+           StringPragma (g_codename);
+           break;
+
+       case PR_DATASEG:
+           StringPragma (g_dataname);
+           break;
+
+       case PR_REGVARADDR:
+           FlagPragma (&AllowRegVarAddr);
+           break;
+
+       case PR_RODATASEG:
+           StringPragma (g_rodataname);
+           break;
+
+       case PR_SIGNEDCHARS:
+           FlagPragma (&SignedChars);
+           break;
+
+       case PR_STATICLOCALS:
+           FlagPragma (&LocalsAreStatic);
+           break;
+
+       case PR_ZPSYM:
+           StringPragma (MakeZPSym);
+           break;
+
+       default:
+                   Internal ("Invalid pragma");
+    }
+
+    /* Closing paren needed */
+    ConsumeRParen ();
+}
+
+
+
diff --git a/src/cc65/pragma.h b/src/cc65/pragma.h
new file mode 100644 (file)
index 0000000..65794a0
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                pragma.h                                  */
+/*                                                                           */
+/*                 Pragma handling for the cc65 C compiler                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef PRAGMA_H
+#define PRAGMA_H
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void DoPragma (void);
+/* Handle pragmas */
+
+
+
+/* End of pragma.h */
+#endif
+
+
+
+
+
diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c
new file mode 100644 (file)
index 0000000..07ef3bd
--- /dev/null
@@ -0,0 +1,882 @@
+
+/* C pre-processor functions */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "codegen.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "ident.h"
+#include "include.h"
+#include "io.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "scanner.h"
+#include "util.h"
+#include "preproc.h"
+
+
+
+/*****************************************************************************/
+/*                                Forwards                                  */
+/*****************************************************************************/
+
+
+
+static int Pass1 (char* from, char* to);
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Set when the pp calls expr() recursively */
+unsigned char Preprocessing = 0;
+
+/* Management data for #if */
+#define N_IFDEF                16
+static int i_ifdef = -1;
+static char s_ifdef[N_IFDEF];
+
+/* Buffer for macro expansion */
+static char mlinebuf [LINESIZE];
+static char* mline = mlinebuf;
+static char* mptr;
+
+/* Flag: Expand macros in this line */
+static int ExpandMacros = 1;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+static int keepch (char c)
+/* Put character c into translation buffer. */
+{
+    return (*mptr++ = c);
+}
+
+
+
+static void keepstr (const char* S)
+/* Put string str into translation buffer. */
+{
+    while (*S) {
+       keepch (*S++);
+    }
+}
+
+
+
+static void comment (void)
+/* Remove comment from line. */
+{
+    unsigned StartingLine = ln;
+
+    gch ();
+    gch ();
+    while (*lptr != '*' || nch () != '/') {
+       if (*lptr == '\0') {
+           if (readline () == 0) {
+               PPError (ERR_EOF_IN_COMMENT, StartingLine);
+               return;
+           }
+       } else {
+           if (*lptr == '/' && nch() == '*') {
+               PPWarning (WARN_NESTED_COMMENT);
+           }
+           ++lptr;
+       }
+    }
+    gch ();
+    gch ();
+}
+
+
+
+static void skipblank (void)
+/* Skip blanks and tabs in the input stream. */
+{
+    while (IsBlank (*lptr)) {
+       ++lptr;
+    }
+}
+
+
+
+static char* CopyQuotedString (int Quote, char* Target)
+/* Copy a single or double quoted string from lptr to Target. Return the
+ * new target pointer. Target will not be terminated after the copy.
+ */
+{
+    /* Copy the starting quote */
+    *Target++ = gch();
+
+    /* Copy the characters inside the string */
+    while (*lptr != '\0' && *lptr != Quote) {
+               /* Keep an escaped char */
+       if (*lptr == '\\') {
+           *Target++ = gch();
+       }
+       /* Copy the character */
+       *Target++ = cgch();
+    }
+
+    /* If we had a terminating quote, copy it */
+    if (*lptr) {
+       *Target++ = gch();
+    }
+
+    /* Return the new target pointer */
+    return Target;
+}
+
+
+
+/*****************************************************************************/
+/*                               Macro stuff                                */
+/*****************************************************************************/
+
+
+
+static int macname (char *sname)
+/* Get macro symbol name.  If error, print message and kill line. */
+{
+    if (issym (sname) == 0) {
+       PPError (ERR_IDENT_EXPECTED);
+       kill ();
+       return 0;
+    } else {
+       return 1;
+    }
+}
+
+
+
+static void ExpandMacroArgs (Macro* M)
+/* Preprocessor pass 2.  Perform macro substitution. */
+{
+    int                C;
+    ident      Ident;
+    const char* Replacement;
+    char*      SavePtr;
+
+    /* Save the current line pointer and setup the new ones */
+    SavePtr = lptr;
+    lptr    = M->Replacement;
+
+    /* Copy the macro replacement checking for parameters to replace */
+    while ((C = *lptr) != '\0') {
+       /* If the next token is an identifier, check for a macro arg */
+       if (IsIdent (C)) {
+           symname (Ident);
+           Replacement = FindMacroArg (M, Ident);
+           if (Replacement) {
+               /* Macro arg, keep the replacement */
+               keepstr (Replacement);
+           } else {
+               /* No macro argument, keep the original identifier */
+               keepstr (Ident);
+           }
+       } else if (C == '#' && IsIdent (nch ())) {
+           ++lptr;
+           symname (Ident);
+           Replacement = FindMacroArg (M, Ident);
+                   if (Replacement) {
+               keepch ('\"');
+               keepstr (Replacement);
+               keepch ('\"');
+           } else {
+               keepch ('#');
+               keepstr (Ident);
+           }
+       } else if (IsQuoteChar(C)) {
+           mptr = CopyQuotedString (C, mptr);
+       } else {
+           *mptr++ = *lptr++;
+       }
+    }
+
+    /* Reset the line pointer */
+    lptr = SavePtr;
+}
+
+
+
+static int MacroCall (Macro* M)
+/* Process a function like macro */
+{
+    unsigned   ArgCount;       /* Macro argument count */
+    unsigned   ParCount;       /* Number of open parenthesis */
+    char       Buf[LINESIZE];  /* Argument buffer */
+    char       C;
+    const char* ArgStart;
+    char*      B;
+
+    /* Expect an argument list */
+    skipblank ();
+    if (*lptr != '(') {
+       PPError (ERR_ILLEGAL_MACRO_CALL);
+       return 0;
+    }
+
+    /* Eat the left paren */
+    ++lptr;
+
+    /* Read the actual macro arguments and store pointers to these arguments
+     * into the array of actual arguments in the macro definition.
+     */
+    ArgCount = 0;
+    ParCount = 0;
+    ArgStart = Buf;
+    B       = Buf;
+    while (1) {
+       C = *lptr;
+       if (C == '(') {
+           *B++ = gch ();
+           ++ParCount;
+       } else if (IsQuoteChar(C)) {
+           B = CopyQuotedString (C, B);
+       } else if (C == ',' || C == ')') {
+           if (ParCount == 0) {
+               /* End of actual argument */
+               gch ();
+               *B++ = '\0';
+               while (IsBlank(*ArgStart)) {
+                   ++ArgStart;
+               }
+               if (ArgCount < M->ArgCount) {
+                   M->ActualArgs[ArgCount++] = ArgStart;
+                       } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
+                   /* Be sure not to count the single empty argument for a
+                    * macro that does not have arguments.
+                    */
+                   ++ArgCount;
+               }
+
+                       /* Start the next one */
+               ArgStart = B;
+               if (C == ')') {
+                   break;
+               }
+           } else {
+               *B++ = gch ();
+               if (C == ')') {
+                   --ParCount;
+               }
+           }
+       } else if (IsBlank (C)) {
+           /* Squeeze runs of blanks */
+           *B++ = ' ';
+           skipblank ();
+       } else if (C == '\0') {
+           /* End of line inside macro argument list - read next line */
+           if (readline () == 0) {
+               return 0;
+           }
+       } else {
+           /* Just copy the character */
+           *B++ = *lptr++;
+       }
+    }
+
+    /* Compare formal argument count with actual */
+    if (M->ArgCount != ArgCount) {
+       PPError (ERR_MACRO_ARGCOUNT);
+       /* Be sure to make enough empty arguments available */
+       while (ArgCount < M->ArgCount) {
+           M->ActualArgs [ArgCount++] = "";
+       }
+    }
+
+    /* Preprocess the line, replacing macro parameters */
+    ExpandMacroArgs (M);
+
+    /* Done */
+    return 1;
+}
+
+
+
+static void ExpandMacro (Macro* M)
+/* Expand a macro */
+{
+    /* Check if this is a function like macro */
+    if (M->ArgCount >= 0) {
+       /* Function like macro */
+               if (MacroCall (M) == 0) {
+           kill ();
+       }
+    } else {
+       /* Just copy the replacement text */
+       keepstr (M->Replacement);
+    }
+}
+
+
+
+static void addmac (void)
+/* Add a macro to the macro table. */
+{
+    char*      saveptr;
+    ident      Ident;
+    char       Buf[LINESIZE];
+    Macro*     M;
+
+    /* Read the macro name */
+    skipblank ();
+    if (!macname (Ident)) {
+       return;
+    }
+
+    /* Create a new macro definition */
+    M = NewMacro (Ident);
+
+    /* Check if this is a function like macro */
+    if (*lptr == '(') {
+
+       /* Skip the left paren */
+       gch ();
+
+               /* Set the marker that this is a function like macro */
+       M->ArgCount = 0;
+
+       /* Read the formal parameter list */
+       while (1) {
+           skipblank ();
+           if (*lptr == ')')
+               break;
+           if (macname (Ident) == 0) {
+               return;
+           }
+           AddMacroArg (M, Ident);
+           skipblank ();
+           if (*lptr != ',')
+               break;
+           gch ();
+       }
+       if (*lptr != ')') {
+                   PPError (ERR_RPAREN_EXPECTED);
+           kill ();
+           return;
+       }
+       gch ();
+    }
+
+    /* Insert the macro into the macro table and allocate the ActualArgs array */
+    InsertMacro (M);
+
+    /* Remove whitespace and comments from the line, store the preprocessed
+     * line into Buf.
+     */
+    skipblank ();
+    saveptr = mptr;
+    Pass1 (lptr, Buf);
+    mptr = saveptr;
+
+    /* Create a copy of the replacement */
+    M->Replacement = xstrdup (Buf);
+}
+
+
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+
+
+static int Pass1 (char* from, char* to)
+/* Preprocessor pass 1.  Remove whitespace and comments. */
+{
+    int        c;      
+    int        done;
+    ident      Ident;
+    int        HaveParen;
+
+    lptr = from;
+    mptr = to;
+    done = 1;
+    while ((c = *lptr) != 0) {
+       if (IsBlank (c)) {
+           keepch (' ');
+           skipblank ();
+               } else if (IsIdent (c)) {
+           symname (Ident);
+           if (Preprocessing && strcmp(Ident, "defined") == 0) {
+               /* Handle the "defined" operator */
+               skipblank();
+               HaveParen = 0;
+               if (*lptr == '(') {
+                   HaveParen = 1;
+                   ++lptr;
+                   skipblank();
+               }
+               if (!IsIdent(c)) {
+                   PPError (ERR_IDENT_EXPECTED);
+                   *mptr++ = '0';
+               } else {
+                   symname (Ident);
+                   *mptr++ = IsMacro(Ident)? '1' : '0';
+                   if (HaveParen) {
+                       skipblank();
+                       if (*lptr != ')') {
+                           PPError (ERR_RPAREN_EXPECTED);
+                       } else {
+                           ++lptr;
+                       }
+                   }
+               }
+           } else {
+               if (MaybeMacro(c)) {
+                   done = 0;
+               }
+               keepstr (Ident);
+           }
+       } else if (IsQuoteChar(c)) {
+           mptr = CopyQuotedString (c, mptr);
+       } else if (c == '/' && nch () == '*') {
+           keepch (' ');
+           comment ();
+       } else if (ANSI == 0 && c == '/' && nch () == '/') {
+           keepch (' ');
+           /* Beware: Because line continuation chars are handled when reading
+            * lines, we may only skip til the end of the source line, which
+            * may not be the same as the end of the input line. The end of the
+            * source line is denoted by a lf (\n) character.
+            */
+           do {
+               ++lptr;
+           } while (*lptr != '\n' && *lptr != '\0');
+           if (*lptr == '\n') {
+               ++lptr;
+           }
+       } else {
+           *mptr++ = *lptr++;
+       }
+    }
+    keepch ('\0');
+    return done;
+}
+
+
+
+static int Pass2 (char *from, char *to)
+/* Preprocessor pass 2.  Perform macro substitution. */
+{
+    int        C;
+    int        no_chg;
+    ident      Ident;
+    Macro*     M;
+
+    lptr = from;
+    mptr = to;
+    no_chg = 1;
+    while ((C = *lptr) != '\0') {
+       /* If we have an identifier, check if it's a macro */
+       if (IsIdent (C)) {
+           symname (Ident);
+           M = FindMacro (Ident);
+           if (M) {
+               ExpandMacro (M);
+               no_chg = 0;
+           } else {
+               keepstr (Ident);
+           }
+       } else if (IsQuoteChar(C)) {
+           mptr = CopyQuotedString (C, mptr);
+       } else {
+           *mptr++ = *lptr++;
+       }
+    }
+    return no_chg;
+}
+
+
+
+static void xlateline (void)
+/* Translate one line. */
+{
+    int cnt;
+    int Done;
+    char *p;
+
+    Done = Pass1 (line, mline);
+    if (ExpandMacros == 0) {
+       Done = 1;
+       ExpandMacros = 1;       /* Reset to default */
+    }
+    cnt = 5;
+    do {
+       p = line;
+       line = mline;
+       mline = p;
+       if (Done)
+           break;
+       Done = Pass2 (line, mline);
+       keepch ('\0');
+    } while (--cnt);
+    lptr = line;
+}
+
+
+
+static void doundef (void)
+/* Process #undef directive */
+{
+    ident Ident;
+
+    skipblank ();
+    if (macname (Ident)) {
+       UndefineMacro (Ident);
+    }
+}
+
+
+
+static int setmflag (int skip, int flag, int cond)
+/* setmflag( skip, flag, cond ) */
+{
+    if (skip) {
+       s_ifdef[++i_ifdef] = 3;
+       return (1);
+    } else {
+       s_ifdef[++i_ifdef] = 6;
+       return (flag ^ cond);
+    }
+}
+
+
+
+static int doiff (int skip)
+/* Process #if directive */
+{
+    struct expent lval;
+    char* S;
+
+    /* We're about to abuse the compiler expression parser to evaluate the
+     * #if expression. Save the current tokens to come back here later.
+     */
+    Token sv1 = CurTok;
+    Token sv2 = NextTok;
+
+    /* Remove the #if from the line and add two semicolons as sentinels */
+    skipblank ();
+    S = line;
+    while ((*S++ = *lptr++) != '\0') ;
+    strcat (line, ";;");
+    lptr = line;
+
+    /* Switch into special preprocessing mode */
+    Preprocessing = 1;
+
+    /* Expand macros in this line */
+    xlateline ();
+
+    /* Prime the token pump (remove old tokens from the stream) */
+    gettok ();
+    gettok ();
+
+    /* Call the expression parser */
+    constexpr (&lval);
+
+    /* End preprocessing mode */
+    Preprocessing = 0;
+
+    /* Reset the old tokens */
+    CurTok  = sv1;
+    NextTok = sv2;
+
+    /* Set the #if condition according to the expression result */
+    return (setmflag (skip, 1, lval.e_const != 0));
+}
+
+
+
+static int doifdef (int skip, int flag)
+/* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
+{
+    ident Ident;
+
+    skipblank ();
+    if (macname (Ident) == 0) {
+               return 0;
+    } else {
+       return setmflag (skip, flag, IsMacro(Ident));
+    }
+}
+
+
+
+static void doinclude (void)
+/* Open an include file. */
+{
+    char name [80];
+    unsigned count;
+    char term;
+    char c;
+    char *p;
+
+    if (ifile >= MAXFILES) {
+       PPError (ERR_INCLUDE_NESTING);
+       goto done;
+    }
+    mptr = mline;
+    skipblank ();
+    if (!strchr ("\"<", (term = cgch ()))) {
+               PPError (ERR_INCLUDE_LTERM_EXPECTED);
+       goto done;
+    }
+    if (term == '<') {
+       term = '>';             /* get right terminator */
+    }
+
+    /* Get the name of the include file */
+    count = 0;
+    while ((c = *lptr) && (c != term) && count < sizeof (name)-1) {
+       name [count++] = c;
+       ++lptr;
+    }
+    if (c != term) {
+       PPError (ERR_INCLUDE_RTERM_EXPECTED);
+       goto done;
+    }
+    name [count] = '\0';
+
+    /* Now search for the name */
+    p = FindInclude (name, (term == '\"')? INC_USER : INC_SYS);
+    if (p == 0) {
+       PPError (ERR_INCLUDE_NOT_FOUND, name);
+       goto done;
+    }
+
+    /* Save the existing file info */
+    filetab[ifile].f_ln = ln;
+    filetab[ifile].f_name = fin;
+    filetab[ifile].f_iocb = inp;
+    ++ifile;
+
+    /* Assign the name and output it */
+    fin = p;
+    if (Verbose) {
+       printf ("including '%s'\n", fin);
+    }
+
+    /* Try to open the include file */
+    if ((inp = fopen (fin, "r")) == 0) {
+       /* oops! restore old file */
+       PPError (ERR_INCLUDE_OPEN_FAILURE, fin);
+       xfree (fin);
+       --ifile;
+       inp = filetab[ifile].f_iocb;
+       fin = filetab[ifile].f_name;
+    } else {
+       ln = 0;
+    }
+
+done:
+    /* clear rest of line so next read will come from new file (if open) */
+    kill ();
+}
+
+
+
+static void doerror (void)
+/* Print an error */
+{
+    skipblank ();
+    if (*lptr == '\0') {
+       PPError (ERR_INVALID_USER_ERROR);
+    } else {
+        PPError (ERR_USER_ERROR, lptr);
+    }
+
+    /* clear rest of line */
+    kill ();
+}
+
+
+
+/* C preprocessor. */
+
+/* stuff used to bum the keyword dispatching stuff */
+enum {
+    D_DEFINE,
+    D_ELSE,
+    D_ENDIF,
+    D_ERROR,
+    D_IF,
+    D_IFDEF,
+    D_IFNDEF,
+    D_INCLUDE,
+    D_LINE,
+    D_PRAGMA,
+    D_UNDEF,
+    D_ILLEGAL,
+};
+
+static const struct tok_elt pre_toks[] = {
+    {  "define",       D_DEFINE        },
+    {  "else",         D_ELSE          },
+    {  "endif",        D_ENDIF         },
+    {  "error",        D_ERROR         },
+    {  "if",           D_IF            },
+    {  "ifdef",        D_IFDEF         },
+    {  "ifndef",       D_IFNDEF        },
+    {  "include",      D_INCLUDE       },
+    {   "line",                D_LINE          },
+    {  "pragma",       D_PRAGMA        },
+    {  "undef",        D_UNDEF         },
+    {  0,              D_ILLEGAL       }
+};
+
+
+
+int searchtok (const char *sym, const struct tok_elt *toks)
+/* Search a token in a table */
+{
+    while (toks->toknam && strcmp (toks->toknam, sym))
+       ++toks;
+    return (toks->toknbr);
+}
+
+
+
+void preprocess (void)
+/* Preprocess a line */
+{
+    int        c;
+    int        Skip;
+    ident      sname;
+
+    /* Process compiler directives, skip empty lines */
+    lptr = line;
+
+    /* Skip white space at the beginning of the line */
+    skipblank ();
+
+    /* Check for stuff to skip */
+    Skip = 0;
+    while ((c = *lptr) == '\0' || c == '#' || Skip) {
+
+       /* Check for preprocessor lines lines */
+               if (c == '#') {
+           ++lptr;
+           skipblank ();
+           if (*lptr == '\0') {
+               /* ignore the empty preprocessor directive */
+               continue;
+           }
+           if (!issym (sname)) {
+               PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+               kill ();
+           } else {
+                       switch (searchtok (sname, pre_toks)) {
+
+                   case D_DEFINE:
+                       if (!Skip) {
+                           addmac ();
+                       }
+                       break;
+
+                   case D_ELSE:
+                       if (s_ifdef[i_ifdef] & 2) {
+                           if (s_ifdef[i_ifdef] & 4) {
+                               Skip = !Skip;
+                           }
+                           s_ifdef[i_ifdef] ^= 2;
+                       } else {
+                           PPError (ERR_UNEXPECTED_CPP_ELSE);
+                       }
+                       break;
+
+                   case D_ENDIF:
+                       if (i_ifdef >= 0) {
+                           Skip = s_ifdef[i_ifdef--] & 1;
+                       } else {
+                           PPError (ERR_UNEXPECTED_CPP_ENDIF);
+                       }
+                       break;
+
+                           case D_ERROR:
+                       if (!Skip) {
+                           doerror ();
+                       }
+                       break;
+
+                   case D_IF:
+                       Skip = doiff (Skip);
+                       break;
+
+                   case D_IFDEF:
+                       Skip = doifdef (Skip, 1);
+                       break;
+
+                   case D_IFNDEF:
+                       Skip = doifdef (Skip, 0);
+                       break;
+
+                   case D_INCLUDE:
+                       if (!Skip) {
+                           doinclude ();
+                       }
+                       break;
+
+                   case D_LINE:
+                       /* Not allowed in strict ANSI mode */
+                       if (ANSI) {
+                           PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+                           kill ();
+                       }
+                       break;
+
+                   case D_PRAGMA:
+                       if (!Skip) {
+                           /* Don't expand macros in this line */
+                           ExpandMacros = 0;
+                           /* #pragma is handled on the scanner level */
+                           goto Done;
+                       }
+                       break;
+
+                   case D_UNDEF:
+                       if (!Skip) {
+                           doundef ();
+                       }
+                       break;
+
+                   default:
+                       PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+                       kill ();
+               }
+           }
+
+       }
+       if (readline () == 0) {
+           if (i_ifdef >= 0) {
+               PPError (ERR_CPP_ENDIF_EXPECTED);
+           }
+           return;
+       }
+       skipblank ();
+    }
+
+Done:
+    xlateline ();
+    if (Verbose > 1) {
+       printf ("line: %s\n", line);
+    }
+}
+
diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h
new file mode 100644 (file)
index 0000000..194d11c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * preproc.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef PREPROC_H
+#define PREPROC_H
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Token table entry */
+struct tok_elt {
+    char *toknam;
+    int toknbr;
+};
+
+/* Set when the pp calls expr() recursively */
+extern unsigned char Preprocessing;
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int searchtok (const char *sym, const struct tok_elt* toks);
+/* Search a token in a table */
+
+void preprocess (void);
+/* Preprocess a line */
+
+
+
+/* End of preproc.h */
+#endif
+
+
+
+
+
diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c
new file mode 100644 (file)
index 0000000..5ca35d4
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * scanner.c
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "ctrans.h"
+#include "datatype.h"
+#include "error.h"
+#include "function.h"
+#include "global.h"
+#include "ident.h"
+#include "io.h"
+#include "litpool.h"
+#include "preproc.h"
+#include "symtab.h"
+#include "util.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+Token CurTok;          /* The current token */
+Token NextTok;         /* The next token */
+
+
+
+/* Token types */
+#define TT_C   0               /* ANSI C token */
+#define TT_EXT 1               /* cc65 extension */
+
+/* Token table */
+static struct Keyword {
+    char*          Key;        /* Keyword name */
+    unsigned char   Tok;       /* The token */
+    unsigned char   Type;              /* Token type */
+} Keywords [] = {
+    { "__AX__",                AX,             TT_C    },
+    { "__EAX__",               EAX,            TT_C    },
+    { "__asm__",               ASM,            TT_C    },
+    { "__fastcall__",          FASTCALL,       TT_C    },
+    { "asm",                   ASM,            TT_EXT  },
+    { "auto",                  AUTO,           TT_C    },
+    { "break",                 BREAK,          TT_C    },
+    { "case",                  CASE,           TT_C    },
+    { "char",                  CHAR,           TT_C    },
+    { "const",                 CONST,          TT_C    },
+    { "continue",              CONTINUE,       TT_C    },
+    { "default",               DEFAULT,        TT_C    },
+    { "do",                    DO,             TT_C    },
+    { "double",                DOUBLE,         TT_C    },
+    { "else",                  ELSE,           TT_C    },
+    { "enum",                  ENUM,           TT_C    },
+    { "extern",                EXTERN,         TT_C    },
+    { "fastcall",              FASTCALL,       TT_EXT  },
+    { "float",                 FLOAT,          TT_C    },
+    { "for",                   FOR,            TT_C    },
+    { "goto",                  GOTO,           TT_C    },
+    { "if",                    IF,             TT_C    },
+    { "int",                   INT,            TT_C    },
+    { "long",                  LONG,           TT_C    },
+    { "register",              REGISTER,       TT_C    },
+    { "return",                RETURN,         TT_C    },
+    { "short",                 SHORT,          TT_C    },
+    { "signed",                SIGNED,         TT_C    },
+    { "sizeof",                SIZEOF,         TT_C    },
+    { "static",                STATIC,         TT_C    },
+    { "struct",                STRUCT,         TT_C    },
+    { "switch",                SWITCH,         TT_C    },
+    { "typedef",               TYPEDEF,        TT_C    },
+    { "union",                 UNION,          TT_C    },
+    { "unsigned",              UNSIGNED,       TT_C    },
+    { "void",                  VOID,           TT_C    },
+    { "volatile",              VOLATILE,       TT_C    },
+    { "while",                 WHILE,          TT_C    },
+};
+#define KEY_COUNT      (sizeof (Keywords) / sizeof (Keywords [0]))
+
+
+
+/* Stuff for determining the type of an integer constant */
+#define IT_INT         0x01
+#define IT_UINT                0x02
+#define IT_LONG                0x04
+#define IT_ULONG       0x08
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+static int CmpKey (const void* Key, const void* Elem)
+/* Compare function for bsearch */
+{
+    return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
+}
+
+
+
+static int FindKey (char* Key)
+/* Find a keyword and return the token. Return IDENT if the token is not a
+ * keyword.
+ */
+{
+    struct Keyword* K;
+    K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
+    if (K && (K->Type != TT_EXT || ANSI == 0)) {
+       return K->Tok;
+    } else {
+       return IDENT;
+    }
+}
+
+
+
+static int skipwhite (void)
+/* Skip white space in the input stream, reading and preprocessing new lines
+ * if necessary. Return 0 if end of file is reached, return 1 otherwise.
+ */
+{
+    while (1) {
+               while (*lptr == 0) {
+           if (readline () == 0) {
+               return 0;
+           }
+           preprocess ();
+       }
+       if (*lptr == ' ' || *lptr == '\r') {
+           ++lptr;
+       } else {
+           return 1;
+       }
+    }
+}
+
+
+
+void symname (char *s)
+/* Get symbol from input stream */
+{
+    unsigned k = 0;
+    do {
+       if (k != MAX_IDENTLEN) {
+           ++k;
+           *s++ = *lptr;
+       }
+       ++lptr;
+    } while (IsIdent (*lptr) || isdigit (*lptr));
+    *s = '\0';
+}
+
+
+
+int issym (char *s)
+/* Get symbol from input stream or return 0 if not a symbol. */
+{
+    if (IsIdent (*lptr)) {
+       symname (s);
+       return 1;
+    } else {
+       return 0;
+    }
+}
+
+
+
+static void unknown (unsigned char c)
+/* Error message for unknown character */
+{
+    Error (ERR_INVALID_CHAR, c);
+    gch ();                    /* Skip */
+}
+
+
+
+static unsigned hexval (int c)
+/* Convert a hex digit into a value */
+{
+    if (!isxdigit (c)) {
+       Error (ERR_ILLEGAL_HEX_DIGIT);
+    }
+    if (isdigit (c)) {
+       return c - '0';
+    } else {
+               return toupper (c) - 'A' + 10;
+    }
+}
+
+
+
+static void SetTok (int tok)
+/* set nxttok and bump line ptr */
+{
+    nxttok = tok;
+    ++lptr;
+}
+
+
+
+static int SignExtendChar (int C)
+/* Do correct sign extension of a character */
+{
+    if (SignedChars && (C & 0x80) != 0) {
+               return C | ~0xFF;
+    } else {
+               return C & 0xFF;
+    }
+}
+
+
+
+static int parsechar (int c)
+/* Parse a character. Converts \n into EOL, etc. */
+{
+    int i;
+    int val;
+
+    /* Check for escape chars */
+    if (c == '\\') {
+       switch (c = gch ()) {
+           case 'b':
+               c = '\b';
+               break;
+           case 'f':
+               c = '\f';
+               break;
+           case 'r':
+               c = '\r';
+               break;
+           case 'n':
+               c = '\n';
+               break;
+           case 't':
+               c = '\t';
+               break;
+           case '\"':
+               c = '\"';
+               break;
+           case '\'':
+               c = '\'';
+               break;
+           case '\\':
+               c = '\\';
+               break;
+           case 'x':
+           case 'X':
+               /* Hex character constant */
+               val = hexval (gch ()) << 4;
+                       c = val | hexval (gch ());      /* Do not translate */
+               break;
+           case '0':
+           case '1':
+               /* Octal constant */
+               i = 0;
+               val = c - '0';
+               while ((c = *lptr) >= '0' && c <= '7' && i++ < 4) {
+                   val = (val << 3) | (c - '0');
+                   gch ();
+               }
+               c = val;                /* Do not translate */
+               break;
+           default:
+               Error (ERR_ILLEGAL_CHARCONST);
+       }
+    }
+
+    /* Do correct sign extension */
+    return SignExtendChar (c);
+}
+
+
+
+static void CharConst (void)
+/* Parse a character constant. */
+{
+    int c;
+
+    /* Skip the quote */
+    ++lptr;
+
+    /* Get character */
+    c = parsechar (cgch ());
+
+    /* Check for closing quote */
+    if (cgch () != '\'') {
+               Error (ERR_QUOTE_EXPECTED);
+    }
+
+    /* Setup values and attributes */
+    nxttok  = CCONST;
+    nxtval  = SignExtendChar (ctrans (c));     /* Translate into target charset */
+    nxttype = type_int;                                /* Character constants have type int */
+}
+
+
+
+static void StringConst (void)
+/* Parse a quoted string */
+{
+    nxtval = GetLiteralOffs ();
+    nxttok = SCONST;
+
+    /* Be sure to concatenate strings */
+    while (*lptr == '\"') {
+
+       /* Skip the quote char */
+       ++lptr;
+
+       while (*lptr != '\"') {
+           if (*lptr == 0) {
+               Error (ERR_UNEXPECTED_NEWLINE);
+               break;
+           }
+           AddLiteralChar (parsechar (gch()));
+       }
+
+       /* Skip closing quote char if there was one */
+       cgch ();
+
+       /* Skip white space, read new input */
+       skipwhite ();
+
+    }
+
+    /* Terminate the string */
+    AddLiteralChar ('\0');
+}
+
+
+
+void gettok (void)
+/* Get next token from input stream */
+{
+    char c;
+    ident token;
+
+    /* Current token is the lookahead token */
+    CurTok = NextTok;
+
+    /* Remember the starting position of the next token */
+    NextTok.Pos = ln;
+
+    /* Skip spaces and read the next line if needed */
+    if (skipwhite () == 0) {
+       /* End of file reached */
+       nxttok = CEOF;
+       return;
+    }
+
+    /* Determine the next token from the lookahead */
+    c = *lptr;
+    if (isdigit (c)) {
+
+       /* A number */
+       int HaveSuffix;         /* True if we have a type suffix */
+       unsigned types;         /* Possible types */
+       unsigned base;
+       unsigned long k;        /* Value */
+
+       k     = 0;
+       base  = 10;
+       types = IT_INT | IT_LONG | IT_ULONG;
+
+               if (c == '0') {
+           /* Octal or hex constants may also be of type unsigned int */
+           types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
+           /* gobble 0 and examin next char */
+           if (toupper (*++lptr) == 'X') {
+               base = 16;
+               nxttype = type_uint;
+               ++lptr;                 /* gobble "x" */
+           } else {
+               base = 8;
+           }
+       }
+       while (1) {
+           c = *lptr;
+           if (isdigit (c)) {
+               k = k * base + (c - '0');
+           } else if (base == 16 && isxdigit (c)) {
+               k = (k << 4) + hexval (c);
+           } else {
+               break;          /* not digit */
+           }
+                   ++lptr;             /* gobble char */
+       }
+
+       /* Check for a suffix */
+       HaveSuffix = 1;
+       c = toupper (*lptr);
+       if (c == 'U') {
+           /* Unsigned type */
+           ++lptr;
+           if (toupper (*lptr) != 'L') {
+               types = IT_UINT | IT_ULONG;
+           } else {
+               ++lptr;
+               types = IT_ULONG;
+           }
+       } else if (c == 'L') {
+           /* Long type */
+           ++lptr;
+           if (toupper (*lptr) != 'U') {
+               types = IT_LONG | IT_ULONG;
+           } else {
+               ++lptr;
+               types = IT_ULONG;
+           }
+       } else {
+           HaveSuffix = 0;
+       }
+
+       /* Check the range to determine the type */
+               if (k > 0x7FFF) {
+           /* Out of range for int */
+           types &= ~IT_INT;
+           /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
+            * allowed, and we don't have a type specifying suffix, emit a
+            * warning.
+            */
+                   if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
+               Warning (WARN_CONSTANT_IS_LONG);
+           }
+       }
+       if (k > 0xFFFF) {
+           /* Out of range for unsigned int */
+           types &= ~IT_UINT;
+       }
+       if (k > 0x7FFFFFFF) {
+           /* Out of range for long int */
+           types &= ~IT_LONG;
+       }
+
+       /* Now set the type string to the smallest type in types */
+       if (types & IT_INT) {
+           nxttype = type_int;
+       } else if (types & IT_UINT) {
+           nxttype = type_uint;
+       } else if (types & IT_LONG) {
+           nxttype = type_long;
+       } else {
+           nxttype = type_ulong;
+       }
+
+       /* Set the value and the token */
+       nxtval = k;
+       nxttok = ICONST;
+       return;
+    }
+
+    if (issym (token)) {
+
+       /* Check for a keyword */
+       if ((nxttok = FindKey (token)) != IDENT) {
+           /* Reserved word found */
+           return;
+       }
+       /* No reserved word, check for special symbols */
+       if (token [0] == '_') {
+           /* Special symbols */
+           if (strcmp (token, "__FILE__") == 0) {
+               nxtval = AddLiteral (fin);
+               nxttok = SCONST;
+               return;
+           } else if (strcmp (token, "__LINE__") == 0) {
+               nxttok  = ICONST;
+               nxtval  = ln;
+               nxttype = type_int;
+               return;
+           } else if (strcmp (token, "__fixargs__") == 0) {
+               nxttok  = ICONST;
+               nxtval  = GetParamSize (CurrentFunc);
+               nxttype = type_uint;
+               return;
+           } else if (strcmp (token, "__func__") == 0) {
+               /* __func__ is only defined in functions */
+               if (CurrentFunc) {
+                   nxtval = AddLiteral (GetFuncName (CurrentFunc));
+                   nxttok = SCONST;
+                   return;
+               }
+           }
+       }
+
+               /* No reserved word but identifier */
+       strcpy (NextTok.Ident, token);
+       NextTok.Tok = IDENT;
+       return;
+    }
+
+    /* Monstrous switch statement ahead... */
+    switch (c) {
+
+       case '!':
+           if (*++lptr == '=') {
+               SetTok (NE);
+           } else {
+               nxttok = BANG;
+           }
+           break;
+
+       case '\"':
+                   StringConst ();
+           break;
+
+       case '%':
+           if (*++lptr == '=') {
+               SetTok (MOASGN);
+           } else {
+               nxttok = MOD;
+           }
+           break;
+
+       case '&':
+           switch (*++lptr) {
+               case '&':
+                   SetTok (DAMP);
+                   break;
+               case '=':
+                   SetTok (AASGN);
+                   break;
+               default:
+                   nxttok = AMP;
+           }
+           break;
+
+       case '\'':
+           CharConst ();
+           break;
+
+       case '(':
+           SetTok (LPAREN);
+           break;
+
+       case ')':
+           SetTok (RPAREN);
+           break;
+
+       case '*':
+           if (*++lptr == '=') {
+               SetTok (MASGN);
+           } else {
+               nxttok = STAR;
+           }
+           break;
+
+       case '+':
+           switch (*++lptr) {
+               case '+':
+                   SetTok (INC);
+                   break;
+               case '=':
+                   SetTok (PASGN);
+                   break;
+               default:
+                   nxttok = PLUS;
+           }
+           break;
+
+       case ',':
+           SetTok (COMMA);
+           break;
+
+       case '-':
+           switch (*++lptr) {
+               case '-':
+                   SetTok (DEC);
+                   break;
+               case '=':
+                   SetTok (SASGN);
+                   break;
+               case '>':
+                   SetTok (PREF);
+                   break;
+               default:
+                   nxttok = MINUS;
+           }
+           break;
+
+       case '.':
+           if (*++lptr == '.') {
+               if (*++lptr == '.') {
+                   SetTok (ELLIPSIS);
+               } else {
+                   unknown (*lptr);
+               }
+           } else {
+               nxttok = DOT;
+           }
+           break;
+
+       case '/':
+           if (*++lptr == '=') {
+               SetTok (DASGN);
+           } else {
+               nxttok = DIV;
+           }
+           break;
+
+       case ':':
+           SetTok (COLON);
+           break;
+
+       case ';':
+           SetTok (SEMI);
+           break;
+
+       case '<':
+           switch (*++lptr) {
+               case '=':
+                   SetTok (LE);
+                   break;
+               case '<':
+                   if (*++lptr == '=') {
+                       SetTok (SLASGN);
+                   } else {
+                       nxttok = ASL;
+                   }
+                   break;
+               default:
+                   nxttok = LT;
+           }
+           break;
+
+       case '=':
+           if (*++lptr == '=') {
+               SetTok (EQ);
+           } else {
+               nxttok = ASGN;
+           }
+           break;
+
+       case '>':
+           switch (*++lptr) {
+               case '=':
+                   SetTok (GE);
+                   break;
+               case '>':
+                   if (*++lptr == '=') {
+                       SetTok (SRASGN);
+                   } else {
+                       nxttok = ASR;
+                   }
+                   break;
+               default:
+                   nxttok = GT;
+           }
+           break;
+
+       case '?':
+           SetTok (QUEST);
+           break;
+
+       case '[':
+           SetTok (LBRACK);
+           break;
+
+       case ']':
+           SetTok (RBRACK);
+           break;
+
+       case '^':
+           if (*++lptr == '=') {
+               SetTok (XOASGN);
+           } else {
+               nxttok = XOR;
+           }
+           break;
+
+       case '{':
+           SetTok (LCURLY);
+           break;
+
+        case '|':
+           switch (*++lptr) {
+               case '|':
+                   SetTok (DBAR);
+                   break;
+               case '=':
+                   SetTok (OASGN);
+                   break;
+               default:
+                   nxttok = BAR;
+           }
+           break;
+
+       case '}':
+           SetTok (RCURLY);
+           break;
+
+       case '~':
+           SetTok (COMP);
+           break;
+
+        case '#':
+           while (*++lptr == ' ') ;    /* Skip it and following whitespace */
+           if (!issym (token) || strcmp (token, "pragma") != 0) {
+               /* OOPS - should not happen */
+               Error (ERR_CPP_DIRECTIVE_EXPECTED);
+           }
+           nxttok = PRAGMA;
+           break;
+
+       default:
+                   unknown (c);
+
+    }
+
+}
+
+
+
+void Consume (unsigned Token, unsigned char ErrNum)
+/* Eat token if it is the next in the input stream, otherwise print an error
+ * message.
+ */
+{
+    if (curtok == Token) {
+       gettok ();
+    } else {
+               Error (ErrNum);
+    }
+}
+
+
+
+void ConsumeColon (void)
+/* Check for a colon and skip it. */
+{
+    Consume (COLON, ERR_COLON_EXPECTED);
+}
+
+
+
+void ConsumeSemi (void)
+/* Check for a semicolon and skip it. */
+{
+    /* Try do be smart about typos... */
+    if (curtok == SEMI) {
+       gettok ();
+    } else {
+       Error (ERR_SEMICOLON_EXPECTED);
+       if (curtok == COLON || curtok == COMMA) {
+           gettok ();
+       }
+    }
+}
+
+
+
+void ConsumeLParen (void)
+/* Check for a left parenthesis and skip it */
+{
+    Consume (LPAREN, ERR_LPAREN_EXPECTED);
+}
+
+
+
+void ConsumeRParen (void)
+/* Check for a right parenthesis and skip it */
+{
+    Consume (RPAREN, ERR_RPAREN_EXPECTED);
+}
+
+
+
+void ConsumeLBrack (void)
+/* Check for a left bracket and skip it */
+{
+    Consume (LBRACK, ERR_LBRACK_EXPECTED);
+}
+
+
+
+void ConsumeRBrack (void)
+/* Check for a right bracket and skip it */
+{
+    Consume (RBRACK, ERR_RBRACK_EXPECTED);
+}
+
+
+
+void ConsumeLCurly (void)
+/* Check for a left curly brace and skip it */
+{
+    Consume (LCURLY, ERR_LCURLY_EXPECTED);
+}
+
+
+
+void ConsumeRCurly (void)
+/* Check for a right curly brace and skip it */
+{
+    Consume (RCURLY, ERR_RCURLY_EXPECTED);
+}
+
+
+
diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h
new file mode 100644 (file)
index 0000000..3becee7
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * scanner.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+#include "datatype.h"
+#include "ident.h"
+
+
+
+/*****************************************************************************/
+/*                            token definitions                             */
+/*****************************************************************************/
+
+
+
+#define CEOF           0
+
+#define AUTO           10
+#define EXTERN         11
+#define REGISTER       12
+#define STATIC         13
+#define TYPEDEF                14
+#define ENUM           15
+#define CONST          16
+#define VOLATILE       17
+
+#define FIRSTTYPE              19
+#define CHAR           19
+#define INT            20
+#define DOUBLE         21
+#define FLOAT          22
+#define LONG           23
+#define UNSIGNED       24
+#define SIGNED         25
+#define SHORT          26
+#define STRUCT         27
+#define UNION          28
+#define VOID           29
+#define LASTTYPE       29
+
+#define DO             30
+#define FOR            31
+#define GOTO           32
+#define IF             33
+#define RETURN         34
+#define SWITCH         35
+#define WHILE          36
+
+#define ASM            40
+#define CASE           41
+#define DEFAULT                42
+#define BREAK          43
+#define CONTINUE       44
+#define ELSE           45
+#define ELLIPSIS       46
+#define SIZEOF                 47
+
+#define IDENT          50
+#define SEMI           51
+
+/* primary operators */
+#define LBRACK         52
+#define LPAREN         53
+#define DOT            54
+#define PREF           55
+
+#define LCURLY         56
+#define RBRACK                 57
+#define COMP           58
+#define INC            59
+#define PASGN          60
+#define PLUS           61
+#define COMMA          62
+#define DEC            63
+#define SASGN          64
+#define RCURLY                 65
+#define MINUS          66
+#define MASGN          67
+#define STAR           68
+#define DASGN          69
+#define DIV            70
+#define DAMP           71
+#define AASGN          72
+#define AMP            73
+#define NE             74
+#define BANG           75
+#define DBAR           76
+#define OASGN          77
+#define BAR            78
+#define EQ             79
+#define ASGN           80
+#define SLASGN                 81
+#define ASL            82
+
+/* inequalities */
+#define LE             83
+#define LT             84
+#define GE             85
+#define GT             86
+
+#define SRASGN                 87
+#define ASR            88
+#define XOASGN                 89
+#define XOR            90
+#define MOASGN                 91
+#define MOD            92
+#define QUEST          93
+#define COLON          94
+#define RPAREN                 95
+#define SCONST                 96
+#define ICONST                 97
+#define CCONST                 98
+#define FCONST                 99
+
+#define        FASTCALL        100
+#define AX             101
+#define EAX            102
+
+#define PRAGMA         110
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+/* Token stuff */
+typedef struct Token_ Token;
+struct Token_ {
+    unsigned   Tok;            /* The token itself */
+    long       IVal;           /* The integer attribute */
+    ident      Ident;          /* Identifier if IDENT */
+    unsigned   Pos;            /* Source line where the token comes from */
+    type*      IType;          /* Type if integer constant */
+};
+
+extern Token CurTok;           /* The current token */
+extern Token NextTok;          /* The next token */
+
+/* Defines to make the old code work */
+#define curtok         CurTok.Tok
+#define curval         CurTok.IVal
+#define curpos         CurTok.Pos
+#define curtype        CurTok.IType
+
+#define nxttok         NextTok.Tok
+#define nxtval         NextTok.IVal
+#define nxtpos         NextTok.Pos
+#define nxttype        NextTok.IType
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void symname (char* s);
+/* Get symbol from input stream */
+
+int issym (char* s);
+/* Get symbol from input stream or return 0 if not a symbol. */
+
+void gettok (void);
+/* Get next token from input stream */
+
+void Consume (unsigned Token, unsigned char ErrNum);
+/* Eat token if it is the next in the input stream, otherwise print an error
+ * message.
+ */
+
+void ConsumeColon (void);
+/* Check for a colon and skip it. */
+
+void ConsumeSemi (void);
+/* Check for a semicolon and skip it. */
+
+void ConsumeLParen (void);
+/* Check for a left parenthesis and skip it */
+
+void ConsumeRParen (void);
+/* Check for a right parenthesis and skip it */
+
+void ConsumeLBrack (void);
+/* Check for a left bracket and skip it */
+
+void ConsumeRBrack (void);
+/* Check for a right bracket and skip it */
+
+void ConsumeLCurly (void);
+/* Check for a left curly brace and skip it */
+
+void ConsumeRCurly (void);
+/* Check for a right curly brace and skip it */
+
+
+
+/* End of scanner.h */
+#endif
+
+
+
+
+
+
diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c
new file mode 100644 (file)
index 0000000..23b2d7e
--- /dev/null
@@ -0,0 +1,176 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                stdfunc.c                                 */
+/*                                                                           */
+/*        Handle inlining of known functions for the cc65 compiler          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "check.h"
+#include "codegen.h"
+#include "error.h"
+#include "global.h"
+#include "scanner.h"
+#include "stdfunc.h"
+
+
+
+/*****************************************************************************/
+/*                            Function forwards                             */
+/*****************************************************************************/
+
+
+
+static void StdFunc_strlen (struct expent*);
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Table with all known functions and their handlers. Must be sorted
+ * alphabetically!
+ */
+static struct FuncDesc {
+    const char*                Name;
+    void               (*Handler) (struct expent*);
+} StdFuncs [] = {
+    {          "strlen",       StdFunc_strlen          },
+
+};
+#define FUNC_COUNT     (sizeof (StdFuncs) / sizeof (StdFuncs [0]))
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static int CmpFunc (const void* Key, const void* Elem)
+/* Compare function for bsearch */
+{
+    return strcmp ((const char*) Key, ((const struct FuncDesc*) Elem)->Name);
+}
+
+
+
+static struct FuncDesc* FindFunc (const char* Name)
+/* Find a function with the given name. Return a pointer to the descriptor if
+ * found, return NULL otherwise.
+ */
+{
+    return bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs [0]), CmpFunc);
+}
+
+
+
+/*****************************************************************************/
+/*                         Handle known functions                           */
+/*****************************************************************************/
+
+
+
+static void StdFunc_strlen (struct expent* lval)
+/* Handle the strlen function */
+{
+    struct expent pval;
+
+    /* Fetch the parameter */
+    int k = hie1 (&pval);
+
+    /* Check if the parameter is a const address */
+    unsigned flags = 0;
+    unsigned pflags = pval.e_flags & ~E_MCTYPE;
+    if (pflags == E_MCONST) {
+       /* Constant numeric address */
+       flags |= CF_CONST | CF_ABSOLUTE;
+    } else if (k == 0 && ((pflags & E_MGLOBAL) != 0 || pval.e_flags == E_MEOFFS)) {
+       /* Global array with or without offset */
+       flags |= CF_CONST;
+       if (pval.e_flags & E_TGLAB) {
+           /* External linkage */
+           flags |= CF_EXTERNAL;
+       } else {
+           flags |= CF_STATIC;
+       }
+    } else {
+       /* Not const, load parameter into primary */
+       exprhs (CF_NONE, k, &pval);
+    }
+
+    /* Convert the parameter type to the type needed, check for mismatches */
+    assignadjust (SignedChars? type_pschar : type_puchar, &pval);
+
+    /* Generate the strlen code */
+    g_strlen (flags, pval.e_name, pval.e_const);
+
+    /* We expect the closing brace */
+    ConsumeRParen ();
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int IsStdFunc (const char* Name)
+/* Determine if the given function is a known standard function that may be
+ * called in a special way.
+ */
+{
+    /* Look into the table for known names */
+    return FindFunc (Name) != 0;
+}
+
+
+
+void HandleStdFunc (struct expent* lval)
+/* Generate code for a known standard function. */
+{
+    /* Get a pointer to the table entry */
+    struct FuncDesc* F = FindFunc ((const char*) lval->e_name);
+    CHECK (F != 0);
+
+    /* Call the handler function */
+    F->Handler (lval);
+}
+
+
+
diff --git a/src/cc65/stdfunc.h b/src/cc65/stdfunc.h
new file mode 100644 (file)
index 0000000..cde09f6
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                stdfunc.h                                 */
+/*                                                                           */
+/*        Handle inlining of known functions for the cc65 compiler          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef STDFUNC_H
+#define STDFUNC_H
+
+
+
+#include "symtab.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int IsStdFunc (const char* Name);
+/* Determine if the given function is a known standard function that may be
+ * called in a special way.
+ */
+
+void HandleStdFunc (struct expent* lval);
+/* Generate code for a known standard function. */
+
+
+
+/* End of stdfunc.h */
+
+#endif
+
+
+
diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c
new file mode 100644 (file)
index 0000000..d04dc30
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * stmt.c
+ *
+ * Ullrich von Bassewitz, 06.08.1998
+ *
+ * Original by John R. Dunning - see copyleft.jrd
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "expr.h"
+#include "function.h"
+#include "global.h"
+#include "goto.h"
+#include "litpool.h"
+#include "locals.h"
+#include "loop.h"
+#include "mem.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "stmt.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Maximum count of cases */
+#define CASE_MAX       257
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static int statement (void);
+/* Forward decl */
+
+
+
+static int doif (void)
+/* Handle 'if' statement here */
+{
+    int flab1;
+    int flab2;
+    int gotbreak;
+
+    /* Skip the if */
+    gettok ();
+
+    /* Generate a jump label and parse the condition */
+    flab1 = GetLabel ();
+    test (flab1, 0);
+
+    /* Parse the if body */
+    gotbreak = statement ();
+
+    /* Else clause present? */
+    if (curtok != ELSE) {
+
+       g_defloclabel (flab1);
+       /* Since there's no else clause, we're not sure, if the a break
+        * statement is really executed.
+        */
+       return 0;
+
+    } else {
+
+       /* Skip the else */
+       gettok ();
+
+       /* If we had some sort of break statement at the end of the if clause,
+        * there's no need to generate an additional jump around the else
+        * clause, since the jump is never reached.
+        */
+       if (!gotbreak) {
+           flab2 = GetLabel ();
+           g_jump (flab2);
+       } else {
+           /* Mark the label as unused */
+           flab2 = 0;
+       }
+       g_defloclabel (flab1);
+       gotbreak &= statement ();
+
+       /* Generate the label for the else clause */
+       if (flab2) {
+           g_defloclabel (flab2);
+       }
+
+       /* Done */
+       return gotbreak;
+    }
+}
+
+
+
+static void dowhile (char wtype)
+/* Handle 'while' statement here */
+{
+    int loop;
+    int lab;
+
+    gettok ();
+    loop = GetLabel ();
+    lab = GetLabel ();
+    addloop (oursp, loop, lab, 0, 0);
+    g_defloclabel (loop);
+    if (wtype == 'w') {
+
+       /* While loop */
+               test (lab, 0);
+
+       /* If the statement following the while loop is empty, that is, we have
+        * something like "while (1) ;", the test function ommitted the jump as
+        * an optimization. Since we know, the condition codes are set, we can
+        * do another small optimization here, and use a conditional jump
+        * instead an absolute one.
+        */
+       if (curtok == SEMI) {
+           /* Shortcut */
+           gettok ();
+           /* Use a conditional jump */
+           g_truejump (CF_NONE, loop);
+       } else {
+           /* There is code inside the while loop */
+           statement ();
+           g_jump (loop);
+           g_defloclabel (lab);
+       }
+
+    } else {
+
+       /* Do loop */
+               statement ();
+       Consume (WHILE, ERR_WHILE_EXPECTED);
+       test (loop, 1);
+       ConsumeSemi ();
+       g_defloclabel (lab);
+
+    }
+    delloop ();
+}
+
+
+
+static void doreturn (void)
+/* Handle 'return' statement here */
+{
+    struct expent lval;
+    unsigned etype = 0;                /* Type of return expression */
+    int HaveVal = 0;           /* Do we have a return value in ax? */
+
+
+    gettok ();
+    if (curtok != SEMI) {
+               if (HasVoidReturn (CurrentFunc)) {
+                   Error (ERR_CANNOT_RETURN_VALUE);
+               }
+               if (evalexpr (CF_NONE, hie0, &lval) == 0) {
+                   /* Constant value */
+                   etype = CF_CONST;
+               } else {
+           /* Value in the primary register */
+           HaveVal = 1;
+       }
+
+       /* Convert the return value to the type of the function result */
+       if (!HasVoidReturn (CurrentFunc)) {
+                   etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
+       }
+    } else if (!HasVoidReturn (CurrentFunc)) {
+               Error (ERR_MUST_RETURN_VALUE);
+    }
+    RestoreRegVars (HaveVal);
+    g_leave (etype, lval.e_const);
+}
+
+
+
+static void dobreak (void)
+/* Handle 'break' statement here */
+{
+    struct loopdesc* l;
+
+    gettok ();
+    if ((l = currentloop ()) == 0) {
+       /* Error: No current loop */
+               return;
+    }
+    g_space (oursp - l->sp);
+    g_jump (l->label);
+}
+
+
+
+static void docontinue (void)
+/* Handle 'continue' statement here */
+{
+    struct loopdesc* l;
+
+    gettok ();
+    if ((l = currentloop ()) == 0) {
+       /* Error: Not in loop */
+               return;
+    }
+    do {
+       if (l->loop) {
+           break;
+       }
+       l = l->next;
+    } while (l);
+    if (l == 0) {
+               Error (ERR_UNEXPECTED_CONTINUE);
+               return;
+    }
+    g_space (oursp - l->sp);
+    if (l->linc) {
+               g_jump (l->linc);
+    } else {
+               g_jump (l->loop);
+    }
+}
+
+
+
+static void cascadeswitch (struct expent* eval)
+/* Handle a switch statement for chars with a cmp cascade for the selector */
+{
+    unsigned exitlab;                  /* Exit label */
+    unsigned nextlab;                  /* Next case label */
+    unsigned codelab;          /* Label that starts the actual selector code */
+    int havebreak;             /* Remember if we exited with break */
+    int lcount;                        /* Label count */
+    unsigned flags;                    /* Code generator flags */
+    struct expent lval;                /* Case label expression */
+    long val;                  /* Case label value */
+
+
+    /* Create a loop so we may break out, init labels */
+    exitlab = GetLabel ();
+    addloop (oursp, 0, exitlab, 0, 0);
+
+    /* Setup some variables needed in the loop  below */
+    flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
+    codelab = nextlab = 0;
+    havebreak = 1;
+
+    /* Parse the labels */
+    lcount = 0;
+    while (curtok != RCURLY) {
+
+       if (curtok == CASE || curtok == DEFAULT) {
+
+           /* If the code for the previous selector did not end with a
+            * break statement, we must jump over the next selector test.
+            */
+           if (!havebreak) {
+               /* Define a label for the code */
+               if (codelab == 0) {
+                   codelab = GetLabel ();
+               }
+               g_jump (codelab);
+           }
+
+           /* If we have a cascade label, emit it */
+           if (nextlab) {
+               g_defloclabel (nextlab);
+               nextlab = 0;
+           }
+
+           while (curtok == CASE || curtok == DEFAULT) {
+
+               /* Parse the selector */
+               if (curtok == CASE) {
+
+                   /* Count labels */
+                   ++lcount;
+
+                   /* Skip the "case" token */
+                   gettok ();
+
+                   /* Read the selector expression */
+                   constexpr (&lval);
+                   if (!IsInt (lval.e_tptr)) {
+                       Error (ERR_ILLEGAL_TYPE);
+                   }
+
+                   /* Check the range of the expression */
+                   val = lval.e_const;
+                   switch (*eval->e_tptr) {
+
+                       case T_CHAR:
+                           /* Signed char */
+                           if (val < -128 || val > 127) {
+                               Error (ERR_RANGE);
+                           }
+                           break;
+
+                       case T_UCHAR:
+                           if (val < 0 || val > 255) {
+                               Error (ERR_RANGE);
+                           }
+                           break;
+
+                       case T_INT:
+                           if (val < -32768 || val > 32767) {
+                               Error (ERR_RANGE);
+                           }
+                           break;
+
+                       case T_UINT:
+                           if (val < 0 || val > 65535) {
+                               Error (ERR_RANGE);
+                           }
+                           break;
+
+                       default:
+                           Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
+                   }
+
+                   /* Skip the colon */
+                   ConsumeColon ();
+
+                   /* Emit a compare */
+                   g_cmp (flags, val);
+
+                   /* If another case follows, we will jump to the code if
+                    * the condition is true.
+                    */
+                   if (curtok == CASE) {
+                       /* Create a code label if needed */
+                       if (codelab == 0) {
+                           codelab = GetLabel ();
+                       }
+                       g_falsejump (CF_NONE, codelab);
+                   } else if (curtok != DEFAULT) {
+                       /* No case follows, jump to next selector */
+                       if (nextlab == 0) {
+                           nextlab = GetLabel ();
+                       }
+                       g_truejump (CF_NONE, nextlab);
+                   }
+
+               } else {
+
+                   /* Default case */
+                   gettok ();
+
+                   /* Skip the colon */
+                   ConsumeColon ();
+
+                   /* Handle the pathologic case: DEFAULT followed by CASE */
+                   if (curtok == CASE) {
+                       if (codelab == 0) {
+                           codelab = GetLabel ();
+                       }
+                       g_jump (codelab);
+                   }
+               }
+
+           }
+
+        }
+
+       /* Emit a code label if we have one */
+       if (codelab) {
+           g_defloclabel (codelab);
+           codelab = 0;
+       }
+
+       /* Parse statements */
+       if (curtok != RCURLY) {
+                   havebreak = statement ();
+       }
+    }
+
+    /* Check if we have any labels */
+    if (lcount == 0) {
+       Warning (WARN_NO_CASE_LABELS);
+    }
+
+    /* Eat the closing curly brace */
+    gettok ();
+
+    /* Define the exit label and, if there's a next label left, create this
+     * one, too.
+     */
+    if (nextlab) {
+       g_defloclabel (nextlab);
+    }
+    g_defloclabel (exitlab);
+
+    /* End the loop */
+    delloop ();
+}
+
+
+
+static void tableswitch (struct expent* eval)
+/* Handle a switch statement via table based selector */
+{
+    /* Entry for one case in a switch statement */
+    struct swent {
+       long     sw_const;      /* selector value */
+               unsigned sw_lab;        /* label for this selector */
+    };
+
+    int dlabel;                        /* for default */
+    int lab;                           /* exit label */
+    int label;                         /* label for case */
+    int lcase;                         /* label for compares */
+    int lcount;                        /* Label count */
+    int havebreak;             /* Last statement has a break */
+    unsigned flags;            /* Code generator flags */
+    struct expent lval;                /* Case label expression */
+    struct swent *p;
+    struct swent *swtab;
+
+    /* Allocate memory for the switch table */
+    swtab = xmalloc (CASE_MAX * sizeof (struct swent));
+
+    /* Create a look so we may break out, init labels */
+    havebreak = 0;             /* Keep gcc silent */
+    dlabel = 0;                        /* init */
+    lab = GetLabel ();         /* get exit */
+    p = swtab;
+    addloop (oursp, 0, lab, 0, 0);
+
+    /* Jump behind the code for the CASE labels */
+    g_jump (lcase = GetLabel ());
+    lcount = 0;
+    while (curtok != RCURLY) {
+       if (curtok == CASE || curtok == DEFAULT) {
+           if (lcount >= CASE_MAX) {
+                       Fatal (FAT_TOO_MANY_CASE_LABELS);
+           }
+           label = GetLabel ();
+           do {
+               if (curtok == CASE) {
+                           gettok ();
+                   constexpr (&lval);
+                   if (!IsInt (lval.e_tptr)) {
+                       Error (ERR_ILLEGAL_TYPE);
+                   }
+                   p->sw_const = lval.e_const;
+                   p->sw_lab = label;
+                   ++p;
+                   ++lcount;
+               } else {
+                   gettok ();
+                   dlabel = label;
+               }
+               ConsumeColon ();
+           } while (curtok == CASE || curtok == DEFAULT);
+           g_defloclabel (label);
+           havebreak = 0;
+       }
+       if (curtok != RCURLY) {
+           havebreak = statement ();
+       }
+    }
+
+    /* Check if we have any labels */
+    if (lcount == 0) {
+       Warning (WARN_NO_CASE_LABELS);
+    }
+
+    /* Eat the closing curly brace */
+    gettok ();
+
+    /* If the last statement doesn't have a break or return, add one */
+    if (!havebreak) {
+        g_jump (lab);
+    }
+
+    /* Actual selector code goes here */
+    g_defloclabel (lcase);
+
+    /* Create the call to the switch subroutine */
+    flags = TypeOf (eval->e_tptr);
+    g_switch (flags);
+
+    /* First entry is negative of label count */
+    g_defdata (CF_INT, -((int)lcount)-1, 0);
+
+    /* Create the case selector table */
+    AddCodeHint ("casetable");
+    p = swtab;
+    while (lcount) {
+               g_case (flags, p->sw_lab, p->sw_const); /* Create one label */
+       --lcount;
+       ++p;
+    }
+
+    if (dlabel) {
+               g_jump (dlabel);
+    }
+    g_defloclabel (lab);
+    delloop ();
+
+    /* Free the allocated space for the labels */
+    xfree (swtab);
+}
+
+
+
+static void doswitch (void)
+/* Handle 'switch' statement here */
+{
+    struct expent eval;                /* Switch statement expression */
+
+    /* Eat the "switch" */
+    gettok ();
+
+    /* Read the switch expression */
+    ConsumeLParen ();
+    intexpr (&eval);
+    ConsumeRParen ();
+
+    /* result of expr is in P */
+    ConsumeLCurly ();
+
+    /* Now decide which sort of switch we will create: */
+    if (IsChar (eval.e_tptr) || (FavourSize == 0 && IsInt (eval.e_tptr))) {
+               cascadeswitch (&eval);
+    } else {
+       tableswitch (&eval);
+    }
+}
+
+
+
+static void dofor (void)
+/* Handle 'for' statement here */
+{
+    int loop;
+    int lab;
+    int linc;
+    int lstat;
+    struct expent lval1;
+    struct expent lval2;
+    struct expent lval3;
+
+    gettok ();
+    loop = GetLabel ();
+    lab = GetLabel ();
+    linc = GetLabel ();
+    lstat = GetLabel ();
+    addloop (oursp, loop, lab, linc, lstat);
+    ConsumeLParen ();
+    if (curtok != SEMI) {      /* exp1 */
+       expression (&lval1);
+    }
+    ConsumeSemi ();
+    g_defloclabel (loop);
+    if (curtok != SEMI) {      /* exp2 */
+       boolexpr (&lval2);
+       g_truejump (CF_NONE, lstat);
+       g_jump (lab);
+    } else {
+       g_jump (lstat);
+    }
+    ConsumeSemi ();
+    g_defloclabel (linc);
+    if (curtok != RPAREN) {    /* exp3 */
+       expression (&lval3);
+    }
+    ConsumeRParen ();
+    g_jump (loop);
+    g_defloclabel (lstat);
+    statement ();
+    g_jump (linc);
+    g_defloclabel (lab);
+    delloop ();
+}
+
+
+
+static int statement (void)
+/* Statement parser. Called whenever syntax requires a statement.
+ * This routine performs that statement and returns 1 if it is a branch,
+ * 0 otherwise
+ */
+{
+    struct expent lval;
+
+    /* */
+    if (curtok == IDENT && nxttok == COLON) {
+
+       /* Special handling for a label */
+       DoLabel ();
+
+    } else {
+
+       switch (curtok) {
+
+           case LCURLY:
+               return compound ();
+
+           case IF:
+               return doif ();
+
+           case WHILE:
+               dowhile ('w');
+               break;
+
+           case DO:
+               dowhile ('d');
+               break;
+
+           case SWITCH:
+               doswitch ();
+               break;
+
+           case RETURN:
+               doreturn ();
+               ConsumeSemi ();
+               return 1;
+
+           case BREAK:
+               dobreak ();
+               ConsumeSemi ();
+               return 1;
+
+           case CONTINUE:
+               docontinue ();
+               ConsumeSemi ();
+               return 1;
+
+           case FOR:
+               dofor ();
+               break;
+
+           case GOTO:
+               DoGoto ();
+               ConsumeSemi ();
+               return 1;
+
+           case SEMI:
+               /* ignore it. */
+               gettok ();
+               break;
+
+           case PRAGMA:
+               DoPragma ();
+               break;
+
+           default:
+               AddCodeHint ("stmt:start");
+               expression (&lval);
+               AddCodeHint ("stmt:end");
+               ConsumeSemi ();
+       }
+    }
+    return 0;
+}
+
+
+
+int compound (void)
+/* Compound statement.         Allow any number of statements, inside braces. */
+{
+    static unsigned CurrentLevel = 0;
+
+    int isbrk;
+    int oldsp;
+
+    /* eat LCURLY */
+    gettok ();
+
+    /* Remember the stack at block entry */
+    oldsp = oursp;
+
+    /* If we're not on function level, enter a new lexical level */
+    if (CurrentLevel++ > 0) {
+       /* A nested block */
+       EnterBlockLevel ();
+    }
+
+    /* Parse local variable declarations if any */
+    DeclareLocals ();
+
+    /* Now process statements in the function body */
+    isbrk = 0;
+    while (curtok != RCURLY) {
+       if (curtok == CEOF)
+           break;
+       else {
+           isbrk = statement ();
+       }
+    }
+
+    /* Emit references to imports/exports for this block */
+    EmitExternals ();
+
+    /* If this is not the top level compound statement, clean up the stack.
+     * For a top level statement this will be done by the function exit code.
+     */
+    if (--CurrentLevel != 0) {
+       /* Some sort of nested block */
+       LeaveBlockLevel ();
+       if (isbrk) {
+           oursp = oldsp;
+       } else {
+           g_space (oursp - oldsp);
+           oursp = oldsp;
+       }
+    }
+
+    /* Eat closing brace */
+    ConsumeRCurly ();
+
+    return isbrk;
+}
+
+
+
diff --git a/src/cc65/stmt.h b/src/cc65/stmt.h
new file mode 100644 (file)
index 0000000..70bfa99
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * stmt.h
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#ifndef STMT_H
+#define STMT_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int compound ();
+/* Compound statement. Allow any number of statements, inside braces. */
+
+
+
+/* End of stmt.h */
+
+#endif
+
+
+
diff --git a/src/cc65/symentry.c b/src/cc65/symentry.c
new file mode 100644 (file)
index 0000000..e2b1a56
--- /dev/null
@@ -0,0 +1,154 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               symentry.c                                 */
+/*                                                                           */
+/*              Symbol table entries for the cc65 C compiler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "mem.h"
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+SymEntry* NewSymEntry (const char* Name, unsigned Flags)
+/* Create a new symbol table with the given name */
+{
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Allocate memory for the symbol entry */
+    SymEntry* E = xmalloc (sizeof (SymEntry) + Len);
+
+    /* Initialize the entry */
+    E->NextHash        = 0;
+    E->PrevSym = 0;
+    E->NextSym = 0;
+    E->Link    = 0;
+    E->Owner   = 0;
+    E->Flags   = Flags;
+    E->Type    = 0;
+    memcpy (E->Name, Name, Len+1);
+
+    /* Return the new entry */
+    return E;
+}
+
+
+
+void FreeSymEntry (SymEntry* E)
+/* Free a symbol entry */
+{
+    TypeFree (E->Type);
+    xfree (E);
+}
+
+
+
+void DumpSymEntry (FILE* F, const SymEntry* E)
+/* Dump the given symbol table entry to the file in readable form */
+{
+    static const struct {
+       const char*         Name;
+       unsigned            Val;
+    } Flags [] = {
+       /* Beware: Order is important! */
+       { "SC_TYPEDEF",     SC_TYPEDEF  },
+       { "SC_SFLD",        SC_SFLD     },
+       { "SC_STRUCT",      SC_STRUCT   },
+       { "SC_AUTO",        SC_AUTO     },
+       { "SC_REGISTER",    SC_REGISTER },
+       { "SC_STATIC",      SC_STATIC   },
+       { "SC_EXTERN",      SC_EXTERN   },
+       { "SC_ENUM",        SC_ENUM     },
+       { "SC_LABEL",       SC_LABEL    },
+       { "SC_PARAM",       SC_PARAM    },
+       { "SC_FUNC",        SC_FUNC     },
+       { "SC_STORAGE",     SC_STORAGE  },
+       { "SC_DEF",         SC_DEF      },
+       { "SC_REF",         SC_REF      },
+       { "SC_ZEROPAGE",    SC_ZEROPAGE },
+    };
+
+    unsigned I;
+    unsigned SymFlags;
+
+    /* Print the name */
+    fprintf (F, "%s:\n", E->Name);
+
+    /* Print the flags */
+    SymFlags = E->Flags;
+    fprintf (F, "    Flags: ");
+    for (I = 0; I < sizeof (Flags) / sizeof (Flags[0]) && SymFlags != 0; ++I) {
+       if ((SymFlags & Flags[I].Val) == Flags[I].Val) {
+           SymFlags &= ~Flags[I].Val;
+           fprintf (F, "%s ", Flags[I].Name);
+       }
+    }
+    if (SymFlags != 0) {
+       fprintf (F, "%04X", SymFlags);
+    }
+    fprintf (F, "\n");
+
+    /* Print the type */
+    fprintf (F, "    Type:  ");
+    if (E->Type) {
+       PrintType (F, E->Type);
+    } else {
+       fprintf (F, "(none)\n");
+    }
+}
+
+
+
+int IsTypeDef (const SymEntry* E)
+/* Return true if the given entry is a typedef entry */
+{
+    return ((E->Flags & SC_TYPEDEF) == SC_TYPEDEF);
+}
+
+
+
+void ChangeSymType (SymEntry* Entry, type* Type)
+/* Change the type of the given symbol */
+{
+    TypeFree (Entry->Type);
+    Entry->Type = TypeDup (Type);
+}
+
+
+
+
diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h
new file mode 100644 (file)
index 0000000..82f9458
--- /dev/null
@@ -0,0 +1,144 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               symentry.h                                 */
+/*                                                                           */
+/*              Symbol table entries for the cc65 C compiler                */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SYMENTRY_H
+#define SYMENTRY_H
+
+
+
+#include <stdio.h>
+
+#include "datatype.h"
+
+
+
+/*****************************************************************************/
+/*                             struct SymEntry                              */
+/*****************************************************************************/
+
+
+
+/* Storage classes and flags */
+#define SC_AUTO        0x0001U
+#define SC_REGISTER            0x0002U /* Register variable, is in static storage */
+#define SC_STATIC      0x0004U
+#define SC_EXTERN      0x0008U
+
+#define SC_ENUM                0x0010U /* An enum (numeric constant) */
+#define SC_LABEL               0x0020U /* A goto label */
+#define SC_PARAM               0x0040U /* This is a function parameter */
+#define SC_FUNC                0x0080U /* Function entry */
+
+#define SC_STORAGE             0x0100U /* Symbol with associated storage */
+#define SC_DEFAULT             0x0200U /* Flag: default storage class was used */
+
+#define SC_DEF         0x0400U /* Symbol is defined */
+#define SC_REF                 0x0800U /* Symbol is referenced */
+
+#define SC_TYPE                0x1000U /* This is a type, struct, typedef, etc. */
+#define SC_STRUCT              0x1001U /* Struct or union */
+#define SC_SFLD                0x1002U /* Struct or union field */
+#define SC_TYPEDEF             0x1003U /* A typedef */
+
+#define SC_ZEROPAGE    0x8000U /* Symbol marked as zeropage */
+
+
+
+/* Symbol table entry */
+typedef struct SymEntry SymEntry;
+struct SymEntry {
+    SymEntry*                          NextHash; /* Next entry in hash list */
+    SymEntry*                          PrevSym;  /* Previous symbol in dl list */
+    SymEntry*                          NextSym;  /* Next symbol double linked list */
+    SymEntry*                          Link;     /* General purpose single linked list */
+    struct SymTable*           Owner;    /* Symbol table the symbol is in */
+    unsigned                           Flags;    /* Symbol flags */
+    type*                              Type;     /* Symbol type */
+
+    /* Data that differs for the different symbol types */
+    union {
+
+       /* Offset for locals or struct members */
+       int                     Offs;
+
+       /* Label name for static symbols */
+       unsigned                Label;
+
+       /* Value for enums */
+       int                     EnumVal;
+
+       /* Data for structs/unions */
+       struct {
+           struct SymTable*    SymTab;   /* Member symbol table */
+           unsigned            Size;     /* Size of the union/struct */
+       } S;
+
+       /* Data for functions */
+       struct FuncDesc*        Func;     /* Function descriptor */
+
+    } V;
+    char                              Name[1]; /* Name, dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+SymEntry* NewSymEntry (const char* Name, unsigned Flags);
+/* Create a new symbol table with the given name */
+
+void FreeSymEntry (SymEntry* E);
+/* Free a symbol entry */
+
+void DumpSymEntry (FILE* F, const SymEntry* E);
+/* Dump the given symbol table entry to the file in readable form */
+
+int IsTypeDef (const SymEntry* E);
+/* Return true if the given entry is a typedef entry */
+
+void ChangeSymType (SymEntry* Entry, type* Type);
+/* Change the type of the given symbol */
+
+
+
+/* End of symentry.h */
+#endif
+
+
+
diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c
new file mode 100644 (file)
index 0000000..6db3fc4
--- /dev/null
@@ -0,0 +1,990 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                symtab.c                                  */
+/*                                                                           */
+/*             Symbol table management for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "global.h"
+#include "hashstr.h"
+#include "io.h"
+#include "mem.h"
+#include "symentry.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* An empty symbol table */
+SymTable       EmptySymTab = {
+    0,                 /* PrevTab */
+    0,         /* SymHead */
+    0,                 /* SymTail */
+    0,         /* SymCount */
+    1,         /* Size */
+    { 0        }       /* Tab[1] */
+};
+
+/* Symbol table sizes */
+#define SYMTAB_SIZE_GLOBAL             211U
+#define SYMTAB_SIZE_FUNCTION    29U
+#define SYMTAB_SIZE_BLOCK       13U
+#define SYMTAB_SIZE_STRUCT      19U
+#define SYMTAB_SIZE_LABEL        7U
+
+/* Predefined lexical levels */
+#define LEX_LEVEL_GLOBAL       1U
+
+/* The current and root symbol tables */
+static unsigned                LexicalLevel    = 0;    /* For safety checks */
+static SymTable*       SymTab0         = 0;
+static SymTable*       SymTab          = 0;
+static SymTable*       StructTab0      = 0;
+static SymTable*       StructTab       = 0;
+static SymTable*       EnumTab0        = 0;
+static SymTable*       EnumTab         = 0;
+static SymTable*       LabelTab        = 0;
+
+
+
+/*****************************************************************************/
+/*                             struct SymTable                              */
+/*****************************************************************************/
+
+
+
+static SymTable* NewSymTable (unsigned Size)
+/* Create and return a symbol table for the given lexical level */
+{
+    unsigned I;
+
+    /* Allocate memory for the table */
+    SymTable* S = xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
+
+    /* Initialize the symbol table structure */
+    S->PrevTab = 0;
+    S->SymHead = 0;
+    S->SymTail = 0;
+    S->SymCount        = 0;
+    S->Size    = Size;
+    for (I = 0; I < Size; ++I) {
+       S->Tab[I] = 0;
+    }
+
+    /* Return the symbol table */
+    return S;
+}
+
+
+
+static void FreeSymTable (SymTable* S)
+/* Free the given symbo table including all symbols */
+{
+    /* Free all symbols */
+    SymEntry* Sym = S->SymHead;
+    while (Sym) {
+       SymEntry* NextSym = Sym->NextSym;
+       FreeSymEntry (Sym);
+       Sym = NextSym;
+    }
+
+    /* Free the table itself */
+    xfree (S);
+}
+
+
+
+/*****************************************************************************/
+/*                        Check symbols in a table                          */
+/*****************************************************************************/
+
+
+
+static void CheckSymTable (SymTable* Tab)
+/* Check a symbol table for open references, unused symbols ... */
+{
+    SymEntry* Entry = Tab->SymHead;
+    while (Entry) {
+
+       /* Get the storage flags for tne entry */
+       unsigned Flags = Entry->Flags;
+
+       /* Ignore typedef entries */
+       if ((Flags & SC_TYPEDEF) != SC_TYPEDEF) {
+
+           /* Check if the symbol is one with storage, and it if it was
+            * defined but not used.
+            */
+           if (((Flags & SC_AUTO) || (Flags & SC_STATIC)) && (Flags & SC_EXTERN) == 0) {
+               if ((Flags & SC_DEF) && !(Flags & SC_REF)) {
+                   if (Flags & SC_PARAM) {
+                       Warning (WARN_UNUSED_PARM, Entry->Name);
+                   } else {
+                       Warning (WARN_UNUSED_ITEM, Entry->Name);
+                   }
+               }
+           }
+    
+           /* If the entry is a label, check if it was defined in the function */
+           if (Flags & SC_LABEL) {
+               if ((Flags & SC_DEF) == 0) {
+                   /* Undefined label */
+                   Error (ERR_UNDEFINED_LABEL, Entry->Name);
+               } else if ((Flags & SC_REF) == 0) {
+                   /* Defined but not used */
+                   Warning (WARN_UNUSED_ITEM, Entry->Name);
+               }
+           }
+    
+       }
+
+       /* Next entry */
+       Entry = Entry->NextSym;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                       Handling of lexical levels                         */
+/*****************************************************************************/
+
+
+
+void EnterGlobalLevel (void)
+/* Enter the program global lexical level */
+{
+    /* Safety */
+    PRECONDITION (++LexicalLevel == LEX_LEVEL_GLOBAL);
+
+    /* Create and assign the symbol table */
+    SymTab0 = SymTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+
+    /* Create and assign the struct table */
+    StructTab0 = StructTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+
+    /* Create and assign the enum table */
+    EnumTab0 = EnumTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+}
+
+
+
+void LeaveGlobalLevel (void)
+/* Leave the program global lexical level */
+{
+    /* Safety */
+    PRECONDITION (LexicalLevel-- == LEX_LEVEL_GLOBAL);
+
+    /* Check the tables */
+    CheckSymTable (SymTab0);
+
+    /* Dump the tables if requested */
+    if (Debug) {
+       PrintSymTable (SymTab0, stdout, "Global symbol table");
+       PrintSymTable (StructTab0, stdout, "Global struct table");
+       PrintSymTable (EnumTab0, stdout, "Global enum table");
+    }
+
+    /* Don't delete the symbol and struct tables! */
+    SymTab0    = SymTab    = 0;
+    StructTab0 = StructTab = 0;
+    EnumTab0   = EnumTab   = 0;
+}
+
+
+
+void EnterFunctionLevel (void)
+/* Enter function lexical level */
+{
+    SymTable* S;
+
+    /* New lexical level */
+    ++LexicalLevel;
+
+    /* Get a new symbol table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+    S->PrevTab = SymTab;
+    SymTab     = S;
+
+    /* Get a new struct table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+    S->PrevTab = StructTab;
+    StructTab  = S;
+
+    /* Get a new enum table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+    S->PrevTab = EnumTab;
+    EnumTab    = S;
+
+    /* Create and assign a new label table */
+    LabelTab = NewSymTable (SYMTAB_SIZE_LABEL);
+}
+
+
+
+void RememberFunctionLevel (struct FuncDesc* F)
+/* Remember the symbol tables for the level and leave the level without checks */
+{
+    /* Leave the lexical level */
+    --LexicalLevel;
+
+    /* Remember the tables */
+    F->SymTab   = SymTab;
+    F->StructTab = StructTab;
+    F->EnumTab  = EnumTab;
+
+    /* Don't delete the tables */
+    SymTab    = SymTab->PrevTab;
+    StructTab = StructTab->PrevTab;
+    EnumTab   = EnumTab->PrevTab;
+}
+
+
+
+void ReenterFunctionLevel (struct FuncDesc* F)
+/* Reenter the function lexical level using the existing tables from F */
+{
+    /* New lexical level */
+    ++LexicalLevel;
+
+    /* Make the tables current again */
+    F->SymTab->PrevTab = SymTab;
+    SymTab = F->SymTab;
+
+    F->StructTab->PrevTab = StructTab;
+    StructTab = F->StructTab;
+
+    F->EnumTab->PrevTab = EnumTab;
+    EnumTab = F->EnumTab;
+
+    /* Create and assign a new label table */
+    LabelTab = NewSymTable (SYMTAB_SIZE_LABEL);
+}
+
+
+
+void LeaveFunctionLevel (void)
+/* Leave function lexical level */
+{
+    /* Leave the lexical level */
+    --LexicalLevel;
+
+    /* Check the tables */
+    CheckSymTable (SymTab);
+    CheckSymTable (LabelTab);
+
+    /* Drop the label table if it is empty */
+    if (LabelTab->SymCount == 0) {
+       FreeSymTable (LabelTab);
+    }
+
+    /* Don't delete the tables */
+    SymTab    = SymTab->PrevTab;
+    StructTab = StructTab->PrevTab;
+    EnumTab   = EnumTab->PrevTab;
+    LabelTab  = 0;
+}
+
+
+
+void EnterBlockLevel (void)
+/* Enter a nested block in a function */
+{
+    SymTable* S;
+
+    /* New lexical level */
+    ++LexicalLevel;
+
+    /* Get a new symbol table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_BLOCK);
+    S->PrevTab         = SymTab;
+    SymTab             = S;
+
+    /* Get a new struct table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_BLOCK);
+    S->PrevTab         = StructTab;
+    StructTab   = S;
+
+    /* Get a new enum table and make it current */
+    S = NewSymTable (SYMTAB_SIZE_BLOCK);
+    S->PrevTab = EnumTab;
+    EnumTab    = S;
+}
+
+
+
+void LeaveBlockLevel (void)
+/* Leave a nested block in a function */
+{
+    /* Leave the lexical level */
+    --LexicalLevel;
+
+    /* Check the tables */
+    CheckSymTable (SymTab);
+
+    /* Don't delete the tables */
+    SymTab    = SymTab->PrevTab;
+    StructTab = StructTab->PrevTab;
+    EnumTab   = EnumTab->PrevTab;
+}
+
+
+
+void EnterStructLevel (void)
+/* Enter a nested block for a struct definition */
+{
+    SymTable* S;
+
+    /* Get a new symbol table and make it current. Note: Structs and enums
+     * nested in struct scope are NOT local to the struct but visible in the
+     * outside scope. So we will NOT create a new struct or enum table.
+     */
+    S = NewSymTable (SYMTAB_SIZE_BLOCK);
+    S->PrevTab         = SymTab;
+    SymTab             = S;
+}
+
+
+
+void LeaveStructLevel (void)
+/* Leave a nested block for a struct definition */
+{
+    /* Don't delete the table */
+    SymTab = SymTab->PrevTab;
+}
+
+
+
+/*****************************************************************************/
+/*                             Find functions                               */
+/*****************************************************************************/
+
+
+
+static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned Hash)
+/* Search for an entry in one table */
+{
+    /* Get the start of the hash chain */
+    SymEntry* E = T->Tab [Hash % T->Size];
+    while (E) {
+       /* Compare the name */
+       if (strcmp (E->Name, Name) == 0) {
+           /* Found */
+           return E;
+       }
+       /* Not found, next entry in hash chain */
+       E = E->NextHash;
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
+/* Find the symbol with the given name in the table tree that starts with T */
+{
+    /* Get the hash over the name */
+    unsigned Hash = HashStr (Name);
+
+    /* Check all symbol tables for the symbol */
+    while (Tab) {
+       /* Try to find the symbol in this table */
+       SymEntry* E = FindSymInTable (Tab, Name, Hash);
+
+       /* Bail out if we found it */
+       if (E != 0) {
+           return E;
+       }
+
+       /* Repeat the search in the next higher lexical level */
+       Tab = Tab->PrevTab;
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+SymEntry* FindSym (const char* Name)
+/* Find the symbol with the given name */
+{
+    return FindSymInTree (SymTab, Name);
+}
+
+
+
+SymEntry* FindStructSym (const char* Name)
+/* Find the symbol with the given name in the struct table */
+{
+    return FindSymInTree (StructTab, Name);
+}
+
+
+
+SymEntry* FindEnumSym (const char* Name)
+/* Find the symbol with the given name in the enum table */
+{
+    return FindSymInTree (EnumTab, Name);
+}
+
+
+
+SymEntry* FindStructField (const type* Type, const char* Name)
+/* Find a struct field in the fields list */
+{
+    SymEntry* Field = 0;
+
+    /* The given type may actually be a pointer to struct */
+    if (Type[0] == T_PTR) {
+       ++Type;
+    }
+
+    /* Non-structs do not have any struct fields... */
+    if (IsStruct (Type)) {
+
+       const SymTable* Tab;
+
+       /* Get a pointer to the struct/union type */
+       const SymEntry* Struct = (const SymEntry*) Decode (Type+1);
+       CHECK (Struct != 0);
+
+       /* Get the field symbol table from the struct entry.
+        * Beware: The table may not exist.
+        */
+       Tab = Struct->V.S.SymTab;
+
+       /* Now search in the struct symbol table */
+       if (Tab) {
+                   Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
+       }
+    }
+
+    return Field;
+}
+
+
+
+/*****************************************************************************/
+/*                      Add stuff to the symbol table                       */
+/*****************************************************************************/
+
+
+
+static void AddSymEntry (SymTable* T, SymEntry* S)
+/* Add a symbol to a symbol table */
+{
+    /* Get the hash value for the name */
+    unsigned Hash = HashStr (S->Name) % T->Size;
+
+    /* Insert the symbol into the list of all symbols in this level */
+    if (T->SymTail) {
+               T->SymTail->NextSym = S;
+    }
+    S->PrevSym = T->SymTail;
+    T->SymTail = S;
+    if (T->SymHead == 0) {
+       /* First symbol */
+       T->SymHead = S;
+    }
+    T->SymCount++;
+
+    /* Insert the symbol into the hash chain */
+    S->NextHash  = T->Tab[Hash];
+    T->Tab[Hash] = S;
+
+    /* Tell the symbol in which table it is */
+    S->Owner = T;
+}
+
+
+
+SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab)
+/* Add a struct/union entry and return it */
+{
+    /* Do we have an entry with this name already? */
+    SymEntry* Entry = FindSymInTable (StructTab, Name, HashStr (Name));
+    if (Entry) {
+
+       /* We do have an entry. This may be a forward, so check it. */
+       if (Entry->Flags != SC_STRUCT) {
+           /* Existing symbol is not a struct */
+           Error (ERR_SYMBOL_KIND);
+       } else if (Size > 0 && Entry->V.S.Size > 0) {
+           /* Both structs are definitions. */
+           Error (ERR_MULTIPLE_DEFINITION, Name);
+       } else {
+           /* Define the struct size if it is given */
+           if (Size > 0) {
+               Entry->V.S.SymTab = Tab;
+               Entry->V.S.Size   = Size;
+           }
+       }
+
+    } else {
+
+       /* Create a new entry */
+       Entry = NewSymEntry (Name, SC_STRUCT);
+
+       /* Set the struct data */
+       Entry->V.S.SymTab = Tab;
+       Entry->V.S.Size   = Size;
+
+       /* Add it to the current table */
+       AddSymEntry (StructTab, Entry);
+    }
+
+    /* Return the entry */
+    return Entry;
+}
+
+
+
+SymEntry* AddEnumSym (const char* Name, int Val)
+/* Add an enum symbol to the symbol table and return it */
+{
+    /* Do we have an entry with this name already? */
+    SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+    if (Entry) {
+       if (Entry->Flags != SC_ENUM) {
+           Error (ERR_SYMBOL_KIND);
+       } else {
+           Error (ERR_MULTIPLE_DEFINITION, Name);
+       }
+       return Entry;
+    }
+
+    /* Create a new entry */
+    Entry = NewSymEntry (Name, SC_ENUM);
+
+    /* Enum values are ints */
+    Entry->Type        = TypeDup (type_int);
+
+    /* Set the enum data */
+    Entry->V.EnumVal = Val;
+
+    /* Add the entry to the symbol table */
+    AddSymEntry (SymTab, Entry);
+
+    /* Return the entry */
+    return Entry;
+}
+
+
+
+SymEntry* AddLabelSym (const char* Name, unsigned Flags)
+/* Add a goto label to the label table */
+{
+    /* Do we have an entry with this name already? */
+    SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
+    if (Entry) {
+
+       if ((Entry->Flags & SC_DEF) != 0 && (Flags & SC_DEF) != 0) {
+           /* Trying to define the label more than once */
+                   Error (ERR_MULTIPLE_DEFINITION, Name);
+       }
+       Entry->Flags |= Flags;
+
+    } else {
+
+       /* Create a new entry */
+       Entry = NewSymEntry (Name, SC_LABEL | Flags);
+
+       /* Set a new label number */
+       Entry->V.Label = GetLabel ();
+
+       /* Add the entry to the label table */
+       AddSymEntry (LabelTab, Entry);
+
+    }
+
+    /* Return the entry */
+    return Entry;
+}
+
+
+
+SymEntry* AddLocalSym (const char* Name, type* Type, unsigned Flags, int Offs)
+/* Add a local symbol and return the symbol entry */
+{
+    SymEntry* Entry;
+
+    /* Functions declared inside of functions do always have external linkage */
+    if (Type != 0 && IsFunc (Type)) {
+               if ((Flags & (SC_DEFAULT | SC_EXTERN)) == 0) {
+                   Warning (WARN_FUNC_MUST_BE_EXTERN);
+               }
+               Flags = SC_EXTERN;
+    }
+
+    /* Do we have an entry with this name already? */
+    Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+    if (Entry) {
+
+       /* We have a symbol with this name already */
+       Error (ERR_MULTIPLE_DEFINITION, Name);
+
+    } else {
+
+       /* Create a new entry */
+       Entry = NewSymEntry (Name, Flags);
+
+       /* Set the symbol attributes */
+       Entry->Type   = TypeDup (Type);
+       Entry->V.Offs = Offs;
+
+       /* Add the entry to the symbol table */
+       AddSymEntry (SymTab, Entry);
+
+    }
+
+    /* Return the entry */
+    return Entry;
+}
+
+
+
+SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags)
+/* Add an external or global symbol to the symbol table and return the entry */
+{
+    /* Functions must be inserted in the global symbol table */
+    SymTable* Tab = IsFunc (Type)? SymTab0 : SymTab;
+
+    /* Do we have an entry with this name already? */
+    SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
+    if (Entry) {
+
+       type* EType;
+
+       /* We have a symbol with this name already */
+       if (Entry->Flags & SC_TYPE) {
+           Error (ERR_MULTIPLE_DEFINITION, Name);
+           return Entry;
+       }
+
+       /* Get the type string of the existing symbol */
+       EType = Entry->Type;
+
+       /* If we are handling arrays, the old entry or the new entry may be an
+        * incomplete declaration. Accept this, and if the exsting entry is
+        * incomplete, complete it.
+        */
+       if (IsArray (Type) && IsArray (EType)) {
+
+           /* Get the array sizes */
+           unsigned Size  = Decode (Type + 1);
+           unsigned ESize = Decode (EType + 1);
+
+           if ((Size != 0 && ESize != 0) ||
+               TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) != 0) {
+               /* Types not identical: Duplicate definition */
+               Error (ERR_MULTIPLE_DEFINITION, Name);
+           } else {
+               /* Check if we have a size in the existing definition */
+               if (ESize == 0) {
+                   /* Existing, size not given, use size from new def */
+                   Encode (EType + 1, Size);
+               }
+           }
+
+               } else {
+           /* New type must be identical */
+           if (!EqualTypes (EType, Type) != 0) {
+               Error (ERR_MULTIPLE_DEFINITION, Name);
+           }
+
+           /* In case of a function, use the new type descriptor, since it
+            * contains pointers to the new symbol tables that are needed if
+            * an actual function definition follows.
+            */
+           if (IsFunc (Type)) {
+               CopyEncode (Type+1, EType+1);
+           }
+       }
+
+       /* Add the new flags */
+       Entry->Flags |= Flags;
+
+    } else {
+
+       /* Create a new entry */
+       Entry = NewSymEntry (Name, Flags);
+
+       /* Set the symbol attributes */
+       Entry->Type = TypeDup (Type);
+
+       /* Add the entry to the symbol table */
+       AddSymEntry (Tab, Entry);
+    }
+
+    /* Return the entry */
+    return Entry;
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+SymTable* GetSymTab (void)
+/* Return the current symbol table */
+{
+    return SymTab;
+}
+
+
+
+static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
+/* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
+{
+    /* Compare the parameter lists */
+    SymEntry* Sym1 = Tab1->SymHead;
+    SymEntry* Sym2 = Tab2->SymHead;
+
+    /* Compare the fields */
+    while (Sym1 && Sym2) {
+
+       /* Compare this field */
+       if (!EqualTypes (Sym1->Type, Sym2->Type)) {
+           /* Field types not equal */
+           return 0;
+       }
+
+       /* Get the pointers to the next fields */
+       Sym1 = Sym1->NextSym;
+       Sym2 = Sym2->NextSym;
+    }
+
+    /* Check both pointers against NULL to compare the field count */
+    return (Sym1 == 0 && Sym2 == 0);
+}
+
+
+
+int EqualTypes (const type* Type1, const type* Type2)
+/* Recursively compare two types. Return 1 if the types match, return 0
+ * otherwise.
+ */
+{
+    int v1, v2;
+    SymEntry* Sym1;
+    SymEntry* Sym2;
+    SymTable* Tab1;
+    SymTable* Tab2;
+    FuncDesc* F1;
+    FuncDesc* F2;
+
+
+    /* Shortcut here: If the pointers are identical, the types are identical */
+    if (Type1 == Type2) {
+       return 1;
+    }
+
+    /* Compare two types. Determine, where they differ */
+    while (*Type1 == *Type2 && *Type1 != T_END) {
+
+       switch (*Type1) {
+
+           case T_FUNC:
+               /* Compare the function descriptors */
+               F1 = DecodePtr (Type1+1);
+               F2 = DecodePtr (Type2+1);
+               if ((F1->Flags & ~FD_IMPLICIT) != (F2->Flags & ~FD_IMPLICIT)) {
+                   /* Flags differ */
+                   return 0;
+               }
+
+               /* Compare the parameter lists */
+               if (EqualSymTables (F1->SymTab, F2->SymTab)       == 0 ||
+                   EqualSymTables (F1->StructTab, F2->StructTab) == 0 ||
+                   EqualSymTables (F1->EnumTab, F2->EnumTab) == 0) {
+                   /* One of the tables is not identical */
+                   return 0;
+               }
+
+               /* Skip the FuncDesc pointers to compare the return type */
+               Type1 += DECODE_SIZE;
+               Type2 += DECODE_SIZE;
+               break;
+
+           case T_ARRAY:
+               /* Check member count */
+               v1 = Decode (Type1+1);
+               v2 = Decode (Type2+1);
+               if (v1 != 0 && v2 != 0 && v1 != v2) {
+                   /* Member count given but different */
+                   return 0;
+               }
+               Type1 += DECODE_SIZE;
+               Type2 += DECODE_SIZE;
+               break;
+
+           case T_STRUCT:
+           case T_UNION:
+                       /* Compare the fields recursively. To do that, we fetch the
+                * pointer to the struct definition from the type, and compare
+                * the fields.
+                */
+               Sym1 = DecodePtr (Type1+1);
+               Sym2 = DecodePtr (Type2+1);
+
+               /* Get the field tables from the struct entry */
+               Tab1 = Sym1->V.S.SymTab;
+               Tab2 = Sym2->V.S.SymTab;
+
+               /* One or both structs may be forward definitions. In this case,
+                * the symbol tables are both non existant. Assume that the
+                * structs are equal in this case.
+                */
+               if (Tab1 != 0 && Tab2 != 0) {
+
+                   if (EqualSymTables (Tab1, Tab2) == 0) {
+                       /* Field lists are not equal */
+                       return 0;
+                   }
+
+               }
+
+               /* Structs are equal */
+               Type1 += DECODE_SIZE;
+               Type2 += DECODE_SIZE;
+               break;
+       }
+       ++Type1;
+               ++Type2;
+    }
+
+    /* Done, types are equal */
+    return 1;
+}
+
+
+
+void MakeZPSym (const char* Name)
+/* Mark the given symbol as zero page symbol */
+{
+    /* Get the symbol table entry */
+    SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+
+    /* Mark the symbol as zeropage */
+    if (Entry) {
+       Entry->Flags |= SC_ZEROPAGE;
+    } else {
+       Error (ERR_UNDEFINED_SYMBOL, Name);
+    }
+}
+
+
+
+void PrintSymTable (const SymTable* Tab, FILE* F, const char* Header, ...)
+/* Write the symbol table to the given file */
+{
+    unsigned Len;
+    const SymEntry* Entry;
+
+    /* Print the header */
+    va_list ap;
+    va_start (ap, Header);
+    fputc ('\n', F);
+    Len = vfprintf (F, Header, ap);
+    va_end (ap);
+    fputc ('\n', F);
+
+    /* Underline the header */
+    while (Len--) {
+       fputc ('=', F);
+    }
+    fputc ('\n', F);
+
+    /* Dump the table */
+    Entry = Tab->SymHead;
+    if (Entry == 0) {
+       fprintf (F, "(empty)\n");
+    } else {
+       while (Entry) {
+           DumpSymEntry (F, Entry);
+           Entry = Entry->NextSym;
+       }
+    }
+    fprintf (F, "\n\n\n");
+}
+
+
+
+void EmitExternals (void)
+/* Write import/export statements for external symbols */
+{
+    SymEntry* Entry;
+
+    AddEmptyLine ();
+
+    Entry = SymTab->SymHead;
+    while (Entry) {
+       unsigned Flags = Entry->Flags;
+               if (Flags & SC_EXTERN) {
+           /* Only defined or referenced externs */
+           if ((Flags & SC_REF) != 0 && (Flags & SC_DEF) == 0) {
+               /* An import */
+               g_defimport (Entry->Name, Flags & SC_ZEROPAGE);
+           } else if (Flags & SC_DEF) {
+               /* An export */
+               g_defexport (Entry->Name, Flags & SC_ZEROPAGE);
+           }
+       }
+       Entry = Entry->NextSym;
+    }
+}
+
+
+
diff --git a/src/cc65/symtab.h b/src/cc65/symtab.h
new file mode 100644 (file)
index 0000000..996941e
--- /dev/null
@@ -0,0 +1,187 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                symtab.h                                  */
+/*                                                                           */
+/*             Symbol table management for the cc65 C compiler              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SYMTAB_H
+#define SYMTAB_H
+
+
+
+#include <stdio.h>
+
+#include "datatype.h"
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Symbol table */
+typedef struct SymTable SymTable;
+struct SymTable {
+    SymTable*                  PrevTab;        /* Pointer to higher level symbol table */
+    SymEntry*                  SymHead;        /* Double linked list of symbols */
+    SymEntry*                  SymTail;        /* Double linked list of symbols */
+    unsigned                   SymCount;       /* Count of symbols in this table */
+    unsigned                   Size;           /* Size of table */
+    SymEntry*                  Tab[1];         /* Actual table, dynamically allocated */
+};
+
+/* An empty symbol table */
+extern SymTable                EmptySymTab;
+
+/* Forwards */
+struct FuncDesc;
+
+
+
+/*****************************************************************************/
+/*                       Handling of lexical levels                         */
+/*****************************************************************************/
+
+
+
+void EnterGlobalLevel (void);
+/* Enter the program global lexical level */
+
+void LeaveGlobalLevel (void);
+/* Leave the program global lexical level */
+
+void EnterFunctionLevel (void);
+/* Enter function lexical level */
+
+void RememberFunctionLevel (struct FuncDesc* F);
+/* Remember the symbol tables for the level and leave the level without checks */
+
+void ReenterFunctionLevel (struct FuncDesc* F);
+/* Reenter the function lexical level using the existing tables from F */
+
+void LeaveFunctionLevel (void);
+/* Leave function lexical level */
+
+void EnterBlockLevel (void);
+/* Enter a nested block in a function */
+
+void LeaveBlockLevel (void);
+/* Leave a nested block in a function */
+
+void EnterStructLevel (void);
+/* Enter a nested block for a struct definition */
+
+void LeaveStructLevel (void);
+/* Leave a nested block for a struct definition */
+
+
+
+/*****************************************************************************/
+/*                             Find functions                               */
+/*****************************************************************************/
+
+
+
+SymEntry* FindSym (const char* Name);
+/* Find the symbol with the given name */
+
+SymEntry* FindStructSym (const char* Name);
+/* Find the symbol with the given name in the struct table */
+
+SymEntry* FindEnumSym (const char* Name);
+/* Find the symbol with the given name in the enum table */
+
+SymEntry* FindStructField (const type* TypeArray, const char* Name);
+/* Find a struct field in the fields list */
+
+
+
+/*****************************************************************************/
+/*                      Add stuff to the symbol table                       */
+/*****************************************************************************/
+
+
+
+SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab);
+/* Add a struct/union entry and return it */
+
+SymEntry* AddEnumSym (const char* Name, int Val);
+/* Add an enum symbol to the symbol table and return it */
+
+SymEntry* AddLabelSym (const char* Name, unsigned Flags);
+/* Add a goto label to the symbol table */
+
+SymEntry* AddLocalSym (const char* Name, type* Type, unsigned Flags, int Offs);
+/* Add a local symbol and return the symbol entry */
+
+SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags);
+/* Add an external or global symbol to the symbol table and return the entry */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+SymTable* GetSymTab (void);
+/* Return the current symbol table */
+
+int EqualTypes (const type* t1, const type* t2);
+/* Recursively compare two types. Return 1 if the types match, return 0
+ * otherwise.
+ */
+
+void MakeZPSym (const char* Name);
+/* Mark the given symbol as zero page symbol */
+
+void PrintSymTable (const SymTable* Tab, FILE* F, const char* Header, ...);
+/* Write the symbol table to the given file */
+
+void EmitExternals (void);
+/* Write import/export statements for external symbols */
+
+
+
+/* End of symtab.h */
+
+#endif
+
+
+
+
+
+
diff --git a/src/cc65/util.c b/src/cc65/util.c
new file mode 100644 (file)
index 0000000..c39232d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * util.c
+ *
+ * Ullrich von Bassewitz, 18.06.1998
+ */
+
+
+
+#include "util.h"
+
+
+
+/*****************************************************************************/
+/*                                  data                                    */
+/*****************************************************************************/
+
+
+
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int IsBlank (char c)
+/* Return true if c is a space, tab or newline */
+{
+    return (c == ' ' || c == '\t' || c == '\n');
+}
+
+
+
+int IsQuoteChar (char c)
+/* Return true if c is a single or double quote */
+{
+    return (c == '"' || c == '\'');
+}
+
+
+
+int powerof2 (unsigned long val)
+/* Return the exponent if val is a power of two. Return -1 if val is not a
+ * power of two.
+ */
+{
+    int i;
+    unsigned long mask;
+    mask = 0x0001;
+
+    for (i = 0; i < 32; ++i) {
+       if (val == mask) {
+           return i;
+       }
+       mask <<= 1;
+    }
+    return -1;
+}
+
+
+
diff --git a/src/cc65/util.h b/src/cc65/util.h
new file mode 100644 (file)
index 0000000..240a3ec
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * util.h
+ *
+ * Ullrich von Bassewitz, 18.06.1998
+ */
+
+
+
+#ifndef UTIL_H
+#define UTIL_H
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+int IsBlank (char c);
+/* Return true if c is a space, tab or newline */
+
+int IsQuoteChar (char c);
+/* Return true if c is a single or double quote */
+
+int powerof2 (unsigned long val);
+/* Return the exponent if val is a power of two. Return -1 if val is not a
+ * power of two.
+ */
+
+
+
+/* End of util.h */
+
+#endif
+
+
+
diff --git a/src/cl65/.cvsignore b/src/cl65/.cvsignore
new file mode 100644 (file)
index 0000000..cd4a303
--- /dev/null
@@ -0,0 +1,3 @@
+cl65
+cl65.exe
+.depend
diff --git a/src/cl65/error.c b/src/cl65/error.c
new file mode 100644 (file)
index 0000000..87200b0
--- /dev/null
@@ -0,0 +1,107 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*        Error handling for the cl65 compile and link utility              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "global.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+    "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+    "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+    "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "%s: ", ProgName);
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "%s: ", ProgName);
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "%s: Internal error: ", ProgName);
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
diff --git a/src/cl65/error.h b/src/cl65/error.h
new file mode 100644 (file)
index 0000000..e029eb5
--- /dev/null
@@ -0,0 +1,87 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*        Error handling for the cl65 compile and link utility              */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c)                                                       \
+    if (!(c))                                                          \
+       Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c)                                                        \
+    if (!(c))                                                          \
+               Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s)                                                                \
+    Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
diff --git a/src/cl65/global.c b/src/cl65/global.c
new file mode 100644 (file)
index 0000000..d56716e
--- /dev/null
@@ -0,0 +1,49 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*         Global variables for the cl65 compile and link utility           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+const char* ProgName               = "cl65";   /* Program name */
+
+
+
diff --git a/src/cl65/global.h b/src/cl65/global.h
new file mode 100644 (file)
index 0000000..4992594
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*         Global variables for the cl65 compile and link utility           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+extern const char*     ProgName;       /* Program name */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
diff --git a/src/cl65/main.c b/src/cl65/main.c
new file mode 100644 (file)
index 0000000..73201e5
--- /dev/null
@@ -0,0 +1,853 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                 main.c                                   */
+/*                                                                          */
+/*            Main module for the cl65 compile and link utility             */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1999-2000 Ullrich von Bassewitz                                      */
+/*              Wacholderweg 14                                             */
+/*              D-70597 Stuttgart                                           */
+/* EMail:       uz@musoftware.de                                            */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef __WATCOMC__
+#  include <process.h>         /* DOS, OS/2 and Windows */
+#else
+#  include "spawn.h"           /* All others */
+#endif
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Struct that describes a command */
+typedef struct CmdDesc_ CmdDesc;
+struct CmdDesc_ {
+    char*      Name;           /* The command name */
+
+    unsigned   ArgCount;       /* Count of arguments */
+    unsigned   ArgMax;         /* Maximum count of arguments */
+    char**     Args;           /* The arguments */
+
+    unsigned   FileCount;      /* Count of files to translate */
+    unsigned   FileMax;        /* Maximum count of files */
+    char**     Files;          /* The files */
+};
+
+/* Command descriptors for the different programs */
+static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
+static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
+static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
+
+/* File types */
+enum {
+    FILETYPE_UNKNOWN,
+    FILETYPE_C,
+    FILETYPE_ASM,
+    FILETYPE_OBJ,
+    FILETYPE_LIB
+};
+
+/* Default file type, used if type unknown */
+static unsigned DefaultFileType = FILETYPE_UNKNOWN;
+
+/* Variables controlling the steps we're doing */
+static int DontLink    = 0;
+static int DontAssemble = 0;
+
+/* The name of the output file, NULL if none given */
+static const char* OutputName = 0;
+
+/* The name of the linker configuration file if given */
+static const char* LinkerConfig = 0;
+
+/* The name of the first input file. This will be used to construct the
+ * executable file name if no explicit name is given.
+ */
+static const char* FirstInput = 0;
+
+/* The target system */
+enum {
+    TGT_UNKNOWN = -1,
+    TGT_NONE,
+    TGT_FIRSTREAL,
+    TGT_ATARI = TGT_FIRSTREAL,
+    TGT_C64,
+    TGT_C128,
+    TGT_ACE,
+    TGT_PLUS4,
+    TGT_CBM610,
+    TGT_PET,
+    TGT_NES,
+    TGT_APPLE2,
+    TGT_GEOS,
+    TGT_COUNT
+} Target = TGT_UNKNOWN;
+
+/* Names of the target systems sorted by target name */
+static const char* TargetNames [] = {
+    "none",
+    "atari",
+    "c64",
+    "c128",
+    "ace",
+    "plus4",
+    "cbm610",
+    "pet",
+    "nes",
+    "apple2",
+    "geos",
+};
+
+/* Name of the crt0 object file and the runtime library */
+static char* TargetCRT0 = 0;
+static char* TargetLib = 0;
+
+
+
+/*****************************************************************************/
+/*                             String handling                              */
+/*****************************************************************************/
+
+
+
+static const char* FindExt (const char* Name)
+/* Return a pointer to the file extension in Name or NULL if there is none */
+{
+    const char* S;
+
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+    if (Len < 2) {
+       return 0;
+    }
+
+    /* Get a pointer to the last character */
+    S = Name + Len - 1;
+
+    /* Search for the dot, beware of subdirectories */
+    while (S >= Name && *S != '.' && *S != '\\' && *S != '/') {
+       --S;
+    }
+
+    /* Did we find an extension? */
+    if (*S == '.') {
+       return S;
+    } else {
+       return 0;
+    }
+}
+
+
+
+static char* ForceExt (const char* Name, const char* Ext)
+/* Return a new filename with the new extension */
+{
+    char* Out;
+    const char* P = FindExt (Name);
+    if (P == 0) {
+       /* No dot, add the extension */
+       Out = Xmalloc (strlen (Name) + strlen (Ext) + 1);
+       strcpy (Out, Name);
+       strcat (Out, Ext);
+    } else {
+       Out = Xmalloc (P - Name + strlen (Ext) + 1);
+       memcpy (Out, Name, P - Name);
+       strcpy (Out + (P - Name), Ext);
+    }
+    return Out;
+}
+
+
+
+/*****************************************************************************/
+/*                          Determine a file type                           */
+/*****************************************************************************/
+
+
+
+static unsigned GetFileType (const char* File)
+/* Determine the type of the given file */
+{
+    /* Table mapping extensions to file types */
+    static const struct {
+       const char*     Ext;
+       unsigned        Type;
+    } FileTypes [] = {
+       {   ".c",       FILETYPE_C      },
+       {   ".s",       FILETYPE_ASM    },
+       {   ".asm",     FILETYPE_ASM    },
+       {   ".o",       FILETYPE_OBJ    },
+       {   ".obj",     FILETYPE_OBJ    },
+       {   ".a",       FILETYPE_LIB    },
+       {   ".lib",     FILETYPE_LIB    },
+    };
+
+    unsigned I;
+
+    /* Determine the file type by the extension */
+    const char* Ext = FindExt (File);
+
+    /* Do we have an extension? */
+    if (Ext == 0) {
+       return DefaultFileType;
+    }
+
+    /* Check for known extensions */
+    for (I = 0; I < sizeof (FileTypes) / sizeof (FileTypes [0]); ++I) {
+       if (strcmp (FileTypes [I].Ext, Ext) == 0) {
+           /* Found */
+           return FileTypes [I].Type;
+       }
+    }
+
+    /* Not found, return the default */
+    return DefaultFileType;
+}
+
+
+
+/*****************************************************************************/
+/*                       Command structure handling                         */
+/*****************************************************************************/
+
+
+
+static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
+/* Add a new argument to the command */
+{
+    /* Expand the argument vector if needed */
+    if (Cmd->ArgCount == Cmd->ArgMax) {
+       unsigned NewMax  = Cmd->ArgMax + 10;
+       char**   NewArgs = Xmalloc (NewMax * sizeof (char*));
+       memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
+       Xfree (Cmd->Args);
+       Cmd->Args   = NewArgs;
+       Cmd->ArgMax = NewMax;
+    }
+
+    /* Add a copy of the new argument, allow a NULL pointer */
+    if (Arg) {
+       Cmd->Args [Cmd->ArgCount++] = StrDup (Arg);
+    } else {
+       Cmd->Args [Cmd->ArgCount++] = 0;
+    }
+}
+
+
+
+static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
+/* Remove all arguments with an index greater than LastValid */
+{
+    while (Cmd->ArgCount > LastValid) {
+       Cmd->ArgCount--;
+       Xfree (Cmd->Args [Cmd->ArgCount]);
+       Cmd->Args [Cmd->ArgCount] = 0;
+    }
+}
+
+
+
+static void CmdAddFile (CmdDesc* Cmd, const char* File)
+/* Add a new file to the command */
+{
+    /* Expand the file vector if needed */
+    if (Cmd->FileCount == Cmd->FileMax) {
+       unsigned NewMax   = Cmd->FileMax + 10;
+       char**   NewFiles = Xmalloc (NewMax * sizeof (char*));
+       memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
+       Xfree (Cmd->Files);
+       Cmd->Files   = NewFiles;
+       Cmd->FileMax = NewMax;
+    }
+
+    /* Add a copy of the file name, allow a NULL pointer */
+    if (File) {
+       Cmd->Files [Cmd->FileCount++] = StrDup (File);
+    } else {
+       Cmd->Files [Cmd->FileCount++] = 0;
+    }
+}
+
+
+
+static void CmdInit (CmdDesc* Cmd, const char* Path)
+/* Initialize the command using the given path to the executable */
+{
+    /* Remember the command */
+    Cmd->Name = StrDup (Path);
+
+    /* Use the command name as first argument */
+    CmdAddArg (Cmd, Path);
+}
+
+
+
+static void CmdSetOutput (CmdDesc* Cmd, const char* File)
+/* Set the output file in a command desc */
+{
+    CmdAddArg (Cmd, "-o");
+    CmdAddArg (Cmd, File);
+}
+
+
+
+static void CmdSetTarget (CmdDesc* Cmd, int Target)
+/* Set the output file in a command desc */
+{
+    if (Target == TGT_UNKNOWN) {
+       /* Use C64 as default */
+       Target = TGT_C64;
+    }
+
+    if (Target != TGT_NONE) {
+       CmdAddArg (Cmd, "-t");
+       CmdAddArg (Cmd, TargetNames[Target]);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                             Target handling                              */
+/*****************************************************************************/
+
+
+
+static int MapTarget (const char* Name)
+/* Map a target name to a system code. Abort on errors */
+{
+    int I;
+
+    /* Check for a numeric target */
+    if (isdigit (*Name)) {
+       int Target = atoi (Name);
+       if (Target >= 0 && Target < TGT_COUNT) {
+           return Target;
+       }
+    }
+
+    /* Check for a target string */
+    for (I = 0; I < TGT_COUNT; ++I) {
+       if (strcmp (TargetNames [I], Name) == 0) {
+           return I;
+       }
+    }
+
+    /* Not found */
+    Error ("No such target system: `%s'", Name);
+    return -1; /* Not reached */
+}
+
+
+
+static void SetTargetFiles (void)
+/* Set the target system files */
+{
+    /* Determine the names of the default startup and library file */
+    if (Target >= TGT_FIRSTREAL) {
+
+       /* Get a pointer to the system name and its length */
+       const char* TargetName = TargetNames [Target];
+       unsigned    TargetNameLen = strlen (TargetName);
+
+       /* Set the startup file */
+       TargetCRT0 = Xmalloc (TargetNameLen + 2 + 1);
+       strcpy (TargetCRT0, TargetName);
+       strcat (TargetCRT0, ".o");
+
+       /* Set the library file */
+       TargetLib = Xmalloc (TargetNameLen + 4 + 1);
+       strcpy (TargetLib, TargetName);
+       strcat (TargetLib, ".lib");
+
+    }
+}
+
+
+
+static void SetTargetByName (const char* Name)
+/* Set the target system by name */
+{
+    Target = MapTarget (Name);
+    SetTargetFiles ();
+}
+
+
+
+/*****************************************************************************/
+/*                              Subprocesses                                */
+/*****************************************************************************/
+
+
+
+static void ExecProgram (CmdDesc* Cmd)
+/* Execute a subprocess with the given name/parameters. Exit on errors. */
+{
+    /* Call the program */
+    int Status = spawnvp (P_WAIT, Cmd->Name, Cmd->Args);
+
+    /* Check the result code */
+    if (Status < 0) {
+       /* Error executing the program */
+       Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
+    } else if (Status != 0) {
+       /* Called program had an error */
+       exit (Status);
+    }
+}
+
+
+
+static void Link (void)
+/* Link the resulting executable */
+{
+    unsigned I;
+
+    /* If we have a linker config file given, set the linker config file.
+     * Otherwise set the target system.
+     */
+    if (LinkerConfig) {
+               CmdAddArg (&LD65, "-C");
+       CmdAddArg (&LD65, LinkerConfig);
+    } else {
+       if (Target == TGT_UNKNOWN) {
+           /* Use c64 instead */
+           Target = TGT_C64;
+       }
+       SetTargetFiles ();
+       CmdSetTarget (&LD65, Target);
+    }
+
+    /* Since linking is always the final step, if we have an output file name
+     * given, set it here. If we don't have an explicit output name given,
+     * try to build one from the name of the first input file.
+     */
+    if (OutputName) {
+
+       CmdAddArg (&LD65, "-o");
+       CmdAddArg (&LD65, OutputName);
+
+    } else if (FirstInput && FindExt (FirstInput)) {  /* Only if ext present! */
+
+       char* Output = ForceExt (FirstInput, "");
+       CmdAddArg (&LD65, "-o");
+       CmdAddArg (&LD65, Output);
+       Xfree (Output);
+
+    }
+
+    /* If we have a startup file, add its name as a parameter */
+    if (TargetCRT0) {
+       CmdAddArg (&LD65, TargetCRT0);
+    }
+
+    /* Add all object files as parameters */
+    for (I = 0; I < LD65.FileCount; ++I) {
+       CmdAddArg (&LD65, LD65.Files [I]);
+    }
+
+    /* Add the system runtime library */
+    if (TargetLib) {
+       CmdAddArg (&LD65, TargetLib);
+    }
+
+    /* Terminate the argument list with a NULL pointer */
+    CmdAddArg (&LD65, 0);
+
+    /* Call the linker */
+    ExecProgram (&LD65);
+}
+
+
+
+static void Assemble (const char* File)
+/* Assemble the given file */
+{
+    /* Remember the current assembler argument count */
+    unsigned ArgCount = CA65.ArgCount;
+
+    /* If we won't link, this is the final step. In this case, set the
+     * output name.
+     */
+    if (DontLink && OutputName) {
+       CmdSetOutput (&CA65, OutputName);
+    } else {
+       /* The object file name will be the name of the source file
+        * with .s replaced by ".o". Add this file to the list of
+        * linker files.
+        */
+       char* ObjName = ForceExt (File, ".o");
+       CmdAddFile (&LD65, ObjName);
+       Xfree (ObjName);
+    }
+
+    /* Add the file as argument for the assembler */
+    CmdAddArg (&CA65, File);
+
+    /* Add a NULL pointer to terminate the argument list */
+    CmdAddArg (&CA65, 0);
+
+    /* Run the assembler */
+    ExecProgram (&CA65);
+
+    /* Remove the excess arguments */
+    CmdDelArgs (&CA65, ArgCount);
+}
+
+
+
+static void Compile (const char* File)
+/* Compile the given file */
+{
+    char* AsmName = 0;
+
+    /* Remember the current assembler argument count */
+    unsigned ArgCount = CC65.ArgCount;
+
+    /* Set the target system */
+    CmdSetTarget (&CC65, Target);
+
+    /* If we won't link, this is the final step. In this case, set the
+     * output name.
+     */
+    if (DontAssemble && OutputName) {
+       CmdSetOutput (&CC65, OutputName);
+    } else {
+       /* The assembler file name will be the name of the source file
+        * with .c replaced by ".s".
+        */
+       AsmName = ForceExt (File, ".s");
+    }
+
+    /* Add the file as argument for the compiler */
+    CmdAddArg (&CC65, File);
+
+    /* Add a NULL pointer to terminate the argument list */
+    CmdAddArg (&CC65, 0);
+
+    /* Run the compiler */
+    ExecProgram (&CC65);
+
+    /* Remove the excess arguments */
+    CmdDelArgs (&CC65, ArgCount);
+
+    /* If this is not the final step, assemble the generated file, then
+     * remove it
+     */
+    if (!DontAssemble) {
+       Assemble (AsmName);
+       if (remove (AsmName) < 0) {
+           Warning ("Cannot remove temporary file `%s': %s",
+                    AsmName, strerror (errno));
+       }
+       Xfree (AsmName);
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+    fprintf (stderr,
+            "Usage: %s [options] file\n"
+            "Options:\n"
+            "\t-A\t\tStrict ANSI mode\n"
+            "\t-C name\t\tUse linker config file\n"
+            "\t-Cl\t\tMake local variables static\n"
+            "\t-D sym[=defn]\tDefine a preprocessor symbol\n"
+            "\t-I path\t\tSet an include directory path\n"
+            "\t-Ln name\tCreate a VICE label file\n"
+            "\t-O\t\tOptimize code\n"
+            "\t-Oi\t\tOptimize code, inline functions\n"
+                    "\t-Or\t\tOptimize code, honour the register keyword\n"
+            "\t-Os\t\tOptimize code, inline known C funtions\n"
+            "\t-S\t\tCompile but don't assemble and link\n"
+            "\t-V\t\tPrint the version number\n"
+            "\t-W\t\tSuppress warnings\n"
+            "\t-c\t\tCompiler and assemble but don't link\n"
+            "\t-d\t\tDebug mode\n"
+            "\t-g\t\tAdd debug info\n"
+            "\t-h\t\tHelp (this text)\n"
+            "\t-m name\t\tCreate a map file\n"
+            "\t-o name\t\tName the output file\n"
+            "\t-t system\tSet the target system\n"
+            "\t-v\t\tVerbose mode\n"
+            "\t-vm\t\tVerbose map file\n",
+            ProgName);
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+    const char* Arg = argv [*ArgNum];
+    if (Arg [Len] != '\0') {
+       /* Argument appended */
+       return Arg + Len;
+    } else {
+       /* Separate argument */
+       Arg = argv [*ArgNum + 1];
+       if (Arg == 0) {
+           /* End of arguments */
+           fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+           exit (EXIT_FAILURE);
+       }
+       ++(*ArgNum);
+       return Arg;
+    }
+}
+
+
+
+static void ArgError (const char* Arg)
+/* Print an error about a wrong argument */
+{
+    Error ("Unknown option: `%s', use -h for help", Arg);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Utility main program */
+{
+    int I;
+
+    /* Initialize the command descriptors */
+    CmdInit (&CC65, "cc65");
+    CmdInit (&CA65, "ca65");
+    CmdInit (&LD65, "ld65");
+
+    /* Check the parameters */
+    I = 1;
+    while (I < argc) {
+
+       /* Get the argument */
+       const char* Arg = argv [I];
+
+       /* Check for an option */
+       if (Arg [0] == '-') {
+
+           switch (Arg [1]) {
+
+               case 'A':
+                   /* Strict ANSI mode (compiler) */
+                   CmdAddArg (&CC65, "-A");
+                   break;
+
+               case 'C':
+                   if (Arg[2] == 'l' && Arg[3] == '\0') {
+                       /* Make local variables static */
+                       CmdAddArg (&CC65, "-Cl");
+                   } else {
+                       /* Specify linker config file */
+                       LinkerConfig = GetArg (&I, argv, 2);
+                   }
+                   break;
+
+               case 'D':
+                   /* Define a preprocessor symbol (compiler) */
+                   CmdAddArg (&CC65, "-D");
+                   CmdAddArg (&CC65, GetArg (&I, argv, 2));
+                   break;
+
+               case 'I':
+                   /* Include directory (compiler) */
+                   CmdAddArg (&CC65, "-I");
+                   CmdAddArg (&CC65, GetArg (&I, argv, 2));
+                   break;
+
+               case 'L':
+                   if (Arg[2] == 'n') {
+                       /* VICE label file (linker) */
+                       CmdAddArg (&LD65, "-Ln");
+                       CmdAddArg (&LD65, GetArg (&I, argv, 3));
+                   } else {
+                       ArgError (Arg);
+                   }
+                   break;
+
+               case 'O':
+                   /* Optimize code (compiler, also covers -Oi and others) */
+                   CmdAddArg (&CC65, Arg);
+                   break;
+
+               case 'S':
+                   /* Dont assemble and link the created files */
+                   DontLink = DontAssemble = 1;
+                   break;
+
+               case 'T':
+                   /* Include source as comment (compiler) */
+                   CmdAddArg (&CC65, "-T");
+                   break;
+
+               case 'V':
+                   /* Print version number */
+                   fprintf (stderr,
+                            "cl65 V%u.%u.%u - (C) Copyright 1998-99 Ullrich von Bassewitz\n",
+                            VER_MAJOR, VER_MINOR, VER_PATCH);
+                   break;
+
+               case 'W':
+                   /* Suppress warnings - compiler and assembler */
+                   CmdAddArg (&CC65, "-W");
+                   CmdAddArg (&CA65, "-W");
+                   CmdAddArg (&CA65, "0");
+                   break;
+
+               case 'c':
+                   /* Don't link the resulting files */
+                   DontLink = 1;
+                   break;
+
+               case 'd':
+                   /* Debug mode (compiler) */
+                   CmdAddArg (&CC65, "-d");
+                   break;
+
+               case 'g':
+                   /* Debugging - add to compiler and assembler */
+                   CmdAddArg (&CC65, "-g");
+                   CmdAddArg (&CA65, "-g");
+                   break;
+
+               case 'h':
+               case '?':
+                   /* Print help - cl65 */
+                   Usage ();
+                   exit (EXIT_SUCCESS);
+                   break;
+
+               case 'm':
+                   /* Create a map file (linker) */
+                   CmdAddArg (&LD65, "-m");
+                   CmdAddArg (&LD65, GetArg (&I, argv, 2));
+                   break;
+
+               case 'o':
+                   /* Name the output file */
+                   OutputName = GetArg (&I, argv, 2);
+                   break;
+
+               case 't':
+                   /* Set target system - compiler and linker */
+                   SetTargetByName (GetArg (&I, argv, 2));
+                   break;
+
+               case 'v':
+                   if (Arg [2] == 'm') {
+                       /* Verbose map file (linker) */
+                       CmdAddArg (&LD65, "-vm");
+                   } else {
+                       /* Verbose mode (compiler, assembler, linker) */
+                       CmdAddArg (&CC65, "-v");
+                       CmdAddArg (&CA65, "-v");
+                       CmdAddArg (&LD65, "-v");
+                   }
+                   break;
+
+               default:
+                   ArgError (Arg);
+           }
+       } else {
+
+           /* Remember the first file name */
+           if (FirstInput == 0) {
+               FirstInput = Arg;
+           }
+
+           /* Determine the file type by the extension */
+           switch (GetFileType (Arg)) {
+
+               case FILETYPE_C:
+                   /* Compile the file */
+                   Compile (Arg);
+                   break;
+
+               case FILETYPE_ASM:
+                   /* Assemble the file */
+                   if (!DontAssemble) {
+                       Assemble (Arg);
+                   }
+                   break;
+
+               case FILETYPE_OBJ:
+               case FILETYPE_LIB:
+                   /* Add to the linker files */
+                   CmdAddFile (&LD65, Arg);
+                   break;
+
+               default:
+                   Error ("Don't know what to do with `%s'", Arg);
+
+           }
+
+       }
+
+       /* Next argument */
+       ++I;
+    }
+
+    /* Check if we had any input files */
+    if (FirstInput == 0) {
+       Warning ("No input files");
+    }
+
+    /* Link the given files if requested and if we have any */
+    if (DontLink == 0 && LD65.FileCount > 0) {
+       Link ();
+    }
+
+    /* Return an apropriate exit code */
+    return EXIT_SUCCESS;
+}
+
+
+
diff --git a/src/cl65/make/gcc.mak b/src/cl65/make/gcc.mak
new file mode 100644 (file)
index 0000000..445bdcf
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Makefile for the cl65 compile&link utility
+#
+
+CC=gcc
+CFLAGS = -O2 -g -Wall
+LDFLAGS=
+
+OBJS = error.o         \
+       global.o        \
+       main.o          \
+       mem.o           \
+       spawn.o
+
+EXECS = cl65
+
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+
+cl65:  $(OBJS)
+       $(CC) $(LDFLAGS) -o cl65 $(CFLAGS) $(OBJS)
+
+clean:
+       rm -f *~ core
+
+zap:   clean
+       rm -f *.o $(EXECS) .depend
+
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
+
+
diff --git a/src/cl65/make/watcom.mak b/src/cl65/make/watcom.mak
new file mode 100644 (file)
index 0000000..ca5e576
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# CL65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All OBJ files
+
+OBJS = error.obj       \
+       global.obj      \
+       main.obj        \
+       mem.obj
+
+.PRECIOUS $(OBJS:.obj=.c)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:           cl65
+
+cl65:          cl65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+cl65.exe:      $(OBJS)
+       $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE error.obj
+FILE global.obj
+FILE main.obj
+FILE mem.obj
+|
+
diff --git a/src/cl65/mem.c b/src/cl65/mem.c
new file mode 100644 (file)
index 0000000..879d3e7
--- /dev/null
@@ -0,0 +1,85 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.c                                   */
+/*                                                                           */
+/*       Memory allocation for the cl65 compile and link utility            */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+    void* p;
+
+    p = malloc (size);
+    if (p == 0 && size != 0) {
+       Error ("Out of memory");
+    }
+
+    /* Return a pointer to the block */
+    return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+    free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+    unsigned len;
+
+    len = strlen (s) + 1;
+    return memcpy (Xmalloc (len), s, len);
+}
+
+
+
+                               
diff --git a/src/cl65/mem.h b/src/cl65/mem.h
new file mode 100644 (file)
index 0000000..f66a56a
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.h                                   */
+/*                                                                           */
+/*       Memory allocation for the cl65 compile and link utility            */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
diff --git a/src/cl65/spawn.c b/src/cl65/spawn.c
new file mode 100644 (file)
index 0000000..8a43087
--- /dev/null
@@ -0,0 +1,95 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               spawn.c                                    */
+/*                                                                           */
+/*                   Execute other external programs                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int spawnvp (int Mode, const char* File, char* const argv [])
+/* Execute the given program searching and wait til it terminates. The Mode
+ * argument is ignored (compatibility only). The result of the function is
+ * the return code of the program. The function will terminate the program
+ * on errors.
+ */
+{
+    int Status = 0;
+
+    /* Fork */
+    int pid = fork ();
+    if (pid < 0) {
+
+       /* Error forking */
+       Error ("Cannot fork: %s", strerror (errno));
+
+    } else if (pid == 0) {
+
+               /* The son - exec the program */
+       if (execvp (File, argv) < 0) {
+           Error ("Cannot exec `%s': %s", File, strerror (errno));
+       }
+
+    } else {
+
+       /* The father: Wait for the subprocess to terminate */
+       if (waitpid (pid, &Status, 0) < 0) {
+           Error ("Failure waiting for subprocess: %s", strerror (errno));
+       }
+
+       /* Examine the child status */
+       if (!WIFEXITED (Status)) {
+           Error ("Subprocess `%s' aborted by signal %d", File, WTERMSIG (Status));
+       }
+    }
+
+    /* Only the father goes here, we place a return here regardless of that
+     * to avoid compiler warnings.
+     */
+    return WEXITSTATUS (Status);
+}
+
+
+
diff --git a/src/cl65/spawn.h b/src/cl65/spawn.h
new file mode 100644 (file)
index 0000000..86f5065
--- /dev/null
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               spawn.h                                    */
+/*                                                                           */
+/*                   Execute other external programs                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SPAWN_H
+#define SPAWN_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Mode argument for spawn. This value is ignored by the function and only
+ * provided for DOS/Windows compatibility.
+ */
+#ifndef P_WAIT
+#define P_WAIT 0
+#endif
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+int spawnvp (int Mode, const char* File, char* const argv []);
+/* Execute the given program searching and wait til it terminates. The Mode
+ * argument is ignored (compatibility only). The result of the function is
+ * the return code of the program. The function will terminate the program
+ * on errors.
+ */
+
+
+
+/* End of spawn.h */
+#endif
+
+
+
diff --git a/src/common/.cvsignore b/src/common/.cvsignore
new file mode 100644 (file)
index 0000000..ec0600e
--- /dev/null
@@ -0,0 +1,3 @@
+.depend
+common.o
+common.lib
diff --git a/src/common/bitops.c b/src/common/bitops.c
new file mode 100644 (file)
index 0000000..071b710
--- /dev/null
@@ -0,0 +1,128 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                        bitops.c                                  */
+/*                                                                          */
+/*                          Single bit operations                           */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include "bitops.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned BitFind (unsigned long Val)
+/* Find the first bit that is set in Val. Val must *not* be zero */
+{
+    unsigned long Mask;
+    unsigned Bit;
+
+    /* Search for the bits */
+    Mask = 1;
+    Bit  = 0;
+    while (1) {
+       if (Val & Mask) {
+           return Bit;
+       }
+       Mask <<= 1;
+       ++Bit;
+    }
+}
+
+
+
+void BitSet (void* Data, unsigned Bit)
+/* Set a bit in a char array */
+{
+    /* Make a char pointer */
+    unsigned char* D = Data;
+
+    /* Set the bit */
+    D [Bit / 8] |= 0x01 << (Bit % 8);
+}
+
+
+
+void BitReset (void* Data, unsigned Bit)
+/* Reset a bit in a char array */
+{
+    /* Make a char pointer */
+    unsigned char* D = Data;
+
+    /* Set the bit */
+    D [Bit / 8] &= ~(0x01 << (Bit % 8));
+}
+
+
+
+int BitIsSet (void* Data, unsigned Bit)
+/* Check if a bit is set in a char array */
+{
+    /* Make a char pointer */
+    unsigned char* D = Data;
+
+    /* Check the bit state */
+    return (D [Bit / 8] & (0x01 << (Bit % 8))) != 0;
+}
+
+
+
+int BitIsReset (void* Data, unsigned Bit)
+/* Check if a bit is reset in a char array */
+{
+    /* Make a char pointer */
+    unsigned char* D = Data;
+
+    /* Check the bit state */
+    return (D [Bit / 8] & (0x01 << (Bit % 8))) == 0;
+}
+
+
+
+void BitMerge (void* Target, const void* Source, unsigned Size)
+/* Merge the bits of two char arrays (that is, do an or for the full array) */
+{
+    /* Make char arrays */
+    unsigned char*      T = Target;
+    const unsigned char* S = Source;
+
+    /* Merge the arrays */
+    while (Size--) {
+       *T++ |= *S++;
+    }
+}
+
+
+
diff --git a/src/common/bitops.h b/src/common/bitops.h
new file mode 100644 (file)
index 0000000..8786fd0
--- /dev/null
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                bitops.h                                  */
+/*                                                                           */
+/*                          Single bit operations                           */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef BITOPS_H
+#define BITOPS_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned BitFind (unsigned long Val);
+/* Find the first bit that is set in Val. Val must *not* be zero */
+
+void BitSet (void* Data, unsigned Bit);
+/* Set a bit in a char array */
+
+void BitReset (void* Data, unsigned Bit);
+/* Reset a bit in a char array */
+
+int BitIsSet (void* Data, unsigned Bit);
+/* Check if a bit is set in a char array */
+
+int BitIsReset (void* Data, unsigned Bit);
+/* Check if a bit is reset in a char array */
+
+void BitMerge (void* Target, const void* Source, unsigned Size);
+/* Merge the bits of two char arrays (that is, do an or for the full array) */
+
+
+
+/* End of bitops.h */
+
+#endif
+
+
+
diff --git a/src/common/exprdefs.h b/src/common/exprdefs.h
new file mode 100644 (file)
index 0000000..8eca9ea
--- /dev/null
@@ -0,0 +1,124 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                       exprdefs.h                                 */
+/*                                                                           */
+/*                       Expression tree definitions                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXPRDEFS_H
+#define EXPRDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Expression type masks */
+#define EXPR_TYPEMASK          0xC0
+#define EXPR_BINARYNODE                0x00
+#define EXPR_UNARYNODE         0x40
+#define EXPR_LEAFNODE                  0x80
+
+/* Type of expression nodes */
+#define EXPR_NULL              0x00    /* Internal error or NULL node */
+
+/* Leaf node codes */
+#define EXPR_LITERAL                   (EXPR_LEAFNODE | 0x01)
+#define EXPR_SYMBOL                    (EXPR_LEAFNODE | 0x02)
+#define EXPR_SEGMENT                   (EXPR_LEAFNODE | 0x03)
+#define EXPR_MEMAREA           (EXPR_LEAFNODE | 0x04)  /* Linker only */
+#define EXPR_ULABEL            (EXPR_LEAFNODE | 0x05)  /* Assembler only */
+
+/* Binary operations, left and right hand sides are valid */
+#define EXPR_PLUS                      (EXPR_BINARYNODE | 0x01)
+#define EXPR_MINUS                     (EXPR_BINARYNODE | 0x02)
+#define EXPR_MUL                       (EXPR_BINARYNODE | 0x03)
+#define EXPR_DIV                       (EXPR_BINARYNODE | 0x04)
+#define EXPR_MOD                       (EXPR_BINARYNODE | 0x05)
+#define EXPR_OR                        (EXPR_BINARYNODE | 0x06)
+#define EXPR_XOR                       (EXPR_BINARYNODE | 0x07)
+#define EXPR_AND                       (EXPR_BINARYNODE | 0x08)
+#define EXPR_SHL                       (EXPR_BINARYNODE | 0x09)
+#define EXPR_SHR                       (EXPR_BINARYNODE | 0x0A)
+#define EXPR_EQ                        (EXPR_BINARYNODE | 0x0B)
+#define EXPR_NE                        (EXPR_BINARYNODE | 0x0C)
+#define EXPR_LT                        (EXPR_BINARYNODE | 0x0D)
+#define EXPR_GT                        (EXPR_BINARYNODE | 0x0E)
+#define EXPR_LE                        (EXPR_BINARYNODE | 0x0F)
+#define EXPR_GE                        (EXPR_BINARYNODE | 0x10)
+#define EXPR_BAND              (EXPR_BINARYNODE | 0x11)
+#define EXPR_BOR               (EXPR_BINARYNODE | 0x12)
+#define EXPR_BXOR              (EXPR_BINARYNODE | 0x13)
+
+/* Unary operations, right hand side is empty */
+#define EXPR_UNARY_MINUS               (EXPR_UNARYNODE | 0x01)
+#define EXPR_NOT                       (EXPR_UNARYNODE | 0x02)
+#define EXPR_LOBYTE                    (EXPR_UNARYNODE | 0x03)
+#define EXPR_HIBYTE                    (EXPR_UNARYNODE | 0x04)
+#define EXPR_SWAP                      (EXPR_UNARYNODE | 0x05)
+#define EXPR_BNOT              (EXPR_UNARYNODE | 0x06)
+
+
+
+/* The expression node itself */
+typedef struct ExprNode_ ExprNode;
+struct ExprNode_ {
+    unsigned char          Op;         /* Operand/Type */
+    ExprNode*              Left;       /* Left leaf */
+    ExprNode*              Right;      /* Right leaf */
+    struct ObjData_*       Obj;        /* Object file reference (linker) */
+    union {
+               long                Val;        /* If this is a value */
+               struct SymEntry_*   Sym;        /* If this is a symbol */
+       unsigned            SegNum;     /* If this is a segment */
+       unsigned            ImpNum;     /* If this is an import */
+       struct Memory_*     MemArea;    /* If this is a memory area */
+    } V;
+};
+
+
+
+/* Macros to determine the expression type */
+#define EXPR_IS_LEAF(Op)               (((Op) & EXPR_TYPEMASK) == EXPR_LEAFNODE)
+#define EXPR_IS_UNARY(Op)      (((Op) & EXPR_TYPEMASK) == EXPR_UNARYNODE)
+#define EXPR_IS_BINARY(OP)     (((Op) & EXPR_TYPEMASK) == EXPR_BINARYNODE)
+
+
+
+/* End of exprdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/filepos.h b/src/common/filepos.h
new file mode 100644 (file)
index 0000000..8378fd4
--- /dev/null
@@ -0,0 +1,65 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                filepos.h                                 */
+/*                                                                           */
+/*                      File position data structure                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FILEPOS_H
+#define FILEPOS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Size of position in file */
+#define POS_SIZE       5
+
+/* Type of a file position */
+typedef struct FilePos_ FilePos;
+struct FilePos_ {
+    unsigned long   Line;              /* Line */
+    unsigned char   Col;               /* Column */
+    unsigned char   Name;              /* File */
+};
+
+
+
+/* End of filepos.h */
+
+#endif
+
+
+
diff --git a/src/common/hashstr.c b/src/common/hashstr.c
new file mode 100644 (file)
index 0000000..0d2eb05
--- /dev/null
@@ -0,0 +1,56 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                hashstr.c                                 */
+/*                                                                           */
+/*                        Hash function for strings                         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S)
+/* Return a hash value for the given string */
+{
+    unsigned L, H;
+
+    /* Do the hash */
+    H = L = 0;
+    while (*S) {
+       H = ((H << 3) ^ ((unsigned char) *S++)) + L++;
+    }
+    return H;
+}
+
+
+
diff --git a/src/common/hashstr.h b/src/common/hashstr.h
new file mode 100644 (file)
index 0000000..af7f279
--- /dev/null
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                hashstr.h                                 */
+/*                                                                           */
+/*                        Hash function for strings                         */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef HASHSTR_H
+#define HASHSTR_H
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S);
+/* Return a hash value for the given string */
+
+
+
+/* End of hashstr.h */
+
+#endif
+
+
+
diff --git a/src/common/libdefs.h b/src/common/libdefs.h
new file mode 100644 (file)
index 0000000..1cda241
--- /dev/null
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                libdefs.h                                 */
+/*                                                                           */
+/*                        Library file definitions                          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LIBDEFS_H
+#define LIBDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Defines for magic and version */
+#define LIB_MAGIC      0x7A55616E
+#define LIB_VERSION    0x0004
+
+/* Size of an library file header */
+#define        LIB_HDR_SIZE    12
+
+
+
+/* Header structure for the library */
+typedef struct LibHeader_ LibHeader;
+struct LibHeader_ {
+    unsigned long      Magic;          /* 32: Magic number */
+    unsigned           Version;        /* 16: Version number */
+    unsigned           Flags;          /* 16: flags */
+    unsigned long              IndexOffs;      /* 32: Offset to directory */
+};
+
+
+
+/* End of libdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/make/gcc.mak b/src/common/make/gcc.mak
new file mode 100644 (file)
index 0000000..4fd29a1
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# gcc Makefile for the binutils common stuff
+#
+
+CFLAGS         = -g -O2 -Wall
+CC     = gcc
+LDFLAGS        =
+LIB    = common.a
+
+
+
+OBJS = bitops.o        \
+       hashstr.o
+
+
+# ------------------------------------------------------------------------------
+# Dummy targets
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all:   lib
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+.PHONY:        lib
+lib:   $(LIB)
+
+$(LIB):        $(OBJS)
+       $(AR) rs $(LIB) $?
+
+clean:
+       rm -f *~ core *.map
+
+zap:   clean
+       rm -f *.o $(LIB) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
+
diff --git a/src/common/make/watcom.mak b/src/common/make/watcom.mak
new file mode 100644 (file)
index 0000000..3c3cd82
--- /dev/null
@@ -0,0 +1,92 @@
+#
+# CC65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+LIB    = common.lib
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = bitops.obj      \
+       hashstr.obj     \
+       wildargv.obj
+
+
+.PRECIOUS $(OBJS:.obj=.cc) $(LIB)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:   lib
+
+lib:   $(LIB)
+
+$(LIB): $(OBJS)
+       @echo Creating library...
+       &@$(AR) -q -b -P=32 $(LIB) +-$?
+       @echo Done!
+
+clean:
+       @if exist *.obj del *.obj
+       @if exist $(LIB) del $(LIB)
+
+
+
diff --git a/src/common/objdefs.h b/src/common/objdefs.h
new file mode 100644 (file)
index 0000000..5a17ea8
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objdefs.h                                 */
+/*                                                                           */
+/*                         Object file definitions                          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDEFS_H
+#define OBJDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Defines for magic and version */
+#define OBJ_MAGIC      0x616E7A55
+#define OBJ_VERSION    0x0005
+
+/* Size of an object file header */
+#define        OBJ_HDR_SIZE    56
+
+/* Flag bits */
+#define OBJ_FLAGS_DBGINFO      0x0001  /* File has debug info */
+
+
+
+/* Header structure */
+typedef struct ObjHeader_ ObjHeader;
+struct ObjHeader_ {
+    unsigned long      Magic;          /* 32: Magic number */
+    unsigned           Version;        /* 16: Version number */
+    unsigned           Flags;          /* 16: flags */
+    unsigned long              OptionOffs;     /* 32: Offset to option table */
+    unsigned long       OptionSize;    /* 32: Size of options */
+    unsigned long      FileOffs;       /* 32: Offset to file table */
+    unsigned long      FileSize;       /* 32: Size of files */
+    unsigned long      SegOffs;        /* 32: Offset to segment table */
+    unsigned long      SegSize;        /* 32: Size of segment table */
+    unsigned long      ImportOffs;     /* 32: Offset to import list */
+    unsigned long      ImportSize;     /* 32: Size of import list */
+    unsigned long              ExportOffs;     /* 32: Offset to export list */
+    unsigned long      ExportSize;     /* 32: Size of export list */
+    unsigned long       DbgSymOffs;            /* 32: Offset to list of debug symbols */
+    unsigned long      DbgSymSize;     /* 32: Size of debug symbols */
+};
+
+
+
+/* End of objdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/optdefs.h b/src/common/optdefs.h
new file mode 100644 (file)
index 0000000..b256147
--- /dev/null
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                        optdefs.h                                 */
+/*                                                                           */
+/*                   Definitions for object file options                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OPTDEFS_H
+#define OPTDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Type of options */
+#define OPT_ARGMASK    0xC0            /* Mask for argument */
+#define OPT_ARGSTR     0x00            /* String argument */
+#define OPT_ARGNUM     0x40            /* Numerical argument */
+
+#define OPT_COMMENT    (OPT_ARGSTR+0)  /* Generic comment */
+#define OPT_AUTHOR     (OPT_ARGSTR+1)  /* Author specification */
+#define OPT_TRANSLATOR (OPT_ARGSTR+2)  /* Translator specification */
+#define OPT_COMPILER   (OPT_ARGSTR+3)  /* Compiler specification */
+#define OPT_OS         (OPT_ARGSTR+4)  /* Operating system specification */
+
+#define        OPT_DATETIME    (OPT_ARGNUM+0)  /* Date/time of translation */
+
+
+
+/* Structure to encode options */
+typedef struct Option_ Option;
+struct Option_ {
+    Option*            Next;           /* For list of options */
+    unsigned char      Type;           /* Type of option */
+    union {
+       const char*     Str;            /* String attribute */
+       unsigned long   Val;            /* Value attribute */
+    } V;
+};
+
+
+
+/* End of optdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/segdefs.h b/src/common/segdefs.h
new file mode 100644 (file)
index 0000000..5da311b
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                segdefs.h                                 */
+/*                                                                           */
+/*             Segment definitions for the bin65 binary utils               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SEGDEFS_H
+#define SEGDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Available segment types */
+#define SEGTYPE_DEFAULT        0
+#define SEGTYPE_ABS    1
+#define SEGTYPE_ZP     2
+#define SEGTYPE_FAR    3
+
+/* Fragment types in the object file */
+#define FRAG_TYPEMASK  0x38            /* Mask the type of the fragment */
+#define FRAG_BYTEMASK   0x07           /* Mask for byte count */
+
+#define FRAG_LITERAL   0x00            /* Literal data */
+#define FRAG_LITERAL8          0x01            /* Literal data with 8 bit length */
+#define FRAG_LITERAL16 0x02            /* Literal data with 16 bit length */
+#define FRAG_LITERAL24 0x03            /* Literal data with 24 bit length */
+#define FRAG_LITERAL32  0x04           /* Literal data with 32 bit length */
+
+#define FRAG_EXPR      0x08            /* Expression */
+#define FRAG_EXPR8             0x09            /* 8 bit expression */
+#define FRAG_EXPR16    0x0A            /* 16 bit expression */
+#define FRAG_EXPR24    0x0B            /* 24 bit expression */
+#define FRAG_EXPR32    0x0C            /* 32 bit expression */
+
+#define FRAG_SEXPR     0x10            /* Signed expression */
+#define FRAG_SEXPR8            0x11            /* 8 bit signed expression */
+#define FRAG_SEXPR16           0x12            /* 16 bit signed expression */
+#define FRAG_SEXPR24   0x13            /* 24 bit signed expression */
+#define FRAG_SEXPR32   0x14            /* 32 bit signed expression */
+
+#define FRAG_FILL              0x20            /* Fill bytes */
+
+
+/* End of segdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/symdefs.h b/src/common/symdefs.h
new file mode 100644 (file)
index 0000000..ffd371d
--- /dev/null
@@ -0,0 +1,63 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                symdefs.h                                 */
+/*                                                                           */
+/*              Symbol definitions for the bin65 binary utils               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SYMDEFS_H
+#define SYMDEFS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Object file tags for imports and exports */
+#define IMP_ABS        0x00            /* Import as normal value */
+#define IMP_ZP                 0x01            /* Import as zero page symbol */
+
+#define EXP_ABS                0x00            /* Export as normal value */
+#define EXP_ZP                 0x01            /* Export as zero page value */
+#define EXP_CONST      0x00            /* Mask bit for const values */
+#define EXP_EXPR       0x02            /* Mask bit for expr values */
+
+
+
+/* End of symdefs.h */
+
+#endif
+
+
+
diff --git a/src/common/version.h b/src/common/version.h
new file mode 100644 (file)
index 0000000..991f5c0
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                version.h                                 */
+/*                                                                          */
+/*            Version information for the cc65 compiler package             */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+#define VER_MAJOR      2U
+#define VER_MINOR      4U
+#define VER_PATCH      4U
+
+
+
+/* End of version.h */
+
+#endif
+
+
+
diff --git a/src/geos/headergen.sh b/src/geos/headergen.sh
new file mode 100755 (executable)
index 0000000..6200f6d
--- /dev/null
@@ -0,0 +1,199 @@
+#!/bin/sh
+
+# GEOS .cvt header generator...
+# it's a really quick and dirty hack ... big and ugly...
+
+# by Maciej 'YTM/Alliance' Witkowiak
+# 9/10.3.2000
+
+case "$1" in
+
+    *.res)
+
+#include resource file
+
+    . $1
+
+#test is arguments are really given, if not - set defaults
+
+# binary file type
+if [ -z "$progtype" ]; then progtype="APPLICATION"; fi
+
+# filenames
+if [ -z "$dosname" ];  then dosname="testapp"  ; fi
+if [ -z "$dostype" ];  then dostype="USR"      ; fi
+
+# date
+if [ -z "$year" ];     then year=`date +%y`    ; fi
+if [ -z "$month" ];    then month=`date +%m`   ; fi
+if [ -z "$day" ];      then day=`date +%e`     ; fi
+if [ -z "$hour" ];     then hour=`date +%k`    ; fi
+if [ -z "$minute" ];   then minute=`date +%M`  ; fi
+
+# screenmode
+if [ -z "$screenmode" ]; then screenmode=0     ; fi
+
+# names
+if [ -z "$class" ];    then class="Programname"; fi
+if [ -z "$version" ];  then version="V1.0"     ; fi
+if [ -z "$author" ];   then author="cc65"; fi
+if [ -z "$note" ];     then note="Program compiled with cc65 and GEOSLib."; fi
+
+# start generator
+
+cat << __END__
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 28.02.2000
+
+; This is .cvt header for GEOS files, it is recognized by Convert v2.5 for GEOS
+; and Star Commander (when copying GEOS files to/from .d64 images)
+
+; currently only SEQUENTIAL structure is supported, no overlays
+
+; THIS IS GENERATED FILE, ANY CHANGES WILL BE LOST!!!
+
+                       .segment "HEADER"
+
+;
+;filetypes
+;      GEOS
+NOT_GEOS               =       0
+BASIC                  =       1
+ASSEMBLY               =       2
+DATA                   =       3
+SYSTEM                 =       4
+DESK_ACC               =       5
+APPLICATION            =       6
+APPL_DATA              =       7
+FONT                   =       8
+PRINTER                =       9
+INPUT_DEVICE           =       10
+DISK_DEVICE            =       11
+SYSTEM_BOOT            =       12
+TEMPORARY              =       13
+AUTO_EXEC              =       14
+INPUT_128              =       15
+NUMFILETYPES           =       16
+;      structure
+SEQUENTIAL             =       0
+VLIR                   =       1
+;      DOS
+DEL                    =       0
+SEQ                    =       1
+PRG                    =       2
+USR                    =       3
+REL                    =       4
+CBM                    =       5
+
+__END__
+
+echo -e ProgType\\t\\t=\\t$progtype
+echo -e \\n\\t\\t.byte $dostype '| $80'\\t\\t'; DOS filetype'
+echo -e \\t\\t.word 0\\t\\t'; T&S, will be fixed by converter'
+echo $dosname | awk '
+{ len=length($0); printf "\t\t.byte %c%s%c\n", 34, substr($0,0,16), 34;
+  if (len<16) { len=15-len; printf "\t\t.byte $a0"
+  while (len>0) { printf ", $a0"; len-=1 } }
+  print ""
+  }'
+echo -e \\t\\t.word 0\\t\\t'; header T&S'
+echo -e \\t\\t.byte SEQUENTIAL
+echo -e \\t\\t.byte ProgType
+echo -e \\t\\t.byte $year
+echo -e \\t\\t.byte $month
+echo -e \\t\\t.byte $day
+echo -e \\t\\t.byte $hour
+echo -e \\t\\t.byte $minute
+echo -e \\n\\t\\t.word 0
+cat << __END__
+
+               .byte "PRG formatted GEOS file V1.0"
+                                               ; converter stamp
+               .res \$c4                       ; some bytes are left
+           
+               .byte 3, 21, 63 | \$80  ; icon picture header, 63 bytes follow
+
+               ;** hey, uberhacker! edit icon here!!! ;-))    
+               .byte %11111111, %11111111, %11111111
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %10000000, %00000000, %00000001
+               .byte %11111111, %11111111, %11111111
+
+__END__
+
+echo -e \\n\\t\\t.byte $dostype '| $80'\\t\\t';DOS filetype again'
+
+cat << __END__
+               .byte ProgType          ;again GEOS type
+               .byte SEQUENTIAL        ;structure
+               .word \$0400            ;ProgStart
+               .word \$0400-1          ;ProgEnd (needs proper value for DESK_ACC)
+               .word \$0400            ;ProgExec
+__END__
+
+echo -e \\t\\t'; GEOS class (11 chars padded with spaces, terminated with space (12th))'
+echo $class | awk '
+{ len=length($0); printf "\t\t.byte %c%s%c\n", 34, substr($0,0,12), 34;
+  if (len<12) { len=11-len; printf "\t\t.byte $20"
+  while (len>0) { printf ", $20"; len-=1 } }
+  print ""
+  }'
+echo -e \\t\\t'; version info (4 characters)'
+echo -en \\t\\t.byte 
+echo $version | awk '{ printf " %c%s%c\n", 34, substr($0,1,4), 34}'
+echo -e \\t\\t.byte 0\\t\\t\\t';string terminator'
+echo -e \\t\\t.word 0
+echo -e \\n\\t\\t.byte $screenmode\\t\\t\\t';40/80 columns capability'
+echo -e \\n\\t\\t'; author, up to 62 characters'
+echo $author | awk '
+{ printf "\t\t.byte %c%s%c\n\t\t.byte 0\n\t\t.res (63-%i)\n", 34, substr($0,0,62), 34, length($0)+1; }'
+echo -e \\n\\t\\t';note (up to 95 chars)'
+echo $note | awk '
+{ printf "\t\t.byte %c%s%c\n\t\t.byte 0\n\t\t.res (96-%i)\n", 34, substr($0,0,95), 34, length($0)+1; }'
+echo -e \\n\\n';end of .cvt header, real code follows'
+
+    ;;
+    *)
+echo "This is GEOSLib .cvt header generator by Maciej Witkowiak"
+echo "Usage:"
+echo "  headergen resourcefile.res"
+echo
+echo "Contents of resource file are (case sensitive):"
+echo "dostype=[PRG,SEQ,USR]"
+echo "dosname=filename"
+echo "progtype=[APPLICATION,ASSEMBLY,DESK_ACC,PRINTER,INPUT_DEVICE,AUTO_EXEC,INPUT_128]"
+echo "         currently only APPLICATION is supported"
+echo "year,month,date,hour,minute=XX - if not given current will be used"
+echo "screenmode=[0,64,128,192] -"
+echo "           0 - GEOS128 only 40 columns"
+echo "          64 - GEOS128 both 40/80 columns"
+echo "         128 - does not run under GEOS128"
+echo "         192 - GEOS128 only 80 columns"  
+echo "class=Class      - GEOS class name"
+echo "author=Author    - author name"
+echo "note=Note        - note field"
+echo 
+echo "If any of those parameters is not given, default will be used"
+echo "Output should be redirected to a file e.g. cvthead.s"
+echo "compiled with ca65 and used in linking process as the first object file -"
+echo "even before crt0.o"
+    ;;
+esac
diff --git a/src/ld65/.cvsignore b/src/ld65/.cvsignore
new file mode 100644 (file)
index 0000000..93a6523
--- /dev/null
@@ -0,0 +1,5 @@
+.depend
+ld65
+*.map
+*.s
+     
diff --git a/src/ld65/bin.c b/src/ld65/bin.c
new file mode 100644 (file)
index 0000000..c902aaf
--- /dev/null
@@ -0,0 +1,258 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  bin.c                                   */
+/*                                                                           */
+/*                 Module to handle the raw binary format                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "segments.h"
+#include "exports.h"
+#include "config.h"
+#include "expr.h"
+#include "bin.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+struct BinDesc_ {
+    unsigned   Undef;          /* Count of undefined externals */
+    FILE*      F;              /* Output file */
+    const char* Filename;      /* Name of output file */
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+BinDesc* NewBinDesc (void)
+/* Create a new binary format descriptor */
+{
+    /* Allocate memory for a new BinDesc struct */
+    BinDesc* D = Xmalloc (sizeof (BinDesc));
+
+    /* Initialize the fields */
+    D->Undef   = 0;
+    D->F       = 0;
+    D->Filename = 0;
+
+    /* Return the created struct */
+    return D;
+}
+
+
+
+void FreeBinDesc (BinDesc* D)
+/* Free a binary format descriptor */
+{
+    Xfree (D);
+}
+
+
+
+static unsigned BinWriteExpr (ExprNode* E, int Signed, unsigned Size,
+                             unsigned long Offs, void* Data)
+/* Called from SegWrite for an expression. Evaluate the expression, check the
+ * range and write the expression value to the file.
+ */
+{
+    /* There's a predefined function to handle constant expressions */
+    return SegWriteConstExpr (((BinDesc*)Data)->F, E, Signed, Size);
+}
+
+
+
+static void BinWriteMem (BinDesc* D, Memory* M)
+/* Write the segments of one memory area to a file */
+{
+    /* Get the start address of this memory area */
+    unsigned long Addr = M->Start;
+
+    /* Get a pointer to the first segment node */
+    MemListNode* N = M->SegList;
+    while (N) {
+
+       int DoWrite;
+
+       /* Get the segment from the list node */
+       SegDesc* S = N->Seg;
+
+       /* Keep the user happy */
+       if (Verbose) {
+           printf ("    Writing `%s'\n", S->Name);
+       }
+
+       /* Writes do only occur in the load area and not for BSS segments */
+               DoWrite = (S->Flags & SF_BSS) == 0      &&      /* No BSS segment */
+                  S->Load == M                 &&      /* LOAD segment */
+                  S->Seg->Dumped == 0;                 /* Not already written */
+
+       /* Check if we would need an alignment */
+       if (S->Seg->Align > S->Align) {
+           /* Segment itself requires larger alignment than configured
+            * in the linker.
+            */
+           Warning ("Segment `%s' in module `%s' requires larger alignment",
+                    S->Name, S->Seg->AlignObj->Name);
+       }
+
+       /* Handle ALIGN and OFFSET/START */
+       if (S->Flags & SF_ALIGN) {
+           /* Align the address */
+           unsigned long Val, NewAddr;
+           Val = (0x01UL << S->Align) - 1;
+           NewAddr = (Addr + Val) & ~Val;
+           if (DoWrite) {
+               WriteMult (D->F, M->FillVal, NewAddr-Addr);
+           }
+           Addr = NewAddr;
+           /* Remember the fill value for the segment */
+                   S->Seg->FillVal = M->FillVal;
+       } else if (S->Flags & (SF_OFFSET | SF_START)) {
+           unsigned long NewAddr = S->Addr;
+           if (S->Flags & SF_OFFSET) {
+               /* It's an offset, not a fixed address, make an address */
+               NewAddr += M->Start;
+           }
+           if (DoWrite) {
+               WriteMult (D->F, M->FillVal, NewAddr-Addr);
+           }
+           Addr = NewAddr;
+       }
+
+       /* Now write the segment to disk if it is not a BSS type segment and
+        * if the memory area is the load area.
+        */
+               if (DoWrite) {
+           SegWrite (D->F, S->Seg, BinWriteExpr, D);
+       } else if (M->Flags & MF_FILL) {
+           WriteMult (D->F, M->FillVal, S->Seg->Size);
+       }
+       S->Seg->Dumped = 1;
+
+       /* Calculate the new address */
+       Addr += S->Seg->Size;
+
+       /* Next segment node */
+       N = N->Next;
+    }
+
+    /* If a fill was requested, fill the remaining space */
+    if (M->Flags & MF_FILL) {
+       while (M->FillLevel < M->Size) {
+           Write8 (D->F, M->FillVal);
+           ++M->FillLevel;
+       }
+    }
+}
+
+
+
+static int BinUnresolved (const char* Name, void* D)
+/* Called if an unresolved symbol is encountered */
+{
+    /* Unresolved symbols are an error in binary format. Bump the counter
+     * and return zero telling the caller that the symbol is indeed
+     * unresolved.
+     */
+    ((BinDesc*) D)->Undef++;
+    return 0;
+}
+
+
+
+void BinWriteTarget (BinDesc* D, struct File_* F)
+/* Write a binary output file */
+{
+    Memory* M;
+
+    /* Place the filename in the control structure */
+    D->Filename = F->Name;
+
+    /* Check for unresolved symbols. The function BinUnresolved is called
+     * if we get an unresolved symbol.
+     */
+    D->Undef = 0;              /* Reset the counter */
+    CheckExports (BinUnresolved, D);
+    if (D->Undef > 0) {
+       /* We had unresolved symbols, cannot create output file */
+               Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
+    }
+
+    /* Open the file */
+    D->F = fopen (F->Name, "wb");
+    if (D->F == 0) {
+       Error ("Cannot open `%s': %s", F->Name, strerror (errno));
+    }
+
+    /* Keep the user happy */
+    if (Verbose) {
+       printf ("Opened `%s'...\n", F->Name);
+    }
+
+    /* Dump all memory areas */
+    M = F->MemList;
+    while (M) {
+       if (Verbose) {
+           printf ("  Dumping `%s'\n", M->Name);
+       }
+       BinWriteMem (D, M);
+       M = M->FNext;
+    }
+
+    /* Close the file */
+    if (fclose (D->F) != 0) {
+       Error ("Cannot write to `%s': %s", F->Name, strerror (errno));
+    }
+
+    /* Reset the file and filename */
+    D->F        = 0;
+    D->Filename = 0;
+}
+
+
+
diff --git a/src/ld65/bin.h b/src/ld65/bin.h
new file mode 100644 (file)
index 0000000..5ed6467
--- /dev/null
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  bin.h                                   */
+/*                                                                           */
+/*                 Module to handle the raw binary format                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef BIN_H
+#define BIN_H
+
+
+
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure describing the format */
+typedef struct BinDesc_ BinDesc;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+BinDesc* NewBinDesc (void);
+/* Create a new binary format descriptor */
+
+void FreeBinDesc (BinDesc* D);
+/* Free a binary format descriptor */
+
+void BinWriteTarget (BinDesc* D, File* F);
+/* Write a binary output file */
+
+
+
+/* End of bin.h */
+
+#endif
+
+
+
diff --git a/src/ld65/binfmt.c b/src/ld65/binfmt.c
new file mode 100644 (file)
index 0000000..b7c9784
--- /dev/null
@@ -0,0 +1,89 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                binfmt.c                                  */
+/*                                                                           */
+/*              Binary format definitions for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "binfmt.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Default format (depends on target system) */
+unsigned char DefaultBinFmt    = BINFMT_BINARY;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int RelocatableBinFmt (unsigned Format)
+/* Return true if this is a relocatable format, return false otherwise */
+{
+    int Reloc = 0;
+
+    /* Resolve the default format */
+    if (Format == BINFMT_DEFAULT) {
+       Format = DefaultBinFmt;
+    }
+
+    /* Check the type */
+    switch (Format) {
+
+       case BINFMT_BINARY:
+           Reloc = 0;
+           break;
+
+       case BINFMT_O65:
+           Reloc = 1;
+           break;
+
+       default:
+           Internal ("Invalid format specifier: %u", Format);
+
+    }
+
+    /* Return the flag */
+    return Reloc;
+}
+
+
+
diff --git a/src/ld65/binfmt.h b/src/ld65/binfmt.h
new file mode 100644 (file)
index 0000000..f541417
--- /dev/null
@@ -0,0 +1,73 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                binfmt.h                                  */
+/*                                                                           */
+/*              Binary format definitions for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef BINFMT_H
+#define BINFMT_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Types of available output formats */
+#define BINFMT_DEFAULT                 0       /* Default (binary) */
+#define BINFMT_BINARY          1       /* Straight binary format */
+#define BINFMT_O65             2       /* Andre Fachats o65 format */
+
+/* Default format (depends on target system) */
+extern unsigned char DefaultBinFmt;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+int RelocatableBinFmt (unsigned Format);
+/* Return true if this is a relocatable format, return false otherwise */
+
+
+
+/* End of binfmt.h */
+
+#endif
+
+
+
diff --git a/src/ld65/config.c b/src/ld65/config.c
new file mode 100644 (file)
index 0000000..20e6306
--- /dev/null
@@ -0,0 +1,1202 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                config.c                                  */
+/*                                                                           */
+/*              Target configuration file for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/bitops.h"
+
+#include "error.h"
+#include "mem.h"
+#include "global.h"
+#include "bin.h"
+#include "o65.h"
+#include "binfmt.h"
+#include "exports.h"
+#include "scanner.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* File list */
+static File*           FileList;       /* Single linked list */
+static unsigned                FileCount;      /* Number of entries in the list */
+
+
+
+/* Memory list */
+static Memory*         MemoryList;     /* Single linked list */
+static Memory*         MemoryLast;     /* Last element in list */
+static unsigned                MemoryCount;    /* Number of entries in the list */
+
+/* Memory attributes */
+#define MA_START               0x0001
+#define MA_SIZE                0x0002
+#define MA_TYPE                0x0004
+#define MA_FILE                0x0008
+#define MA_DEFINE              0x0010
+#define MA_FILL                0x0020
+#define MA_FILLVAL             0x0040
+
+
+
+/* Segment list */
+SegDesc*               SegDescList;    /* Single linked list */
+unsigned               SegDescCount;   /* Number of entries in list */
+
+/* Segment attributes */
+#define SA_TYPE                0x0001
+#define SA_LOAD                0x0002
+#define SA_RUN         0x0004
+#define SA_ALIGN       0x0008
+#define SA_DEFINE      0x0010
+#define SA_OFFSET      0x0020
+#define SA_START       0x0040
+
+
+
+/* Descriptor holding information about the binary formats */
+static BinDesc*        BinFmtDesc      = 0;
+static O65Desc* O65FmtDesc     = 0;
+
+/* Attributes for the o65 format */
+static unsigned O65Attr        = 0;
+#define OA_OS          0x0001
+#define OA_TYPE                0x0002
+#define OA_VERSION     0x0004
+#define OA_OSVERSION   0x0008
+#define OA_TEXT                0x0010
+#define OA_DATA                0x0020
+#define OA_BSS         0x0040
+#define OA_ZP          0x0080
+
+
+
+/*****************************************************************************/
+/*                        Constructors/Destructors                          */
+/*****************************************************************************/
+
+
+
+static File* NewFile (const char* Name)
+/* Create a new file descriptor and insert it into the list */
+{
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Allocate memory */
+    File* F = Xmalloc (sizeof (File) + Len);
+
+    /* Initialize the fields */
+    F->Flags   = 0;
+    F->Format  = BINFMT_DEFAULT;
+    F->MemList = 0;
+    F->MemLast = 0;
+    memcpy (F->Name, Name, Len);
+    F->Name [Len] = '\0';
+
+    /* Insert the struct into the list */
+    F->Next  = FileList;
+    FileList = F;
+    ++FileCount;
+
+    /* ...and return it */
+    return F;
+}
+
+
+
+static Memory* NewMemory (const char* Name)
+/* Create a new memory section and insert it into the list */
+{
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Check for duplicate names */
+    Memory* M =        MemoryList;
+    while (M) {
+       if (strcmp (M->Name, Name) == 0) {
+                   CfgError ("Memory area `%s' defined twice", Name);
+           break;
+               }
+       M = M->Next;
+    }
+
+    /* Allocate memory */
+    M = Xmalloc (sizeof (Memory) + Len);
+
+    /* Initialize the fields */
+    M->Next     = 0;
+    M->FNext     = 0;
+    M->Attr      = 0;
+    M->Flags     = 0;
+    M->Start     = 0;
+    M->Size      = 0;
+    M->FillLevel = 0;
+    M->FillVal   = 0;
+    M->SegList   = 0;
+    M->SegLast   = 0;
+    M->F         = 0;
+    memcpy (M->Name, Name, Len);
+    M->Name [Len] = '\0';
+
+    /* Insert the struct into the list */
+    if (MemoryLast == 0) {
+       /* First element */
+       MemoryList = M;
+    } else {
+       MemoryLast->Next = M;
+    }
+    MemoryLast = M;
+    ++MemoryCount;
+
+    /* ...and return it */
+    return M;
+}
+
+
+
+static SegDesc* NewSegDesc (const char* Name)
+/* Create a segment descriptor */
+{
+    Segment* Seg;
+
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Check for duplicate names */
+    SegDesc* S = SegDescList;
+    while (S) {
+       if (strcmp (S->Name, Name) == 0) {
+                   CfgError ("Segment `%s' defined twice", Name);
+           break;
+               }
+       S = S->Next;
+    }
+
+    /* Verify that the given segment does really exist */
+    Seg = SegFind (Name);
+    if (Seg == 0) {
+               CfgWarning ("Segment `%s' does not exist", Name);
+    }
+
+    /* Allocate memory */
+    S = Xmalloc (sizeof (SegDesc) + Len);
+
+    /* Initialize the fields */
+    S->Next    = 0;
+    S->Seg     = Seg;
+    S->Attr    = 0;
+    S->Flags   = 0;
+    S->Align   = 0;
+    memcpy (S->Name, Name, Len);
+    S->Name [Len] = '\0';
+
+    /* ...and return it */
+    return S;
+}
+
+
+
+static void FreeSegDesc (SegDesc* S)
+/* Free a segment descriptor */
+{
+    Xfree (S);
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
+/* Check if the item is already defined. Print an error if so. If not, set
+ * the marker that we have a definition now.
+ */
+{
+    if (*Flags & Mask) {
+       CfgError ("%s is already defined", Name);
+    }
+    *Flags |= Mask;
+}
+
+
+
+static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
+/* Check that a mandatory attribute was given */
+{
+    if ((Attr & Mask) == 0) {
+       CfgError ("%s attribute is missing", Name);
+    }
+}
+
+
+
+static File* FindFile (const char* Name)
+/* Find a file with a given name. */
+{
+    File* F = FileList;
+    while (F) {
+       if (strcmp (F->Name, Name) == 0) {
+           return F;
+       }
+       F = F->Next;
+    }
+    return 0;
+}
+
+
+
+static File* GetFile (const char* Name)
+/* Get a file entry with the given name. Create a new one if needed. */
+{
+    File* F = FindFile (Name);
+    if (F == 0) {
+       /* Create a new one */
+       F = NewFile (Name);
+    }
+    return F;
+}
+
+
+
+static void FileInsert (File* F, Memory* M)
+/* Insert the memory area into the files list */
+{
+    M->F = F;
+    if (F->MemList == 0) {
+       /* First entry */
+       F->MemList = M;
+    } else {
+       F->MemLast->FNext = M;
+    }
+    F->MemLast = M;
+}
+
+
+
+static void ParseMemory (void)
+/* Parse a MEMORY section */
+{
+    static const IdentTok Attributes [] = {
+               {   "START",    CFGTOK_START    },
+       {   "SIZE",     CFGTOK_SIZE     },
+        {   "TYPE",     CFGTOK_TYPE     },
+        {   "FILE",     CFGTOK_FILE     },
+        {   "DEFINE",   CFGTOK_DEFINE   },
+       {   "FILL",     CFGTOK_FILL     },
+               {   "FILLVAL",  CFGTOK_FILLVAL  },
+    };
+    static const IdentTok Types [] = {
+               {   "RO",       CFGTOK_RO       },
+               {   "RW",       CFGTOK_RW       },
+    };
+
+    while (CfgTok == CFGTOK_IDENT) {
+
+       /* Create a new entry on the heap */
+               Memory* M = NewMemory (CfgSVal);
+
+       /* Skip the name and the following colon */
+       CfgNextTok ();
+       CfgConsumeColon ();
+
+               /* Read the attributes */
+       while (CfgTok == CFGTOK_IDENT) {
+
+           /* Map the identifier to a token */
+           unsigned AttrTok;
+           CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+           AttrTok = CfgTok;
+
+           /* An optional assignment follows */
+           CfgNextTok ();
+           CfgOptionalAssign ();
+
+           /* Check which attribute was given */
+           switch (AttrTok) {
+
+               case CFGTOK_START:
+                   FlagAttr (&M->Attr, MA_START, "START");
+                   CfgAssureInt ();
+                   M->Start = CfgIVal;
+                   break;
+
+               case CFGTOK_SIZE:
+                   FlagAttr (&M->Attr, MA_SIZE, "SIZE");
+                   CfgAssureInt ();
+                   M->Size = CfgIVal;
+                   break;
+
+               case CFGTOK_TYPE:
+                   FlagAttr (&M->Attr, MA_TYPE, "TYPE");
+                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+                   if (CfgTok == CFGTOK_RO) {
+                       M->Flags |= MF_RO;
+                   }
+                   break;
+
+               case CFGTOK_FILE:
+                   FlagAttr (&M->Attr, MA_FILE, "FILE");
+                   CfgAssureStr ();
+                           /* Get the file entry and insert the memory area */
+                   FileInsert (GetFile (CfgSVal), M);
+                   break;
+
+               case CFGTOK_DEFINE:
+                   FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
+                   /* Map the token to a boolean */
+                   CfgBoolToken ();
+                   if (CfgTok == CFGTOK_TRUE) {
+                       M->Flags |= MF_DEFINE;
+                   }
+                   break;
+
+               case CFGTOK_FILL:
+                   FlagAttr (&M->Attr, MA_FILL, "FILL");
+                   /* Map the token to a boolean */
+                   CfgBoolToken ();
+                   if (CfgTok == CFGTOK_TRUE) {
+                       M->Flags |= MF_FILL;
+                   }
+                   break;
+
+               case CFGTOK_FILLVAL:
+                   FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
+                   CfgAssureInt ();
+                   CfgRangeCheck (0, 0xFF);
+                   M->FillVal = (unsigned char) CfgIVal;
+                   break;
+
+               default:
+                   FAIL ("Unexpected attribute token");
+
+           }
+
+           /* Skip the attribute value and an optional comma */
+           CfgNextTok ();
+           CfgOptionalComma ();
+       }
+
+       /* Skip the semicolon */
+       CfgConsumeSemi ();
+
+       /* Check for mandatory parameters */
+               AttrCheck (M->Attr, MA_START, "START");
+       AttrCheck (M->Attr, MA_SIZE, "SIZE");
+
+       /* If we don't have a file name for output given, use the default
+        * file name.
+        */
+       if ((M->Attr & MA_FILE) == 0) {
+           FileInsert (GetFile (OutputName), M);
+       }
+    }
+}
+
+
+
+static void ParseFiles (void)
+/* Parse a FILES section */
+{
+    static const IdentTok Attributes [] = {
+               {   "FORMAT",   CFGTOK_FORMAT   },
+    };
+    static const IdentTok Formats [] = {
+               {   "O65",      CFGTOK_O65           },
+               {   "BIN",      CFGTOK_BIN      },
+               {   "BINARY",   CFGTOK_BIN      },
+    };
+
+
+    /* Parse all files */
+    while (CfgTok != CFGTOK_RCURLY) {
+
+       File* F;
+
+       /* We expect a string value here */
+       CfgAssureStr ();
+
+       /* Search for the file, it must exist */
+               F = FindFile (CfgSVal);
+       if (F == 0) {
+           CfgError ("No such file: `%s'", CfgSVal);
+       }
+
+       /* Skip the token and the following colon */
+       CfgNextTok ();
+       CfgConsumeColon ();
+
+       /* Read the attributes */
+       while (CfgTok == CFGTOK_IDENT) {
+
+           /* Map the identifier to a token */
+           unsigned AttrTok;
+           CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+           AttrTok = CfgTok;
+
+           /* An optional assignment follows */
+           CfgNextTok ();
+           CfgOptionalAssign ();
+
+           /* Check which attribute was given */
+           switch (AttrTok) {
+
+               case CFGTOK_FORMAT:
+                   if (F->Format != BINFMT_DEFAULT) {
+                       /* We've set the format already! */
+                       Error ("Cannot set a file format twice");
+                   }
+                   /* Read the format token */
+                   CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+                   switch (CfgTok) {
+
+                       case CFGTOK_BIN:
+                           F->Format = BINFMT_BINARY;
+                           break;
+
+                       case CFGTOK_O65:
+                           F->Format = BINFMT_O65;
+                           break;
+
+                       default:
+                           Error ("Unexpected format token");
+                   }
+                   break;
+
+               default:
+                   FAIL ("Unexpected attribute token");
+
+           }
+
+           /* Skip the attribute value and an optional comma */
+           CfgNextTok ();
+           CfgOptionalComma ();
+       }
+
+       /* Skip the semicolon */
+       CfgConsumeSemi ();
+
+    }
+}
+
+
+
+static Memory* CfgFindMemory (const char* Name)
+/* Find the memory are with the given name. Return NULL if not found */
+{
+    Memory* M = MemoryList;
+    while (M) {
+               if (strcmp (M->Name, Name) == 0) {
+                   return M;
+               }
+               M = M->Next;
+    }
+    return 0;
+}
+
+
+
+static Memory* CfgGetMemory (const char* Name)
+/* Find the memory are with the given name. Print an error on an invalid name */
+{
+    Memory* M = CfgFindMemory (Name);
+    if (M == 0) {
+       CfgError ("Invalid memory area `%s'", Name);
+    }
+    return M;
+}
+
+
+
+static void SegDescInsert (SegDesc* S)
+/* Insert a segment descriptor into the list of segment descriptors */
+{
+    /* Insert the struct into the list */
+    S->Next = SegDescList;
+    SegDescList = S;
+    ++SegDescCount;
+}
+
+
+
+static void MemoryInsert (Memory* M, SegDesc* S)
+/* Insert the segment descriptor into the memory area list */
+{
+    /* Create a new node for the entry */
+    MemListNode* N = Xmalloc (sizeof (MemListNode));
+    N->Seg  = S;
+    N->Next = 0;
+
+    if (M->SegLast == 0) {
+               /* First entry */
+               M->SegList = N;
+    } else {
+       M->SegLast->Next = N;
+    }
+    M->SegLast = N;
+}
+
+
+
+static void ParseSegments (void)
+/* Parse a SEGMENTS section */
+{
+    static const IdentTok Attributes [] = {
+               {   "LOAD",     CFGTOK_LOAD     },
+       {   "RUN",      CFGTOK_RUN      },
+        {   "TYPE",     CFGTOK_TYPE     },
+        {   "ALIGN",    CFGTOK_ALIGN    },
+        {   "DEFINE",   CFGTOK_DEFINE   },
+       {   "OFFSET",   CFGTOK_OFFSET   },
+       {   "START",    CFGTOK_START    },
+    };
+    static const IdentTok Types [] = {
+               {   "RO",       CFGTOK_RO       },
+               {   "RW",       CFGTOK_RW       },
+               {   "BSS",      CFGTOK_BSS      },
+       {   "ZP",       CFGTOK_ZP       },
+       {   "WP",       CFGTOK_WPROT    },
+       {   "WPROT",    CFGTOK_WPROT    },
+    };
+
+    unsigned Count;
+
+    while (CfgTok == CFGTOK_IDENT) {
+
+       SegDesc* S;
+
+       /* Create a new entry on the heap */
+               S = NewSegDesc (CfgSVal);
+
+       /* Skip the name and the following colon */
+       CfgNextTok ();
+       CfgConsumeColon ();
+
+               /* Read the attributes */
+       while (CfgTok == CFGTOK_IDENT) {
+
+           /* Map the identifier to a token */
+           unsigned AttrTok;
+           CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+           AttrTok = CfgTok;
+
+           /* An optional assignment follows */
+           CfgNextTok ();
+           CfgOptionalAssign ();
+
+           /* Check which attribute was given */
+           switch (AttrTok) {
+
+               case CFGTOK_LOAD:
+                   FlagAttr (&S->Attr, SA_LOAD, "LOAD");
+                   S->Load = CfgGetMemory (CfgSVal);
+                   break;
+
+               case CFGTOK_RUN:
+                   FlagAttr (&S->Attr, SA_RUN, "RUN");
+                   S->Run = CfgGetMemory (CfgSVal);
+                   break;
+
+               case CFGTOK_TYPE:
+                   FlagAttr (&S->Attr, SA_TYPE, "TYPE");
+                           CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+                   switch (CfgTok) {
+                               case CFGTOK_RO:    S->Flags |= SF_RO;               break;
+                       case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
+                       case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
+                       case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT);  break;
+                   }
+                   break;
+
+               case CFGTOK_ALIGN:
+                   CfgAssureInt ();
+                   FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
+                   CfgRangeCheck (1, 0x10000);
+                   S->Align = BitFind (CfgIVal);
+                   if ((0x01UL << S->Align) != CfgIVal) {
+                       CfgError ("Alignment must be a power of 2");
+                   }
+                   S->Flags |= SF_ALIGN;
+                   break;
+
+               case CFGTOK_DEFINE:
+                   FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
+                   /* Map the token to a boolean */
+                   CfgBoolToken ();
+                   if (CfgTok == CFGTOK_TRUE) {
+                       S->Flags |= SF_DEFINE;
+                   }
+                   break;
+
+               case CFGTOK_OFFSET:
+                   CfgAssureInt ();
+                   FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
+                   CfgRangeCheck (1, 0x1000000);
+                   S->Addr   = CfgIVal;
+                   S->Flags |= SF_OFFSET;
+                   break;
+
+               case CFGTOK_START:
+                   CfgAssureInt ();
+                   FlagAttr (&S->Attr, SA_START, "START");
+                   CfgRangeCheck (1, 0x1000000);
+                   S->Addr   = CfgIVal;
+                   S->Flags |= SF_START;
+                   break;
+
+               default:
+                           FAIL ("Unexpected attribute token");
+
+           }
+
+           /* Skip the attribute value and an optional comma */
+           CfgNextTok ();
+           CfgOptionalComma ();
+       }
+
+       /* Skip the semicolon */
+       CfgConsumeSemi ();
+
+       /* Check for mandatory parameters */
+       AttrCheck (S->Attr, SA_LOAD, "LOAD");
+
+       /* Set defaults for stuff not given */
+       if ((S->Attr & SA_RUN) == 0) {
+           S->Attr |= SA_RUN;
+           S->Run = S->Load;
+       } else {
+           /* Both attributes given */
+           S->Flags |= SF_LOAD_AND_RUN;
+       }
+       if ((S->Attr & SA_ALIGN) == 0) {
+           S->Attr |= SA_ALIGN;
+           S->Align = 0;
+       }
+
+       /* If the segment is marked as BSS style, check that there's no
+        * initialized data in the segment.
+        */
+       if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
+           Warning ("%s(%u): Segment with type `bss' contains initialized data",
+                    CfgGetName (), CfgErrorLine);
+       }
+
+       /* Don't allow read/write data to be put into a readonly area */
+       if ((S->Flags & SF_RO) == 0) {
+                   if (S->Run->Flags & MF_RO) {
+               CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
+                         S->Name, S->Run->Name);
+           }
+       }
+
+       /* Only one of ALIGN, START and OFFSET may be used */
+               Count = ((S->Flags & SF_ALIGN)  != 0) +
+               ((S->Flags & SF_OFFSET) != 0) +
+               ((S->Flags & SF_START)  != 0);
+       if (Count > 1) {
+                   CfgError ("Only one of ALIGN, START, OFFSET may be used");
+       }
+
+       /* If this segment does exist in any of the object files, insert the
+        * descriptor into the list of segment descriptors. Otherwise discard
+        * it silently, because the segment pointer in the descriptor is
+        * invalid.
+        */
+       if (S->Seg != 0) {
+           /* Insert the descriptor into the list of all descriptors */
+           SegDescInsert (S);
+           /* Insert the segment into the memory area list */
+           MemoryInsert (S->Run, S);
+           if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
+               /* We have a separate RUN area given */
+               MemoryInsert (S->Load, S);
+           }
+       } else {
+           /* Segment does not exist, discard the descriptor */
+           FreeSegDesc (S);
+       }
+    }
+}
+
+
+
+static void ParseO65 (void)
+/* Parse the o65 format section */
+{
+    static const IdentTok Attributes [] = {
+               {   "EXPORT",    CFGTOK_EXPORT          },
+       {   "IMPORT",    CFGTOK_IMPORT          },
+        {   "TYPE",      CFGTOK_TYPE           },
+               {   "OS",        CFGTOK_OS              },
+    };
+    static const IdentTok Types [] = {
+               {   "SMALL",     CFGTOK_SMALL           },
+               {   "LARGE",     CFGTOK_LARGE           },
+    };
+    static const IdentTok OperatingSystems [] = {
+               {   "LUNIX",     CFGTOK_LUNIX           },
+               {   "OSA65",     CFGTOK_OSA65           },
+    };
+
+    while (CfgTok == CFGTOK_IDENT) {
+
+       /* Map the identifier to a token */
+       unsigned AttrTok;
+               CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+       AttrTok = CfgTok;
+
+       /* An optional assignment follows */
+       CfgNextTok ();
+       CfgOptionalAssign ();
+
+       /* Check which attribute was given */
+       switch (AttrTok) {
+
+           case CFGTOK_EXPORT:
+               /* We expect an identifier */
+               CfgAssureIdent ();
+               /* Check if we have this symbol defined already. The entry
+                * routine will check this also, but we get a more verbose
+                * error message when checking it here.
+                */
+               if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
+                   CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
+               }
+               /* Insert the symbol into the table */
+               O65SetExport (O65FmtDesc, CfgSVal);
+               break;
+
+           case CFGTOK_IMPORT:
+               /* We expect an identifier */
+               CfgAssureIdent ();
+               /* Check if we have this symbol defined already. The entry
+                * routine will check this also, but we get a more verbose
+                * error message when checking it here.
+                */
+               if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+                   CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
+               }
+               /* Insert the symbol into the table */
+               O65SetImport (O65FmtDesc, CfgSVal);
+               break;
+
+           case CFGTOK_TYPE:
+               /* Cannot have this attribute twice */
+               FlagAttr (&O65Attr, OA_TYPE, "TYPE");
+               /* Get the type of the executable */
+               CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+               switch (CfgTok) {
+
+                   case CFGTOK_SMALL:
+                       /* Default, nothing to do */
+                       break;
+
+                   case CFGTOK_LARGE:
+                       O65SetLargeModel (O65FmtDesc);
+                       break;
+
+                   default:
+                       Error ("Unexpected type token");
+               }
+               break;
+
+           case CFGTOK_OS:
+               /* Cannot use this attribute twice */
+               FlagAttr (&O65Attr, OA_OS, "OS");
+               /* Get the operating system */
+               CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
+               switch (CfgTok) {
+
+                   case CFGTOK_LUNIX:
+                       O65SetOS (O65FmtDesc, O65OS_LUNIX);
+                       break;
+
+                   case CFGTOK_OSA65:
+                       O65SetOS (O65FmtDesc, O65OS_OSA65);
+                       break;
+
+                   default:
+                       Error ("Unexpected OS token");
+               }
+               break;
+
+           default:
+               FAIL ("Unexpected attribute token");
+
+       }
+
+       /* Skip the attribute value and an optional comma */
+       CfgNextTok ();
+       CfgOptionalComma ();
+    }
+}
+
+
+
+static void ParseFormats (void)
+/* Parse a target format section */
+{
+    static const IdentTok Formats [] = {
+               {   "O65",      CFGTOK_O65      },
+               {   "BIN",      CFGTOK_BIN      },
+               {   "BINARY",   CFGTOK_BIN      },
+    };
+
+    while (CfgTok == CFGTOK_IDENT) {
+
+       /* Map the identifier to a token */
+       unsigned FormatTok;
+               CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+       FormatTok = CfgTok;
+
+       /* Skip the name and the following colon */
+       CfgNextTok ();
+       CfgConsumeColon ();
+
+       /* Parse the format options */
+       switch (FormatTok) {
+
+           case CFGTOK_O65:
+               ParseO65 ();
+               break;
+
+           case CFGTOK_BIN:
+               /* No attribibutes available */
+               break;
+
+           default:
+               Error ("Unexpected format token");
+       }
+
+       /* Skip the semicolon */
+       CfgConsumeSemi ();
+    }
+}
+
+
+
+static void ParseConfig (void)
+/* Parse the config file */
+{
+    static const IdentTok BlockNames [] = {
+       {   "MEMORY",   CFGTOK_MEMORY    },
+       {   "FILES",    CFGTOK_FILES     },
+        {   "SEGMENTS", CFGTOK_SEGMENTS  },
+       {   "FORMATS",  CFGTOK_FORMATS   },
+    };
+    unsigned BlockTok;
+
+    do {
+
+       /* Read the block ident */
+               CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
+       BlockTok = CfgTok;
+       CfgNextTok ();
+
+       /* Expected a curly brace */
+       CfgConsume (CFGTOK_LCURLY, "`{' expected");
+
+       /* Read the block */
+       switch (BlockTok) {
+
+           case CFGTOK_MEMORY:
+               ParseMemory ();
+               break;
+
+           case CFGTOK_FILES:
+               ParseFiles ();
+               break;
+
+           case CFGTOK_SEGMENTS:
+               ParseSegments ();
+               break;
+
+           case CFGTOK_FORMATS:
+               ParseFormats ();
+               break;
+
+           default:
+               FAIL ("Unexpected block token");
+
+       }
+
+       /* Skip closing brace */
+       CfgConsume (CFGTOK_RCURLY, "`}' expected");
+
+    } while (CfgTok != CFGTOK_EOF);
+}
+
+
+
+void CfgRead (void)
+/* Read the configuration */
+{
+    /* Create the descriptors for the binary formats */
+    BinFmtDesc = NewBinDesc ();
+    O65FmtDesc = NewO65Desc ();
+
+    /* If we have a config name given, open the file, otherwise we will read
+     * from a buffer.
+     */
+    CfgOpenInput ();
+
+    /* Parse the file */
+    ParseConfig ();
+
+    /* Close the input file */
+    CfgCloseInput ();
+}
+
+
+
+static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
+/* Create the defines for a RUN segment */
+{
+    char Buf [256];
+
+    sprintf (Buf, "__%s_RUN__", S->Name);
+    CreateMemExport (Buf, M, Addr - M->Start);
+    sprintf (Buf, "__%s_SIZE__", S->Name);
+    CreateConstExport (Buf, S->Seg->Size);
+    S->Flags |= SF_RUN_DEF;
+}
+
+
+
+static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
+/* Create the defines for a LOAD segment */
+{
+    char Buf [256];
+
+    sprintf (Buf, "__%s_LOAD__", S->Name);
+    CreateMemExport (Buf, M, Addr - M->Start);
+    S->Flags |= SF_LOAD_DEF;
+}
+
+
+
+void CfgAssignSegments (void)
+/* Assign segments, define linker symbols where requested */
+{
+    /* Walk through each of the memory sections. Add up the sizes and check
+     * for an overflow of the section. Assign the start addresses of the
+     * segments while doing this.
+     */
+    Memory* M = MemoryList;
+    while (M) {
+
+       /* Get the start address of this memory area */
+       unsigned long Addr = M->Start;
+
+       /* Walk through the segments in this memory area */
+       MemListNode* N = M->SegList;
+       while (N) {
+
+           /* Get the segment from the node */
+           SegDesc* S = N->Seg;
+
+           /* Handle ALIGN and OFFSET/START */
+           if (S->Flags & SF_ALIGN) {
+               /* Align the address */
+               unsigned long Val = (0x01UL << S->Align) - 1;
+               Addr = (Addr + Val) & ~Val;
+           } else if (S->Flags & (SF_OFFSET | SF_START)) {
+               /* Give the segment a fixed starting address */
+               unsigned long NewAddr = S->Addr;
+               if (S->Flags & SF_OFFSET) {
+                   /* An offset was given, no address, make an address */
+                   NewAddr += M->Start;
+               }
+                       if (Addr > NewAddr) {
+                   /* Offset already too large */
+                   if (S->Flags & SF_OFFSET) {
+                       Error ("Offset too small in `%s', segment `%s'",
+                              M->Name, S->Name);
+                   } else {
+                       Error ("Start address too low in `%s', segment `%s'",
+                              M->Name, S->Name);
+                   }
+               }
+               Addr = NewAddr;
+           }
+
+                   /* If this is the run area, set the start address of this segment */
+           if (S->Run == M) {
+               S->Seg->PC = Addr;
+           }
+
+           /* Increment the fill level of the memory area and check for an
+            * overflow.
+            */
+           M->FillLevel = Addr + S->Seg->Size - M->Start;
+           if (M->FillLevel > M->Size) {
+               Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
+                      M->Name, S->Name, M->FillLevel - M->Size);
+           }
+
+           /* If requested, define symbols for the start and size of the
+            * segment.
+            */
+           if (S->Flags & SF_DEFINE) {
+               if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
+                   /* RUN and LOAD given and in one memory area.
+                    * Be careful: We will encounter this code twice, the
+                    * first time when walking the RUN list, second time when
+                    * walking the LOAD list. Be sure to define only the
+                    * relevant symbols on each walk.
+                    */
+                   if (S->Load == M) {
+                       if ((S->Flags & SF_LOAD_DEF) == 0) {
+                           CreateLoadDefines (M, S, Addr);
+                       } else {
+                           CHECK ((S->Flags & SF_RUN_DEF) == 0);
+                           CreateRunDefines (M, S, Addr);
+                       }
+                   }
+               } else {
+                   /* RUN and LOAD in different memory areas, or RUN not
+                    * given, so RUN defaults to LOAD. In the latter case, we
+                    * have only one copy of the segment in the area.
+                    */
+                   if (S->Run == M) {
+                       CreateRunDefines (M, S, Addr);
+                   }
+                   if (S->Load == M) {
+                       CreateLoadDefines (M, S, Addr);
+                   }
+               }
+           }
+
+           /* Calculate the new address */
+           Addr += S->Seg->Size;
+
+           /* Next segment */
+           N = N->Next;
+       }
+
+       /* If requested, define symbols for start and size of the memory area */
+       if (M->Flags & MF_DEFINE) {
+           char Buf [256];
+           sprintf (Buf, "__%s_START__", M->Name);
+           CreateMemExport (Buf, M, 0);
+           sprintf (Buf, "__%s_SIZE__", M->Name);
+           CreateConstExport (Buf, M->Size);
+           sprintf (Buf, "__%s_LAST__", M->Name);
+           CreateConstExport (Buf, M->FillLevel);
+       }
+
+       /* Next memory area */
+       M = M->Next;
+    }
+}
+
+
+
+void CfgWriteTarget (void)
+/* Write the target file(s) */
+{
+    Memory* M;
+
+    /* Walk through the files list */
+    File* F = FileList;
+    while (F) {
+       /* We don't need to look at files with no memory areas */
+       if (F->MemList) {
+
+           /* Is there an output file? */
+           if (strlen (F->Name) > 0) {
+
+               /* Assign a proper binary format */
+               if (F->Format == BINFMT_DEFAULT) {
+                   F->Format = DefaultBinFmt;
+               }
+
+               /* Call the apropriate routine for the binary format */
+               switch (F->Format) {
+
+                   case BINFMT_BINARY:
+                       BinWriteTarget (BinFmtDesc, F);
+                       break;
+
+                   case BINFMT_O65:
+                       O65WriteTarget (O65FmtDesc, F);
+                       break;
+
+                   default:
+                       Internal ("Invalid binary format: %u", F->Format);
+
+               }
+
+           } else {
+
+               /* No output file. Walk through the list and mark all segments
+                * assigned to the memory areas in this file as dumped.
+                */
+               M = F->MemList;
+               while (M) {
+                   /* Walk throught the segments */
+                   MemListNode* N = M->SegList;
+                   while (N) {
+                       /* Mark the segment as dumped */
+                               N->Seg->Seg->Dumped = 1;
+
+                       /* Next segment node */
+                       N = N->Next;
+                   }
+                   /* Next memory area */
+                   M = M->FNext;
+               }
+           }
+       }
+
+       /* Next file */
+       F = F->Next;
+    }
+}
+
+
+
diff --git a/src/ld65/config.h b/src/ld65/config.h
new file mode 100644 (file)
index 0000000..2f5c811
--- /dev/null
@@ -0,0 +1,147 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                config.h                                  */
+/*                                                                           */
+/*              Target configuration file for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+
+#include "segments.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* File list entry */
+typedef struct File_ File;
+struct File_ {
+    File*              Next;           /* Pointer to next entry in list */
+    unsigned           Flags;
+    unsigned           Format;         /* Output format */
+    struct Memory_*    MemList;        /* List of memory areas in this file */
+    struct Memory_*    MemLast;        /* Last memory area in this file */
+    char               Name [1];       /* Name of file */
+};
+
+/* Segment list node. Needed because there are two lists (RUN & LOAD) */
+typedef struct MemListNode_ MemListNode;
+struct MemListNode_ {
+    MemListNode*       Next;           /* Next entry */
+    struct SegDesc_*   Seg;            /* Segment */
+};
+
+/* Memory list entry */
+typedef struct Memory_ Memory;
+struct Memory_ {
+    Memory*            Next;           /* Pointer to next entry in list */
+    Memory*                    FNext;          /* Next in file list */
+    unsigned                   Attr;           /* Which values are valid? */
+    unsigned           Flags;          /* Set of bitmapped flags */
+    unsigned long      Start;          /* Start address */
+    unsigned long              Size;           /* Length of memory section */
+    unsigned long              FillLevel;      /* Actual fill level of segment */
+    unsigned char      FillVal;        /* Value used to fill rest of seg */
+    MemListNode*       SegList;        /* List of segments for this section */
+    MemListNode*       SegLast;        /* Last segment in this section */
+    File*              F;              /* File that contains the entry */
+    char               Name [1];       /* Name of the memory section */
+};
+
+/* Segment descriptor entry */
+typedef struct SegDesc_ SegDesc;
+struct SegDesc_ {
+    SegDesc*                   Next;           /* Pointer to next entry in list */
+    Segment*           Seg;            /* Pointer to segment structure */
+    unsigned           Attr;           /* Attributes for segment */
+    unsigned           Flags;          /* Set of bitmapped flags */
+    Memory*            Load;           /* Load memory section */
+    Memory*            Run;            /* Run memory section */
+    unsigned long              Addr;           /* Start address or offset into segment */
+    unsigned char      Align;          /* Alignment if given */
+    char               Name [1];       /* Copy of name */
+};
+
+/* Segment list */
+extern SegDesc*                SegDescList;    /* Single linked list */
+extern unsigned                SegDescCount;   /* Number of entries in list */
+
+/* Memory flags */
+#define MF_DEFINE              0x0001          /* Define start and size */
+#define MF_FILL                0x0002          /* Fill segment */
+#define MF_RO          0x0004          /* Read only memory area */
+
+/* Segment flags */
+#define SF_RO          0x0001          /* Read only segment */
+#define SF_BSS                 0x0002          /* Segment is BSS style segment */
+#define SF_ZP          0x0004          /* Zeropage segment (o65 only) */
+#define SF_WPROT       0x0008          /* Write protected segment */
+#define SF_DEFINE              0x0010          /* Define start and size */
+#define SF_ALIGN       0x0020          /* Align the segment */
+#define SF_OFFSET      0x0040          /* Segment has offset in memory */
+#define SF_START       0x0080          /* Segment has fixed start address */
+#define SF_LOAD_AND_RUN        0x1000          /* LOAD and RUN given */
+#define SF_RUN_DEF             0x2000          /* RUN symbols already defined */
+#define SF_LOAD_DEF    0x4000          /* LOAD symbols already defined */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void CfgRead (void);
+/* Read the configuration */
+
+void CfgAssignSegments (void);
+/* Assign segments, define linker symbols where requested */
+
+void CfgWriteTarget (void);
+/* Write the target file(s) */
+
+
+
+/* End of config.h */
+
+#endif
+
+
+
+
diff --git a/src/ld65/dbgsyms.c b/src/ld65/dbgsyms.c
new file mode 100644 (file)
index 0000000..77d7dd3
--- /dev/null
@@ -0,0 +1,210 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                dbgsyms.c                                 */
+/*                                                                           */
+/*                Debug symbol handing for the ld65 linker                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/symdefs.h"
+
+#include "global.h"
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "expr.h"
+#include "dbgsyms.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* We will collect all debug symbols in the following array and remove
+ * duplicates before outputing them.
+ */
+static DbgSym* DbgSymPool [256];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static DbgSym* NewDbgSym (unsigned char Type, const char* Name, ObjData* O)
+/* Create a new DbgSym and return it */
+{
+    /* Get the length of the symbol name */
+    unsigned Len = strlen (Name);
+
+    /* Allocate memory */
+    DbgSym* D = Xmalloc (sizeof (DbgSym) + Len);
+
+    /* Initialize the fields */
+    D->Next     = 0;
+    D->Flags   = 0;
+    D->Obj      = O;
+    D->Expr            = 0;
+    D->Type            = Type;
+    memcpy (D->Name, Name, Len);
+    D->Name [Len] = '\0';
+
+    /* Return the new entry */
+    return D;
+}
+
+
+
+static DbgSym* GetDbgSym (DbgSym* D, long Val)
+/* Check if we find the same debug symbol in the table. If we find it, return
+ * a pointer to the other occurrence, if we didn't find it, return NULL.
+ */
+{
+    /* Create the hash. We hash over the symbol value */
+    unsigned Hash = ((Val >> 24) & 0xFF) ^
+                   ((Val >> 16) & 0xFF) ^
+                   ((Val >>  8) & 0xFF) ^
+                   ((Val >>  0) & 0xFF);
+
+    /* Check for this symbol */
+    DbgSym* Sym = DbgSymPool [Hash];
+    while (Sym) {
+       /* Is this symbol identical? */
+       if (strcmp (Sym->Name, D->Name) == 0 && EqualExpr (Sym->Expr, D->Expr)) {
+           /* Found */
+           return Sym;
+       }
+
+       /* Next symbol */
+       Sym = Sym->Next;
+    }
+
+    /* This is the first symbol of it's kind */
+    return 0;
+}
+
+
+
+static void InsertDbgSym (DbgSym* D, long Val)
+/* Insert the symbol into the hashed symbol pool */
+{
+    /* Create the hash. We hash over the symbol value */
+    unsigned Hash = ((Val >> 24) & 0xFF) ^
+                   ((Val >> 16) & 0xFF) ^
+                   ((Val >>  8) & 0xFF) ^
+                   ((Val >>  0) & 0xFF);
+
+    /* Insert the symbol */
+    D->Next = DbgSymPool [Hash];
+    DbgSymPool [Hash] = D;
+}
+
+
+
+DbgSym* ReadDbgSym (FILE* F, ObjData* O)
+/* Read a debug symbol from a file, insert and return it */
+{
+    unsigned char Type;
+    char Name [256];
+    DbgSym* D;
+
+    /* Read the type */
+    Type = Read8 (F);
+
+    /* Read the name */
+    ReadStr (F, Name);
+
+    /* Create a new export */
+    D = NewDbgSym (Type, Name, O);
+
+    /* Read the value */
+    if (Type & EXP_EXPR) {
+               D->Expr = ReadExpr (F, O);
+    } else {
+       D->Expr = LiteralExpr (Read32 (F), O);
+    }
+
+    /* Last is the file position where the definition was done */
+    ReadFilePos (F, &D->Pos);
+
+    /* Return the new DbgSym */
+    return D;
+}
+
+
+
+long GetDbgSymVal (DbgSym* D)
+/* Get the value of this symbol */
+{
+    CHECK (D->Expr != 0);
+    return GetExprVal (D->Expr);
+}
+
+
+
+void PrintDbgSymLabels (ObjData* O, FILE* F)
+/* Print the debug symbols in a VICE label file */
+{
+    unsigned I;
+
+    /* Walk through all debug symbols in this module */
+    for (I = 0; I < O->DbgSymCount; ++I) {
+
+       /* Get the next debug symbol */
+       DbgSym* D = O->DbgSyms [I];
+
+       /* Get the symbol value */
+       long Val = GetDbgSymVal (D);
+
+       /* Lookup this symbol in the table. If it is found in the table, it was
+        * already written to the file, so don't emit it twice. If it is not in
+        * the table, insert and output it.
+        */
+               if (GetDbgSym (D, Val) == 0) {
+
+           /* Emit the VICE label line */
+                   fprintf (F, "al %06lX .%s\n", Val, D->Name);
+
+           /* Insert the symbol into the table */
+           InsertDbgSym (D, Val);
+               }
+    }
+}
+
+
+
diff --git a/src/ld65/dbgsyms.h b/src/ld65/dbgsyms.h
new file mode 100644 (file)
index 0000000..a8dc29d
--- /dev/null
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                dbgsyms.h                                 */
+/*                                                                           */
+/*                Debug symbol handing for the ld65 linker                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef DBGSYMS_H
+#define DBGSYMS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Debug symbol structure */
+typedef struct DbgSym_ DbgSym;
+struct DbgSym_ {
+    DbgSym*                    Next;           /* Pool linear list link */
+    unsigned                   Flags;          /* Generic flags */
+    ObjData*                   Obj;            /* Object file that exports the name */
+    FilePos                    Pos;            /* File position of definition */
+    ExprNode*                  Expr;           /* Expression (0 if not def'd) */
+    unsigned char      Type;           /* Type of symbol */
+    char                       Name [1];       /* Name - dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+DbgSym* ReadDbgSym (FILE* F, ObjData* Obj);
+/* Read a debug symbol from a file, insert and return it */
+
+long GetDbgSymVal (DbgSym* D);
+/* Get the value of this symbol */
+
+void PrintDbgSymLabels (ObjData* O, FILE* F);
+/* Print the debug symbols in a VICE label file */
+
+
+
+/* End of dbgsyms.h */
+
+#endif
+
+
+
diff --git a/src/ld65/error.c b/src/ld65/error.c
new file mode 100644 (file)
index 0000000..0476ab7
--- /dev/null
@@ -0,0 +1,106 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*                   Error handling for the ld65 linker                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+    "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+    "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+    "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Warning: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Error: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+    va_list ap;
+    va_start (ap, Format);
+    fprintf (stderr, "Internal error: ");
+    vfprintf (stderr, Format, ap);
+    putc ('\n', stderr);
+    va_end (ap);
+    exit (EXIT_FAILURE);
+}
+
+
+
diff --git a/src/ld65/error.h b/src/ld65/error.h
new file mode 100644 (file)
index 0000000..9f213ab
--- /dev/null
@@ -0,0 +1,87 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*                   Error handling for the ld65 linker                     */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c)                                                       \
+    if (!(c))                                                          \
+       Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c)                                                        \
+    if (!(c))                                                          \
+               Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s)                                                                \
+    Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
diff --git a/src/ld65/exports.c b/src/ld65/exports.c
new file mode 100644 (file)
index 0000000..1929a6a
--- /dev/null
@@ -0,0 +1,662 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                exports.c                                 */
+/*                                                                           */
+/*                   Exports handing for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/symdefs.h"
+#include "../common/hashstr.h"
+
+#include "global.h"
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "expr.h"
+#include "exports.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Hash table */
+#define HASHTAB_SIZE   4081
+static Export*                 HashTab [HASHTAB_SIZE];
+
+/* Import management variables */
+static unsigned                ImpCount = 0;           /* Import count */
+static unsigned                ImpOpen  = 0;           /* Count of open imports */
+
+/* Export management variables */
+static unsigned                ExpCount = 0;           /* Export count */
+static Export**                ExpPool  = 0;           /* Exports array */
+
+/* Defines for the flags in Export */
+#define EXP_USERMARK   0x0001
+
+
+
+/*****************************************************************************/
+/*                             Import handling                              */
+/*****************************************************************************/
+
+
+
+static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj);
+/* Create a new export and initialize it */
+
+
+
+static Import* NewImport (unsigned char Type, ObjData* Obj)
+/* Create a new import and initialize it */
+{
+    /* Allocate memory */
+    Import* I = Xmalloc (sizeof (Import));
+
+    /* Initialize the fields */
+    I->Next    = 0;
+    I->Obj     = Obj;
+    I->V.Name  = 0;
+    I->Type    = Type;
+
+    /* Return the new structure */
+    return I;
+}
+
+
+
+void InsertImport (Import* I)
+/* Insert an import into the table */
+{
+    Export* E;
+    unsigned HashVal;
+
+    /* As long as the import is not inserted, V.Name is valid */
+    const char* Name = I->V.Name;
+
+    /* Create a hash value for the given name */
+    HashVal = HashStr (Name) % HASHTAB_SIZE;
+
+    /* Search through the list in that slot and print matching duplicates */
+    if (HashTab [HashVal] == 0) {
+       /* The slot is empty, we need to insert a dummy export */
+       E = HashTab [HashVal] = NewExport (0, Name, 0);
+       ++ExpCount;
+    } else {
+       E = HashTab [HashVal];
+       while (1) {
+           if (strcmp (E->Name, Name) == 0) {
+               /* We have an entry, L points to it */
+                       break;
+           }
+           if (E->Next == 0) {
+               /* End of list an entry not found, insert a dummy */
+               E->Next = NewExport (0, Name, 0);
+               E = E->Next;            /* Point to dummy */
+               ++ExpCount;             /* One export more */
+                       break;
+           } else {
+               E = E->Next;
+           }
+       }
+    }
+
+    /* Ok, E now points to a valid exports entry for the given import. Insert
+     * the import into the imports list and update the counters.
+     */
+    I->V.Exp   = E;
+    I->Next    = E->ImpList;
+    E->ImpList = I;
+    E->ImpCount++;
+    ++ImpCount;                        /* Total import count */
+    if (E->Expr == 0) {
+               /* This is a dummy export */
+       ++ImpOpen;
+    }
+
+    /* Now free the name since it's no longer needed */
+    Xfree (Name);
+}
+
+
+
+Import* ReadImport (FILE* F, ObjData* Obj)
+/* Read an import from a file and return it */
+{
+    Import* I;
+
+    /* Read the import type and check it */
+    unsigned char Type = Read8 (F);
+    if (Type != IMP_ZP && Type != IMP_ABS) {
+       Error ("Unknown import type in module `%s': %02X", Obj->Name, Type);
+    }
+
+    /* Create a new import */
+    I = NewImport (Type, Obj);
+
+    /* Read the name */
+    I->V.Name = ReadMallocedStr (F);
+
+    /* Read the file position */
+    ReadFilePos (F, &I->Pos);
+
+    /* Return the new import */
+    return I;
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
+/* Create a new export and initialize it */
+{
+    /* Get the length of the symbol name */
+    unsigned Len = strlen (Name);
+
+    /* Allocate memory */
+    Export* E = Xmalloc (sizeof (Export) + Len);
+
+    /* Initialize the fields */
+    E->Next     = 0;
+    E->Flags   = 0;
+    E->Obj      = Obj;
+    E->ImpCount = 0;
+    E->ImpList  = 0;
+    E->Expr            = 0;
+    E->Type            = Type;
+    memcpy (E->Name, Name, Len);
+    E->Name [Len] = '\0';
+
+    /* Return the new entry */
+    return E;
+}
+
+
+
+void InsertExport (Export* E)
+/* Insert an exported identifier and check if it's already in the list */
+{
+    Export* L;
+    Export* Last;
+    Import* Imp;
+    unsigned HashVal;
+
+    /* Create a hash value for the given name */
+    HashVal = HashStr (E->Name) % HASHTAB_SIZE;
+
+    /* Search through the list in that slot */
+    if (HashTab [HashVal] == 0) {
+       /* The slot is empty */
+       HashTab [HashVal] = E;
+       ++ExpCount;
+    } else {
+
+       Last = 0;
+       L = HashTab [HashVal];
+       do {
+           if (strcmp (L->Name, E->Name) == 0) {
+               /* This may be an unresolved external */
+               if (L->Expr == 0) {
+
+                   /* This *is* an unresolved external */
+                   E->Next     = L->Next;
+                   E->ImpCount = L->ImpCount;
+                   E->ImpList  = L->ImpList;
+                   if (Last) {
+                       Last->Next = E;
+                   } else {
+                       HashTab [HashVal] = E;
+                   }
+                           ImpOpen -= E->ImpCount;     /* Decrease open imports now */
+                   Xfree (L);
+                   /* We must run through the import list and change the
+                    * export pointer now.
+                    */
+                   Imp = E->ImpList;
+                   while (Imp) {
+                       Imp->V.Exp = E;
+                       Imp = Imp->Next;
+                   }
+               } else {
+                   /* Duplicate entry, ignore it */
+                   Warning ("Duplicate external identifier: `%s'", L->Name);
+               }
+               return;
+           }
+           Last = L;
+           L = L->Next;
+
+       } while (L);
+
+       /* Insert export at end of queue */
+       Last->Next = E;
+       ++ExpCount;
+    }
+}
+
+
+
+Export* ReadExport (FILE* F, ObjData* O)
+/* Read an export from a file */
+{
+    unsigned char Type;
+    char Name [256];
+    Export* E;
+
+    /* Read the type */
+    Type = Read8 (F);
+
+    /* Read the name */
+    ReadStr (F, Name);
+
+    /* Create a new export */
+    E = NewExport (Type, Name, O);
+
+    /* Read the value */
+    if (Type & EXP_EXPR) {
+               E->Expr = ReadExpr (F, O);
+    } else {
+       E->Expr = LiteralExpr (Read32 (F), O);
+    }
+
+    /* Last is the file position where the definition was done */
+    ReadFilePos (F, &E->Pos);
+
+    /* Return the new export */
+    return E;
+}
+
+
+
+Export* CreateConstExport (const char* Name, long Value)
+/* Create an export for a literal date */
+{
+    /* Create a new export */
+    Export* E = NewExport (EXP_ABS, Name, 0);
+
+    /* Assign the value */
+    E->Expr = LiteralExpr (Value, 0);
+
+    /* Insert the export */
+    InsertExport (E);
+
+    /* Return the new export */
+    return E;
+}
+
+
+
+Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs)
+/* Create an relative export for a memory area offset */
+{
+    /* Create a new export */
+    Export* E = NewExport (EXP_ABS, Name, 0);
+
+    /* Assign the value */
+    E->Expr = MemExpr (Mem, Offs, 0);
+
+    /* Insert the export */
+    InsertExport (E);
+
+    /* Return the new export */
+    return E;
+}
+
+
+
+static Export* FindExport (const char* Name)
+/* Check for an identifier in the list. Return 0 if not found, otherwise
+ * return a pointer to the export.
+ */
+{
+    /* Get a pointer to the list with the symbols hash value */
+    Export* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
+    while (L) {
+        /* Search through the list in that slot */
+       if (strcmp (L->Name, Name) == 0) {
+           /* Entry found */
+           return L;
+       }
+       L = L->Next;
+    }
+
+    /* Not found */
+    return 0;
+}
+
+
+
+int IsUnresolved (const char* Name)
+/* Check if this symbol is an unresolved export */
+{
+    /* Find the export */
+    Export* E = FindExport (Name);
+
+    /* Check if it's unresolved */
+    return E != 0 && E->Expr == 0;
+}
+
+
+
+int IsConstExport (const Export* E)
+/* Return true if the expression associated with this export is const */
+{
+    if (E->Expr == 0) {
+       /* External symbols cannot be const */
+       return 0;
+    } else {
+        return IsConstExpr (E->Expr);
+    }
+}
+
+
+
+long GetExportVal (const Export* E)
+/* Get the value of this export */
+{
+    if (E->Expr == 0) {
+       /* OOPS */
+               Internal ("`%s' is an undefined external", E->Name);
+    }
+    return GetExprVal (E->Expr);
+}
+
+
+
+static void CheckSymType (Export* E)
+/* Check the types for one export */
+{
+    /* External with matching imports */
+    Import* Imp = E->ImpList;
+    int ZP = (E->Type & EXP_ZP) != 0;
+    while (Imp) {
+       if (ZP != ((Imp->Type & IMP_ZP) != 0)) {
+           /* Export is ZP, import is abs or the other way round */
+           if (E->Obj) {
+               /* User defined export */
+               Warning ("Type mismatch for `%s', export in "
+                        "%s(%lu), import in %s(%lu)",
+                        E->Name, E->Obj->Files [Imp->Pos.Name],
+                        E->Pos.Line, Imp->Obj->Files [Imp->Pos.Name],
+                        Imp->Pos.Line);
+           } else {
+               /* Export created by the linker */
+               Warning ("Type mismatch for `%s', imported from %s(%lu)",
+                        E->Name, Imp->Obj->Files [Imp->Pos.Name],
+                        Imp->Pos.Line);
+           }
+       }
+       Imp = Imp->Next;
+    }
+}
+
+
+
+static void CheckSymTypes (void)
+/* Check for symbol tape mismatches */
+{
+    unsigned I;
+
+    /* Print all open imports */
+    for (I = 0; I < ExpCount; ++I) {
+       Export* E = ExpPool [I];
+       if (E->Expr != 0 && E->ImpCount > 0) {
+           /* External with matching imports */
+           CheckSymType (E);
+       }
+    }
+}
+
+
+
+static void PrintUnresolved (ExpCheckFunc F, void* Data)
+/* Print a list of unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+{
+    unsigned I;
+
+    /* Print all open imports */
+    for (I = 0; I < ExpCount; ++I) {
+       Export* E = ExpPool [I];
+       if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
+           /* Unresolved external */
+           Import* Imp = E->ImpList;
+           fprintf (stderr,
+                    "Unresolved external `%s' referenced in:\n",
+                    E->Name);
+           while (Imp) {
+               const char* Name = Imp->Obj->Files [Imp->Pos.Name];
+               fprintf (stderr, "  %s(%lu)\n", Name, Imp->Pos.Line);
+               Imp = Imp->Next;
+           }
+       }
+    }
+}
+
+
+
+static int CmpExpName (const void* K1, const void* K2)
+/* Compare function for qsort */
+{
+    return strcmp ((*(Export**)K1)->Name, (*(Export**)K2)->Name);
+}
+
+
+
+static void CreateExportPool (void)
+/* Create an array with pointer to all exports */
+{
+    unsigned I, J;
+
+    /* Allocate memory */
+    if (ExpPool) {
+       Xfree (ExpPool);
+    }
+    ExpPool = Xmalloc (ExpCount * sizeof (Export*));
+
+    /* Walk through the list and insert the exports */
+    for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
+       Export* E = HashTab [I];
+       while (E) {
+           CHECK (J < ExpCount);
+           ExpPool [J++] = E;
+           E = E->Next;
+       }
+    }
+
+    /* Sort them by name */
+    qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
+}
+
+
+
+void CheckExports (ExpCheckFunc F, void* Data)
+/* Check if there are any unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+{
+    /* Create an export pool */
+    CreateExportPool ();
+
+    /* Check for symbol type mismatches */
+    CheckSymTypes ();
+
+    /* Check for unresolved externals (check here for special bin formats) */
+    if (ImpOpen != 0) {
+               /* Print all open imports */
+       PrintUnresolved (F, Data);
+    }
+}
+
+
+
+void PrintExportMap (FILE* F)
+/* Print an export map to the given file */
+{
+    unsigned I;
+    unsigned Count;
+
+    /* Print all exports */
+    Count = 0;
+    for (I = 0; I < ExpCount; ++I) {
+       Export* E = ExpPool [I];
+
+       /* Print unreferenced symbols only if explictly requested */
+       if (VerboseMap || E->ImpCount > 0) {
+           fprintf (F,
+                    "%-25s %06lX %c%c    ",
+                    E->Name,
+                    GetExportVal (E),
+                    E->ImpCount? 'R' : ' ',
+                    (E->Type & EXP_ZP)? 'Z' : ' ');
+           if (++Count == 2) {
+               Count = 0;
+               fprintf (F, "\n");
+           }
+       }
+    }
+    fprintf (F, "\n");
+}
+
+
+
+void PrintImportMap (FILE* F)
+/* Print an import map to the given file */
+{
+    unsigned I;
+    Import* Imp;
+
+    /* Loop over all exports */
+    for (I = 0; I < ExpCount; ++I) {
+
+       /* Get the export */
+       Export* Exp = ExpPool [I];
+
+       /* Print the symbol only if there are imports, or if a verbose map
+        * file is requested.
+        */
+       if (VerboseMap || Exp->ImpCount > 0) {
+
+           /* Get the name of the object file that exports the symbol.
+            * Beware: There may be no object file if the symbol is a linker
+            * generated symbol.
+            */
+           const char* ObjName = (Exp->Obj != 0)? Exp->Obj->Name : "linker generated";
+
+           /* Print the export */
+           fprintf (F,
+                    "%s (%s):\n",
+                    Exp->Name,
+                    ObjName);
+
+           /* Print all imports for this symbol */
+           Imp = Exp->ImpList;
+           while (Imp) {
+
+               /* Print the import */
+               fprintf (F,
+                        "    %-25s %s(%lu)\n",
+                        Imp->Obj->Name,
+                        Imp->Obj->Files [Imp->Pos.Name],
+                        Imp->Pos.Line);
+
+               /* Next import */
+               Imp = Imp->Next;
+           }
+       }
+    }
+    fprintf (F, "\n");
+}
+
+
+
+void PrintExportLabels (FILE* F)
+/* Print the exports in a VICE label file */
+{
+    unsigned I;
+
+    /* Print all exports */
+    for (I = 0; I < ExpCount; ++I) {
+       Export* E = ExpPool [I];
+               fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
+    }
+}
+
+
+
+void MarkExport (Export* E)
+/* Mark the export */
+{
+    E->Flags |= EXP_USERMARK;
+}
+
+
+
+void UnmarkExport (Export* E)
+/* Remove the mark from the export */
+{
+    E->Flags &= ~EXP_USERMARK;
+}
+
+
+
+int ExportHasMark (Export* E)
+/* Return true if the export has a mark */
+{
+    return (E->Flags & EXP_USERMARK) != 0;
+}
+
+
+
+void CircularRefError (const Export* E)
+/* Print an error about a circular reference using to define the given export */
+{
+    Error ("Circular reference for symbol `%s', %s(%lu)",
+          E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
+}
+
+
+
diff --git a/src/ld65/exports.h b/src/ld65/exports.h
new file mode 100644 (file)
index 0000000..46a9646
--- /dev/null
@@ -0,0 +1,164 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                exports.h                                 */
+/*                                                                           */
+/*                   Exports handing for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXPORTS_H
+#define EXPORTS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "objdata.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Import symbol structure */
+typedef struct Import_ Import;
+struct Import_ {
+    Import*            Next;           /* Single linked list */
+    ObjData*           Obj;            /* Object file that imports the name */
+    FilePos            Pos;            /* File position of reference */
+    union {
+       struct Export_* Exp;            /* Matching export for this import */
+       const char*     Name;           /* Name if not in table */
+    } V;
+    unsigned char      Type;           /* Type of import */
+};
+
+
+
+/* Export symbol structure */
+typedef struct Export_ Export;
+struct Export_ {
+    Export*                    Next;           /* Hash table link */
+    unsigned           Flags;          /* Generic flags */
+    ObjData*           Obj;            /* Object file that exports the name */
+    unsigned           ImpCount;       /* How many imports for this symbol? */
+    Import*            ImpList;        /* List of imports for this symbol */
+    FilePos            Pos;            /* File position of definition */
+    ExprNode*                  Expr;           /* Expression (0 if not def'd) */
+    unsigned char      Type;           /* Type of export */
+    char               Name [1];       /* Name - dynamically allocated */
+};
+
+
+
+/* Prototype of a function that is called if an undefined symbol is found. It
+ * may check if the symbol is an external symbol (for binary formats that
+ * support externals) and will return zero if the symbol could not be
+ * resolved, or a value != zero if the symbol could be resolved. The
+ * CheckExports routine will print out the missing symbol in the first case.
+ */
+typedef int (*ExpCheckFunc) (const char* Name, void* Data);
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+Import* ReadImport (FILE* F, ObjData* Obj);
+/* Read an import from a file and insert it into the table */
+
+void InsertImport (Import* I);
+/* Insert an import into the table */
+
+Export* ReadExport (FILE* F, ObjData* Obj);
+/* Read an export from a file */
+
+void InsertExport (Export* E);
+/* Insert an exported identifier and check if it's already in the list */
+
+Export* CreateConstExport (const char* Name, long Value);
+/* Create an export for a literal date */
+
+Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs);
+/* Create an relative export for a memory area offset */
+
+int IsUnresolved (const char* Name);
+/* Check if this symbol is an unresolved export */
+
+int IsConstExport (const Export* E);
+/* Return true if the expression associated with this export is const */
+
+long GetExportVal (const Export* E);
+/* Get the value of this export */
+
+void CheckExports (ExpCheckFunc F, void* Data);
+/* Check if there are any unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+
+void PrintExportMap (FILE* F);
+/* Print an export map to the given file */
+
+void PrintImportMap (FILE* F);
+/* Print an import map to the given file */
+
+void PrintExportLabels (FILE* F);
+/* Print the exports in a VICE label file */
+
+void MarkExport (Export* E);
+/* Mark the export */
+
+void UnmarkExport (Export* E);
+/* Remove the mark from the export */
+
+int ExportHasMark (Export* E);
+/* Return true if the export has a mark */
+
+void CircularRefError (const Export* E);
+/* Print an error about a circular reference using to define the given export */
+
+
+
+/* End of exports.h */
+
+#endif
+
+
+
diff --git a/src/ld65/expr.c b/src/ld65/expr.c
new file mode 100644 (file)
index 0000000..a47c653
--- /dev/null
@@ -0,0 +1,622 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 expr.c                                   */
+/*                                                                           */
+/*                Expression evaluation for the ld65 linker                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "../common/exprdefs.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "segments.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/*                                 Helpers                                  */
+/*****************************************************************************/
+
+
+
+static ExprNode* NewExprNode (ObjData* O)
+/* Create a new expression node */
+{
+    /* Allocate fresh memory */
+    ExprNode* N = Xmalloc (sizeof (ExprNode));
+    N->Op      = EXPR_NULL;
+    N->Left    = 0;
+    N->Right   = 0;
+    N->Obj     = O;
+    N->V.Val   = 0;
+
+    return N;
+}
+
+
+
+static void FreeExprNode (ExprNode* E)
+/* Free a node */
+{
+    /* Free the memory */
+    Xfree (E);
+}
+
+
+
+/*****************************************************************************/
+/*             Dump an expression tree on stdout for debugging              */
+/*****************************************************************************/
+
+
+
+static void InternalDumpExpr (const ExprNode* Expr)
+/* Dump an expression in UPN */
+{
+    if (Expr == 0) {
+       return;
+    }
+    InternalDumpExpr (Expr->Left);
+    InternalDumpExpr (Expr->Right);
+
+    switch (Expr->Op) {
+
+       case EXPR_LITERAL:
+           printf (" $%04lX", Expr->V.Val & 0xFFFF);
+           break;
+
+       case EXPR_SYMBOL:
+                   printf (" SYM");
+           break;
+
+       case EXPR_SEGMENT:
+           printf (" SEG");
+           break;
+
+               case EXPR_PLUS:
+           printf (" +");
+           break;
+
+               case EXPR_MINUS:
+           printf (" -");
+           break;
+
+               case EXPR_MUL:
+           printf (" *");
+           break;
+
+               case EXPR_DIV:
+           printf (" /");
+           break;
+
+               case EXPR_MOD:
+           printf (" %%");
+           break;
+
+       case EXPR_OR:
+           printf (" OR");
+           break;
+
+       case EXPR_XOR:
+           printf (" XOR");
+           break;
+
+       case EXPR_AND:
+           printf (" AND");
+           break;
+
+       case EXPR_SHL:
+           printf (" SHL");
+           break;
+
+       case EXPR_SHR:
+           printf (" SHR");
+           break;
+
+               case EXPR_EQ:
+           printf (" =");
+           break;
+
+               case EXPR_NE:
+           printf ("<>");
+           break;
+
+               case EXPR_LT:
+           printf (" <");
+           break;
+
+               case EXPR_GT:
+           printf (" >");
+           break;
+
+               case EXPR_UNARY_MINUS:
+           printf (" NEG");
+           break;
+
+               case EXPR_NOT:
+           printf (" ~");
+           break;
+
+               case EXPR_LOBYTE:
+           printf (" LO");
+           break;
+
+               case EXPR_HIBYTE:
+           printf (" HI");
+           break;
+
+               case EXPR_SWAP:
+           printf (" SWAP");
+           break;
+
+       case EXPR_BAND:
+           printf (" BOOL_AND");
+           break;
+
+       case EXPR_BOR:
+           printf (" BOOL_OR");
+           break;
+
+       case EXPR_BXOR:
+           printf (" BOOL_XOR");
+           break;
+
+       case EXPR_BNOT:
+           printf (" BOOL_NOT");
+           break;
+
+        default:
+                   Internal ("Unknown Op type: %u", Expr->Op);
+
+    }
+}
+
+
+
+void DumpExpr (const ExprNode* Expr)
+/* Dump an expression tree to stdout */
+{
+    InternalDumpExpr (Expr);
+    printf ("\n");
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void FreeExpr (ExprNode* Root)
+/* Free the expression, Root is pointing to. */
+{
+    if (Root) {
+       FreeExpr (Root->Left);
+       FreeExpr (Root->Right);
+       FreeExprNode (Root);
+    }
+}
+
+
+
+int IsConstExpr (ExprNode* Root)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+{
+    int Const;
+    Export* E;
+
+    if (EXPR_IS_LEAF (Root->Op)) {
+       switch (Root->Op) {
+
+           case EXPR_LITERAL:
+               return 1;
+
+           case EXPR_SYMBOL:
+               /* Get the referenced export */
+                       E = GetExprExport (Root);
+               /* If this export has a mark set, we've already encountered it.
+                * This means that the export is used to define it's own value,
+                * which in turn means, that we have a circular reference.
+                */
+               if (ExportHasMark (E)) {
+                   Error ("Circular reference for symbol `%s', %s(%u)",
+                          E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
+                   Const = 0;
+               } else {
+                   MarkExport (E);
+                   Const = IsConstExport (E);
+                   UnmarkExport (E);
+               }
+               return Const;
+
+           default:
+               return 0;
+
+       }
+    } else if (EXPR_IS_UNARY (Root->Op)) {
+
+       return IsConstExpr (Root->Left);
+
+    } else {
+
+       /* We must handle shortcut boolean expressions here */
+       switch (Root->Op) {
+
+           case EXPR_BAND:
+               if (IsConstExpr (Root->Left)) {
+                   /* lhs is const, if it is zero, don't eval right */
+                   if (GetExprVal (Root->Left) == 0) {
+                       return 1;
+                   } else {
+                       return IsConstExpr (Root->Right);
+                   }
+               } else {
+                   /* lhs not const --> tree not const */
+                   return 0;
+               }
+               break;
+
+           case EXPR_BOR:
+               if (IsConstExpr (Root->Left)) {
+                   /* lhs is const, if it is not zero, don't eval right */
+                   if (GetExprVal (Root->Left) != 0) {
+                       return 1;
+                   } else {
+                       return IsConstExpr (Root->Right);
+                   }
+               } else {
+                   /* lhs not const --> tree not const */
+                   return 0;
+               }
+               break;
+
+           default:
+               /* All others are handled normal */
+               return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
+       }
+    }
+}
+
+
+
+Import* GetExprImport (ExprNode* Expr)
+/* Get the import data structure for a symbol expression node */
+{
+    /* Check that this is really a symbol */
+    PRECONDITION (Expr->Op == EXPR_SYMBOL);
+
+    /* Return the import */
+    return Expr->Obj->Imports [Expr->V.ImpNum];
+}
+
+
+
+Export* GetExprExport (ExprNode* Expr)
+/* Get the exported symbol for a symbol expression node */
+{
+    /* Check that this is really a symbol */
+    PRECONDITION (Expr->Op == EXPR_SYMBOL);
+
+    /* Return the export */
+    return Expr->Obj->Imports [Expr->V.ImpNum]->V.Exp;
+}
+
+
+
+Section* GetExprSection (ExprNode* Expr)
+/* Get the segment for a segment expression node */
+{
+    /* Check that this is really a segment node */
+    PRECONDITION (Expr->Op == EXPR_SEGMENT);
+
+    /* Return the export */
+    return Expr->Obj->Sections [Expr->V.SegNum];
+}
+
+
+
+long GetExprVal (ExprNode* Expr)
+/* Get the value of a constant expression */
+{
+    long Right, Left, Val;
+    Section* S;
+    Export* E;
+
+    switch (Expr->Op) {
+
+               case EXPR_LITERAL:
+           return Expr->V.Val;
+
+               case EXPR_SYMBOL:
+           /* Get the referenced export */
+                   E = GetExprExport (Expr);
+           /* If this export has a mark set, we've already encountered it.
+            * This means that the export is used to define it's own value,
+            * which in turn means, that we have a circular reference.
+            */
+           if (ExportHasMark (E)) {
+               CircularRefError (E);
+               Val = 0;
+           } else {
+               MarkExport (E);
+               Val = GetExportVal (E);
+               UnmarkExport (E);
+           }
+           return Val;
+
+        case EXPR_SEGMENT:
+                   S = GetExprSection (Expr);
+           return S->Offs + S->Seg->PC;
+
+       case EXPR_MEMAREA:
+                   return Expr->V.MemArea->Start;
+
+               case EXPR_PLUS:
+           return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
+
+               case EXPR_MINUS:
+           return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
+
+               case EXPR_MUL:
+           return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
+
+               case EXPR_DIV:
+           Left  = GetExprVal (Expr->Left);
+           Right = GetExprVal (Expr->Right);
+           if (Right == 0) {
+               Error ("Division by zero");
+           }
+           return Left / Right;
+
+               case EXPR_MOD:
+           Left  = GetExprVal (Expr->Left);
+           Right = GetExprVal (Expr->Right);
+           if (Right == 0) {
+               Error ("Modulo operation with zero");
+           }
+           return Left % Right;
+
+               case EXPR_OR:
+                   return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
+
+               case EXPR_XOR:
+                   return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
+
+               case EXPR_AND:
+                   return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
+
+               case EXPR_SHL:
+                   return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
+
+               case EXPR_SHR:
+                   return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
+
+               case EXPR_EQ:
+                   return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
+
+               case EXPR_NE:
+                   return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
+
+               case EXPR_LT:
+           return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
+
+               case EXPR_GT:
+           return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
+
+               case EXPR_LE:
+           return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
+
+               case EXPR_GE:
+           return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
+
+               case EXPR_UNARY_MINUS:
+           return -GetExprVal (Expr->Left);
+
+               case EXPR_NOT:
+           return ~GetExprVal (Expr->Left);
+
+               case EXPR_LOBYTE:
+           return GetExprVal (Expr->Left) & 0xFF;
+
+               case EXPR_HIBYTE:
+           return (GetExprVal (Expr->Left) >> 8) & 0xFF;
+
+        case EXPR_SWAP:
+           Left = GetExprVal (Expr->Left);
+           return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
+
+       case EXPR_BAND:
+           return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
+
+       case EXPR_BOR:
+           return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
+
+       case EXPR_BXOR:
+           return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+
+       case EXPR_BNOT:
+                   return !GetExprVal (Expr->Left);
+
+        default:
+                   Internal ("Unknown expression Op type: %u", Expr->Op);
+           /* NOTREACHED */
+           return 0;
+    }
+}
+
+
+
+ExprNode* LiteralExpr (long Val, ObjData* O)
+/* Return an expression tree that encodes the given literal value */
+{
+    ExprNode* Expr = NewExprNode (O);
+    Expr->Op = EXPR_LITERAL;
+    Expr->V.Val = Val;
+    return Expr;
+}
+
+
+
+ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O)
+/* Return an expression tree that encodes an offset into the memory area */
+{
+    ExprNode* Root;
+
+    ExprNode* Expr = NewExprNode (O);
+    Expr->Op = EXPR_MEMAREA;
+    Expr->V.MemArea = Mem;
+
+    Root = NewExprNode (O);
+    Root->Op = EXPR_PLUS;
+    Root->Left = Expr;
+    Root->Right = LiteralExpr (Offs, O);
+
+    return Root;
+}
+
+
+
+ExprNode* ReadExpr (FILE* F, ObjData* O)
+/* Read an expression from the given file */
+{
+    ExprNode* Expr;
+
+    /* Read the node tag and handle NULL nodes */
+    unsigned char Op = Read8 (F);
+    if (Op == EXPR_NULL) {
+       return 0;
+    }
+
+    /* Create a new node */
+    Expr = NewExprNode (O);
+    Expr->Op = Op;
+
+    /* Check the tag and handle the different expression types */
+    if (EXPR_IS_LEAF (Op)) {
+       switch (Op) {
+
+           case EXPR_LITERAL:
+               Expr->V.Val = Read32Signed (F);
+               break;
+
+           case EXPR_SYMBOL:
+               /* Read the import number */
+               Expr->V.ImpNum = Read16 (F);
+               break;
+
+           case EXPR_SEGMENT:
+               /* Read the segment number */
+               Expr->V.SegNum = Read8 (F);
+               break;
+
+           default:
+               Error ("Invalid expression op: %02X", Op);
+
+       }
+
+    } else {
+
+       /* Not a leaf node */
+       Expr->Left = ReadExpr (F, O);
+       Expr->Right = ReadExpr (F, O);
+
+    }
+
+    /* Return the tree */
+    return Expr;
+}
+
+
+
+int EqualExpr (ExprNode* E1, ExprNode* E2)
+/* Check if two expressions are identical. */
+{
+    /* If one pointer is NULL, both must be NULL */
+    if ((E1 == 0) ^ (E2 == 0)) {
+       return 0;
+    }
+    if (E1 == 0) {
+       return 1;
+    }
+
+    /* Both pointers not NULL, check OP */
+    if (E1->Op != E2->Op) {
+       return 0;
+    }
+
+    /* OPs are identical, check data for leafs, or subtrees */
+    switch (E1->Op) {
+
+       case EXPR_LITERAL:
+           /* Value must be identical */
+           return (E1->V.Val == E2->V.Val);
+
+       case EXPR_SYMBOL:
+           /* Import number must be identical */
+           return (E1->V.ImpNum == E2->V.ImpNum);
+
+       case EXPR_SEGMENT:
+                   /* Segment number must be identical */
+                   return (E1->V.SegNum == E2->V.SegNum);
+
+       case EXPR_MEMAREA:
+                   /* Memory area must be identical */
+                   return (E1->V.MemArea == E2->V.MemArea);
+
+       default:
+           /* Not a leaf node */
+                   return EqualExpr (E1->Left, E2->Left) && EqualExpr (E1->Right, E2->Right);
+    }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ld65/expr.h b/src/ld65/expr.h
new file mode 100644 (file)
index 0000000..6305e9e
--- /dev/null
@@ -0,0 +1,97 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 expr.h                                   */
+/*                                                                           */
+/*                Expression evaluation for the ld65 linker                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "../common/exprdefs.h"
+
+#include "objdata.h"
+#include "exports.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void FreeExpr (ExprNode* Root);
+/* Free the expression tree, Root is pointing to. */
+
+int IsConstExpr (ExprNode* Root);
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+
+Import* GetExprImport (ExprNode* Expr);
+/* Get the import data structure for a symbol expression node */
+
+Export* GetExprExport (ExprNode* Expr);
+/* Get the exported symbol for a symbol expression node */
+
+Section* GetExprSection (ExprNode* Expr);
+/* Get the segment for a segment expression node */
+
+long GetExprVal (ExprNode* Expr);
+/* Get the value of a constant expression */
+
+ExprNode* LiteralExpr (long Val, ObjData* O);
+/* Return an expression tree that encodes the given literal value */
+
+ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O);
+/* Return an expression tree that encodes an offset into the memory area */
+
+void DumpExpr (const ExprNode* Expr);
+/* Dump an expression tree to stdout */
+
+ExprNode* ReadExpr (FILE* F, ObjData* O);
+/* Read an expression from the given file */
+
+int EqualExpr (ExprNode* E1, ExprNode* E2);
+/* Check if two expressions are identical. */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
diff --git a/src/ld65/extsyms.c b/src/ld65/extsyms.c
new file mode 100644 (file)
index 0000000..73582b3
--- /dev/null
@@ -0,0 +1,237 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                extsyms.c                                 */
+/*                                                                           */
+/*     Handle program external symbols for relocatable output formats       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "extsyms.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure holding an external symbol */
+struct ExtSym_ {
+    ExtSym*    List;           /* Next entry in list of all symbols */
+    ExtSym*            Next;           /* Next entry in hash list */
+    unsigned           Flags;          /* Generic flags */
+    unsigned   Num;            /* Number of external symbol */
+    char               Name [1];       /* Name - dynamically allocated */
+};
+
+/* External symbol table structure */
+#define HASHTAB_SIZE   53
+struct ExtSymTab_ {
+    ExtSym*    Root;           /* List of symbols */
+    ExtSym*    Last;           /* Pointer to last symbol */
+    unsigned   Count;          /* Number of symbols */
+    ExtSym*    HashTab [HASHTAB_SIZE];
+};
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name)
+/* Create a new external symbol and insert it into the table */
+{
+    /* Get the hash value of the string */
+    unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
+
+    /* Get the length of the name */
+    unsigned Len = strlen (Name);
+
+    /* Check for duplicates */
+    ExtSym* E =        GetExtSym (Tab, Name);  /* Don't care about duplicate hash here... */
+    if (E != 0) {
+       /* We do already have a symbol with this name */
+       Error ("Duplicate external symbol `%s'", Name);
+    }
+
+    /* Allocate memory for the structure */
+    E = Xmalloc (sizeof (ExtSym) + Len);
+
+    /* Initialize the structure */
+    E->List  = 0;
+    E->Flags = 0;
+    E->Num   = Tab->Count;
+    memcpy (E->Name, Name, Len+1);
+
+    /* Insert the entry into the list of all symbols */
+    if (Tab->Last == 0) {
+       /* List is empty */
+       Tab->Root = E;
+    } else {
+       /* List not empty */
+               Tab->Last->List = E;
+    }
+    Tab->Last = E;
+    Tab->Count++;
+
+    /* Insert the symbol into the hash table */
+    E->Next = Tab->HashTab [Hash];
+    Tab->HashTab [Hash] = E;
+
+    /* Done, return the created entry */
+    return E;
+}
+
+
+
+static void FreeExtSym (ExtSym* E)
+/* Free an external symbol structure. Will not unlink the entry, so internal
+ * use only.
+ */
+{
+    Xfree (E);
+}
+
+
+
+ExtSymTab* NewExtSymTab (void)
+/* Create a new external symbol table */
+{
+    unsigned I;
+
+    /* Allocate memory */
+    ExtSymTab* Tab = Xmalloc (sizeof (ExtSymTab));
+
+    /* Initialize the fields */
+    Tab->Root  = 0;
+    Tab->Last   = 0;
+    Tab->Count  = 0;
+    for (I = 0; I < HASHTAB_SIZE; ++I) {
+       Tab->HashTab [I] = 0;
+    }
+
+    /* Done, return the hash table */
+    return Tab;
+}
+
+
+
+void FreeExtSymTab (ExtSymTab* Tab)
+/* Free an external symbol structure */
+{
+    /* Free all entries */
+    while (Tab->Root) {
+       ExtSym* E = Tab->Root;
+       Tab->Root = E->Next;
+       FreeExtSym (E);
+    }
+
+    /* Free the struct itself */
+    Xfree (Tab);
+}
+
+
+
+ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name)
+/* Return the entry for the external symbol with the given name. Return NULL
+ * if there is no such symbol.
+ */
+{
+    /* Hash the name */
+    unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
+
+    /* Check the linked list */
+    ExtSym* E = Tab->HashTab [Hash];
+    while (E) {
+       if (strcmp (E->Name, Name) == 0) {
+           /* Found it */
+           break;
+       }
+       E = E->Next;
+    }
+
+    /* Return the symbol we found */
+    return E;
+}
+
+
+
+unsigned ExtSymCount (const ExtSymTab* Tab)
+/* Return the number of symbols in the table */
+{
+    return Tab->Count;
+}
+
+
+
+const ExtSym* ExtSymList (const ExtSymTab* Tab)
+/* Return the start of the symbol list sorted by symbol number. Call
+ * ExtSymNext for the next symbol.
+ */
+{
+    return Tab->Root;
+}
+
+
+
+unsigned ExtSymNum (const ExtSym* E)
+/* Return the number of an external symbol */
+{
+    return E->Num;
+}
+
+
+
+const char* ExtSymName (const ExtSym* E)
+/* Return the symbol name */
+{
+    return E->Name;
+}
+
+
+
+const ExtSym* ExtSymNext (const ExtSym* E)
+/* Return the next symbol in the list */
+{
+    return E->Next;
+}
+
+
+
diff --git a/src/ld65/extsyms.h b/src/ld65/extsyms.h
new file mode 100644 (file)
index 0000000..de6b01b
--- /dev/null
@@ -0,0 +1,99 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                extsyms.h                                 */
+/*                                                                           */
+/*     Handle program external symbols for relocatable output formats       */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef EXTSYMS_H
+#define EXTSYMS_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Forward decl for structure holding an external symbol */
+typedef struct ExtSym_ ExtSym;
+
+/* External symbol table structure */
+typedef struct ExtSymTab_ ExtSymTab;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name);
+/* Create a new external symbol and insert it into the list */
+
+ExtSymTab* NewExtSymTab (void);
+/* Create a new external symbol table */
+
+void FreeExtSymTab (ExtSymTab* Tab);
+/* Free an external symbol structure */
+
+ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name);
+/* Return the entry for the external symbol with the given name. Return NULL
+ * if there is no such symbol.
+ */
+
+unsigned ExtSymCount (const ExtSymTab* Tab);
+/* Return the number of symbols in the table */
+
+const ExtSym* ExtSymList (const ExtSymTab* Tab);
+/* Return the start of the symbol list sorted by symbol number. Call
+ * ExtSymNext for the next symbol.
+ */
+
+unsigned ExtSymNum (const ExtSym* E);
+/* Return the number of an external symbol */
+
+const char* ExtSymName (const ExtSym* E);
+/* Return the symbol name */
+
+const ExtSym* ExtSymNext (const ExtSym* E);
+/* Return the next symbol in the list */
+
+
+
+/* End of extsyms.h */
+
+#endif
+
+
+
diff --git a/src/ld65/fileio.c b/src/ld65/fileio.c
new file mode 100644 (file)
index 0000000..263f3ab
--- /dev/null
@@ -0,0 +1,269 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                fileio.c                                  */
+/*                                                                           */
+/*                      File I/O for the ld65 linker                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val)
+/* Write an 8 bit value to the file */
+{
+    if (putc (Val, F) == EOF) {
+       Error ("Write error (disk full?)");
+    }
+}
+
+
+
+void Write16 (FILE* F, unsigned Val)
+/* Write a 16 bit value to the file */
+{
+    Write8 (F, (unsigned char) Val);
+    Write8 (F, (unsigned char) (Val >> 8));
+}
+
+
+
+void Write24 (FILE* F, unsigned long Val)
+/* Write a 24 bit value to the file */
+{
+    Write8 (F, (unsigned char) Val);
+    Write8 (F, (unsigned char) (Val >> 8));
+    Write8 (F, (unsigned char) (Val >> 16));
+}
+
+
+
+void Write32 (FILE* F, unsigned long Val)
+/* Write a 32 bit value to the file */
+{
+    Write8 (F, (unsigned char) Val);
+    Write8 (F, (unsigned char) (Val >> 8));
+    Write8 (F, (unsigned char) (Val >> 16));
+    Write8 (F, (unsigned char) (Val >> 24));
+}
+
+
+
+void WriteVal (FILE* F, unsigned long Val, unsigned Size)
+/* Write a value of the given size to the output file */
+{
+    switch (Size) {
+
+       case 1:
+           Write8 (F, Val);
+           break;
+
+       case 2:
+           Write16 (F, Val);
+           break;
+
+       case 3:
+           Write24 (F, Val);
+           break;
+
+       case 4:
+           Write32 (F, Val);
+           break;
+
+       default:
+                   Internal ("WriteVal: Invalid size: %u", Size);
+
+    }
+}
+
+
+
+void WriteStr (FILE* F, const char* S)
+/* Write a string to the file */
+{
+    unsigned Len = strlen (S);
+    if (Len > 255) {
+               Internal ("String too long");
+    }
+    Write8 (F, (unsigned char) Len);
+    WriteData (F, S, Len);
+}
+
+
+
+void WriteData (FILE* F, const void* Data, unsigned Size)
+/* Write data to the file */
+{
+    if (fwrite (Data, 1, Size, F) != Size) {
+       Error ("Write error (disk full?)");
+    }
+}
+
+
+
+void WriteMult (FILE* F, unsigned char Val, unsigned long Count)
+/* Write one byte several times to the file */
+{
+    while (Count--) {
+       Write8 (F, Val);
+    }
+}
+
+
+
+unsigned Read8 (FILE* F)
+/* Read an 8 bit value from the file */
+{
+    int C = getc (F);
+    if (C == EOF) {
+       Error ("Read error (file corrupt?)");
+    }
+    return C;
+}
+
+
+
+unsigned Read16 (FILE* F)
+/* Read a 16 bit value from the file */
+{
+    unsigned Lo = Read8 (F);
+    unsigned Hi = Read8 (F);
+    return (Hi << 8) | Lo;
+}
+
+
+
+unsigned long Read24 (FILE* F)
+/* Read a 24 bit value from the file */
+{
+    unsigned long Lo = Read16 (F);
+    unsigned long Hi = Read8 (F);
+    return (Hi << 16) | Lo;
+}
+
+
+
+unsigned long Read32 (FILE* F)
+/* Read a 32 bit value from the file */
+{
+    unsigned long Lo = Read16 (F);
+    unsigned long Hi = Read16 (F);
+    return (Hi << 16) | Lo;
+}
+
+
+
+long Read32Signed (FILE* F)
+/* Read a 32 bit value from the file. Sign extend the value. */
+{
+    /* Read a 32 bit value */
+    unsigned long V = Read32 (F);
+
+    /* Sign extend the value */
+    if (V & 0x80000000UL) {
+       /* Signed value */
+       V |= ~0xFFFFFFFFUL;
+    }
+
+    /* Return it as a long */
+    return (long) V;
+}
+
+
+
+char* ReadStr (FILE* F, char* Str)
+/* Read a string from the file. Str must hold 256 chars at max */
+{
+    /* Read the length byte */
+    unsigned Len = Read8 (F);
+
+    /* Read the string itself */
+    ReadData (F, Str, Len);
+
+    /* Terminate the string and return it */
+    Str [Len] = '\0';
+    return Str;
+}
+
+
+
+char* ReadMallocedStr (FILE* F)
+/* Read a string from the file into a malloced area */
+{
+    /* Read the length byte */
+    unsigned Len = Read8 (F);
+
+    /* Allocate memory */
+    char* Str = Xmalloc (Len + 1);
+
+    /* Read the string itself */
+    ReadData (F, Str, Len);
+
+    /* Terminate the string and return it */
+    Str [Len] = '\0';
+    return Str;
+}
+
+
+
+FilePos* ReadFilePos (FILE* F, FilePos* Pos)
+/* Read a file position from the file */
+{
+    /* The line number is encoded as 24 bit value to save some space */
+    Pos->Line =        Read24 (F);
+    Pos->Col  = Read8 (F);
+    Pos->Name = Read8 (F);
+    return Pos;
+}
+
+
+
+void* ReadData (FILE* F, void* Data, unsigned Size)
+/* Read data from the file */
+{
+    if (fread (Data, 1, Size, F) != Size) {
+       Error ("Read error (file corrupt?)");
+    }
+    return Data;
+}
+
+
+
diff --git a/src/ld65/fileio.h b/src/ld65/fileio.h
new file mode 100644 (file)
index 0000000..390d35e
--- /dev/null
@@ -0,0 +1,111 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                fileio.h                                  */
+/*                                                                           */
+/*                      File I/O for the ld65 linker                        */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef FILEIO_H
+#define FILEIO_H
+
+
+
+#include <stdio.h>
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val);
+/* Write an 8 bit value to the file */
+
+void Write16 (FILE* F, unsigned Val);
+/* Write a 16 bit value to the file */
+
+void Write24 (FILE* F, unsigned long Val);
+/* Write a 24 bit value to the file */
+
+void Write32 (FILE* F, unsigned long Val);
+/* Write a 32 bit value to the file */
+
+void WriteVal (FILE* F, unsigned long Val, unsigned Size);
+/* Write a value of the given size to the output file */
+
+void WriteStr (FILE* F, const char* S);
+/* Write a string to the file */
+
+void WriteData (FILE* F, const void* Data, unsigned Size);
+/* Write data to the file */
+
+void WriteMult (FILE* F, unsigned char Val, unsigned long Count);
+/* Write one byte several times to the file */
+
+unsigned Read8 (FILE* F);
+/* Read an 8 bit value from the file */
+
+unsigned Read16 (FILE* F);
+/* Read a 16 bit value from the file */
+
+unsigned long Read24 (FILE* F);
+/* Read a 24 bit value from the file */
+
+unsigned long Read32 (FILE* F);
+/* Read a 32 bit value from the file */
+
+long Read32Signed (FILE* F);
+/* Read a 32 bit value from the file. Sign extend the value. */
+
+char* ReadStr (FILE* F, char* Str);
+/* Read a string from the file. Str must hold 256 chars at max */
+
+char* ReadMallocedStr (FILE* F);
+/* Read a string from the file into a malloced area */
+
+FilePos* ReadFilePos (FILE* F, FilePos* Pos);
+/* Read a file position from the file */
+
+void* ReadData (FILE* F, void* Data, unsigned Size);
+/* Read data from the file */
+
+
+
+/* End of fileio.h */
+
+#endif
+
+
+
diff --git a/src/ld65/global.c b/src/ld65/global.c
new file mode 100644 (file)
index 0000000..ffad095
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.c                                  */
+/*                                                                           */
+/*                  Global variables for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+const char* ProgName               = "ld65";   /* Program name */
+
+const char* OutputName     = "a.out";  /* Name of output file */
+
+unsigned long StartAddr            = 0x200;    /* Start address */
+
+unsigned char Verbose       = 0;               /* Verbose operation flag */
+unsigned char VerboseMap    = 0;       /* Verbose map file */
+const char* MapFileName            = 0;        /* Name of the map file */
+const char* LabelFileName   = 0;       /* Name of the label file */
+unsigned char WProtSegs     = 0;       /* Mark write protected segments */
+
+
+
diff --git a/src/ld65/global.h b/src/ld65/global.h
new file mode 100644 (file)
index 0000000..39056cf
--- /dev/null
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                global.h                                  */
+/*                                                                           */
+/*                  Global variables for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+extern const char*     ProgName;       /* Program name */
+
+extern const char*     OutputName;     /* Name of output file */
+
+extern unsigned long   StartAddr;      /* Start address */
+
+extern unsigned char   Verbose;        /* Verbose operation flag */
+extern unsigned char   VerboseMap;     /* Verbose map file */
+extern const char*     MapFileName;    /* Name of the map file */
+extern const char*     LabelFileName;  /* Name of the label file */
+extern unsigned char           WProtSegs;      /* Mark write protected segments */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
diff --git a/src/ld65/library.c b/src/ld65/library.c
new file mode 100644 (file)
index 0000000..d9649a2
--- /dev/null
@@ -0,0 +1,285 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                library.c                                 */
+/*                                                                          */
+/*         Library data structures and helpers for the ld65 linker          */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/objdefs.h"
+#include "../common/libdefs.h"
+#include "../common/symdefs.h"
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "objfile.h"
+#include "exports.h"
+#include "library.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+/* Library data */
+static FILE*           Lib             = 0;
+static char*           LibName         = 0;
+static unsigned                ModuleCount     = 0;
+static ObjData**       Index           = 0;
+
+
+
+/*****************************************************************************/
+/*                      Reading file data structures                        */
+/*****************************************************************************/
+
+
+
+static void LibReadObjHeader (ObjData* O)
+/* Read the header of the object file checking the signature */
+{
+    O->Header.Magic     = Read32 (Lib);
+    if (O->Header.Magic != OBJ_MAGIC) {
+       Error ("Object file `%s' in library `%s' is invalid", O->Name, LibName);
+    }
+    O->Header.Version   = Read16 (Lib);
+    if (O->Header.Version != OBJ_VERSION) {
+       Error ("Object file `%s' in library `%s' has wrong version",
+              O->Name, LibName);
+    }
+    O->Header.Flags     = Read16 (Lib);
+    O->Header.OptionOffs = Read32 (Lib);
+    O->Header.OptionSize = Read32 (Lib);
+    O->Header.FileOffs  = Read32 (Lib);
+    O->Header.FileSize  = Read32 (Lib);
+    O->Header.SegOffs   = Read32 (Lib);
+    O->Header.SegSize   = Read32 (Lib);
+    O->Header.ImportOffs = Read32 (Lib);
+    O->Header.ImportSize = Read32 (Lib);
+    O->Header.ExportOffs = Read32 (Lib);
+    O->Header.ExportSize = Read32 (Lib);
+    O->Header.DbgSymOffs = Read32 (Lib);
+    O->Header.DbgSymSize = Read32 (Lib);                                       
+}
+
+
+
+static ObjData* ReadIndexEntry (void)
+/* Read one entry in the index */
+{
+    unsigned I;
+
+    /* Create a new entry and insert it into the list */
+    ObjData* O = NewObjData ();
+
+    /* Module name/flags/MTime/Start/Size */
+    O->Name    = ReadMallocedStr (Lib);
+    O->Flags   = Read16 (Lib);
+    Read32 (Lib);                      /* Skip MTime */
+    O->Start   = Read32 (Lib);
+    Read32 (Lib);                      /* Skip Size */
+
+    /* Skip the export size, then read the exports */
+    Read16 (Lib);
+    O->ExportCount = Read16 (Lib);
+    O->Exports = Xmalloc (O->ExportCount * sizeof (Export*));
+    for (I = 0; I < O->ExportCount; ++I) {
+       O->Exports [I] = ReadExport (Lib, O);
+    }
+
+    /* Skip the import size, then read the imports */
+    Read16 (Lib);
+    O->ImportCount = Read16 (Lib);
+    O->Imports = Xmalloc (O->ImportCount * sizeof (Import*));
+    for (I = 0; I < O->ImportCount; ++I) {
+       O->Imports [I] = ReadImport (Lib, O);
+    }
+
+    /* Done */
+    return O;
+}
+
+
+
+static void ReadIndex (void)
+/* Read the index of a library file */
+{
+    unsigned I;
+
+    /* Read the object file count and allocate memory */
+    ModuleCount = Read16 (Lib);
+    Index = Xmalloc (ModuleCount * sizeof (ObjData*));
+
+    /* Read all entries in the index */
+    for (I = 0; I < ModuleCount; ++I) {
+       Index [I] = ReadIndexEntry ();
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            High level stuff                              */
+/*****************************************************************************/
+
+
+
+static void LibCheckExports (ObjData* O)
+/* Check if the exports from this file can satisfy any import requests. If so,
+ * insert the imports and exports from this file and mark the file as added.
+ */
+{
+    unsigned I;
+
+    /* Check all exports */
+    for (I = 0; I < O->ExportCount; ++I) {
+       if (IsUnresolved (O->Exports [I]->Name)) {
+           /* We need this module */
+           O->Flags |= OBJ_REF;
+           break;
+       }
+    }
+
+    /* If we need this module, insert the imports and exports */
+    if (O->Flags & OBJ_REF) {
+       /* Insert the exports */
+       for (I = 0; I < O->ExportCount; ++I) {
+           InsertExport (O->Exports [I]);
+       }
+       /* Insert the imports */
+       for (I = 0; I < O->ImportCount; ++I) {
+           InsertImport (O->Imports [I]);
+       }
+    }
+}
+
+
+
+void LibAdd (FILE* F, const char* Name)
+/* Add files from the library to the list if there are references that could
+ * be satisfied.
+ */
+{
+    int Add;
+    unsigned I;
+    LibHeader Header;
+
+    /* Store the parameters, so they're visible for other routines */
+    Lib     = F;
+    LibName = StrDup (Name);
+
+    /* Read the remaining header fields (magic is already read) */
+    Header.Magic   = LIB_MAGIC;
+    Header.Version = Read16 (Lib);
+    if (Header.Version != LIB_VERSION) {
+       Error ("Wrong data version in `%s'", Name);
+    }
+    Header.Flags   = Read16 (Lib);
+    Header.IndexOffs = Read32 (Lib);
+
+    /* Seek to the index position and read the index */
+    fseek (Lib, Header.IndexOffs, SEEK_SET);
+    ReadIndex ();
+
+    /* Walk through all library modules and check for each module if there
+     * are unresolved externals in existing modules that may be resolved
+     * by adding the module. Repeat this step until no more object files
+     * were added.
+     */
+    do {
+       Add = 0;
+       for (I = 0; I < ModuleCount; ++I) {
+           ObjData* O = Index [I];
+           if ((O->Flags & OBJ_REF) == 0) {
+               LibCheckExports (O);
+               if (O->Flags & OBJ_REF) {
+                   /* The routine added the file */
+                   Add = 1;
+               }
+           }
+       }
+    } while (Add);
+
+    /* Add the files list and sections for all requested modules */
+    for (I = 0; I < ModuleCount; ++I) {
+       ObjData* O = Index [I];
+       if (O->Flags & OBJ_REF) {
+
+           /* Seek to the start of the object file and read the header */
+           fseek (Lib, O->Start, SEEK_SET);
+           LibReadObjHeader (O);
+
+           /* Seek to the start of the files list and read the files list */
+           fseek (Lib, O->Start + O->Header.FileOffs, SEEK_SET);
+           ObjReadFiles (Lib, O);
+
+           /* Seek to the start of the segment list and read the segments */
+           fseek (Lib, O->Start + O->Header.SegOffs, SEEK_SET);
+           ObjReadSections (Lib, O);
+
+           /* Seek to the start of the debug info and read the debug info */
+           fseek (Lib, O->Start + O->Header.DbgSymOffs, SEEK_SET);
+           ObjReadDbgSyms (Lib, O);
+
+           /* We have the data now */
+           O->Flags |= OBJ_HAVEDATA;
+
+       }
+
+       /* Add a pointer to the library name */
+       O->LibName = LibName;
+    }
+
+    /* Done. Close the file, release allocated memory */
+    fclose (F);
+    Xfree (Index);
+    Lib                = 0;
+    LibName    = 0;
+    ModuleCount = 0;
+    Index      = 0;
+}
+
+
+
+
+
+
+
diff --git a/src/ld65/library.h b/src/ld65/library.h
new file mode 100644 (file)
index 0000000..f4c5281
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                library.h                                 */
+/*                                                                           */
+/*         Library data structures and helpers for the ld65 linker          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef LIBRARY_H
+#define LIBRARY_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void LibAdd (FILE* F, const char* Name);
+/* Add files from the library to the list if there are references that could
+ * be satisfied.
+ */
+
+
+
+/* End of library.h */
+
+#endif
+
+
+
diff --git a/src/ld65/main.c b/src/ld65/main.c
new file mode 100644 (file)
index 0000000..eb76f35
--- /dev/null
@@ -0,0 +1,391 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                 main.c                                   */
+/*                                                                          */
+/*                    Main program for the ld65 linker                      */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/libdefs.h"
+#include "../common/objdefs.h"
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "target.h"
+#include "fileio.h"
+#include "scanner.h"
+#include "config.h"
+#include "objfile.h"
+#include "library.h"
+#include "exports.h"
+#include "segments.h"
+#include "mapfile.h"
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+static unsigned                ObjFiles   = 0; /* Count of object files linked */
+static unsigned                LibFiles   = 0; /* Count of library files linked */
+static const char*     LibPath    = 0; /* Search path for modules */
+static unsigned                LibPathLen = 0; /* Length of LibPath */
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+    fprintf (stderr,
+            "Usage: %s [options] module ...\n"
+            "Options are:\n"
+            "\t-m name\t\tCreate a map file\n"
+            "\t-o name\t\tName the default output file\n"
+            "\t-t type\t\tType of target system\n"
+            "\t-v\t\tVerbose mode\n"
+            "\t-vm\t\tVerbose map file\n"
+            "\t-C name\t\tUse linker config file\n"
+                    "\t-Ln name\tCreate a VICE label file\n"
+            "\t-Lp\t\tMark write protected segments as such (VICE)\n"
+            "\t-S addr\t\tSet the default start address\n"
+            "\t-V\t\tPrint linker version\n",
+            ProgName);
+    exit (EXIT_FAILURE);
+}
+
+
+
+static void UnknownOption (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+    fprintf (stderr, "Unknown option: %s\n", Arg);
+    Usage ();
+}
+
+
+
+static void InvNumber (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+    fprintf (stderr, "Invalid number given in argument: %s\n", Arg);
+    Usage ();
+}
+
+
+
+static unsigned long CvtNumber (const char* Arg, const char* Number)
+/* Convert a number from a string. Allow '$' and '0x' prefixes for hex
+ * numbers.
+ */
+{
+    unsigned long Val;
+
+    /* Convert */
+    if (*Number == '$') {
+       ++Number;
+       if (sscanf (Number, "%lx", &Val) != 1) {
+           InvNumber (Arg);
+       }
+    } else {
+       if (sscanf (Number, "%li", (long*)&Val) != 1) {
+           InvNumber (Arg);
+       }
+    }
+
+    /* Return the result */
+    return Val;
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+    const char* Arg = argv [*ArgNum];
+    if (Arg [Len] != '\0') {
+       /* Argument appended */
+       return Arg + Len;
+    } else {
+       /* Separate argument */
+       Arg = argv [*ArgNum + 1];
+       if (Arg == 0) {
+           /* End of arguments */
+           fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+           exit (EXIT_FAILURE);
+       }
+       ++(*ArgNum);
+       return Arg;
+    }
+}
+
+
+
+static void LongOption (int* Arg, char* argv [])
+/* Handle a long command line option */
+{
+    /* For now ... */
+    UnknownOption (argv [*Arg]);
+}
+
+
+
+static int HasPath (const char* Name)
+/* Check if the given Name has a path component */
+{
+    return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
+}
+
+
+
+static void LinkFile (const char* Name)
+/* Handle one file */
+{
+    unsigned long Magic;
+    unsigned Len;
+    char* NewName = 0;
+
+    /* Try to open the file */
+    FILE* F = fopen (Name, "rb");
+    if (F == 0) {
+       /* We couldn't open the file. If the name doesn't have a path, and we
+        * have a search path given, try the name with the search path
+        * prepended.
+        */
+       if (LibPathLen > 0 && !HasPath (Name)) {
+           /* Allocate memory. Account for the trailing zero, and for a
+            * path separator character eventually needed.
+            */
+           Len = LibPathLen;
+           NewName = Xmalloc (strlen (Name) + Len + 2);
+           /* Build the new name */
+           memcpy (NewName, LibPath, Len);
+           if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') {
+               /* We need an additional path separator */
+               NewName [Len++] = '/';
+           }
+           strcpy (NewName + Len, Name);
+
+           /* Now try to open the new file */
+           F = fopen (NewName, "rb");
+       }
+
+       if (F == 0) {
+           Error ("Cannot open `%s': %s", Name, strerror (errno));
+       }
+    }
+
+    /* Read the magic word */
+    Magic = Read32 (F);
+
+    /* Do we know this type of file? */
+    switch (Magic) {
+
+       case OBJ_MAGIC:
+           ObjAdd (F, Name);
+           ++ObjFiles;
+           break;
+
+       case LIB_MAGIC:
+           LibAdd (F, Name);
+           ++LibFiles;
+           break;
+
+       default:
+           fclose (F);
+           Error ("File `%s' has unknown type", Name);
+
+    }
+
+    /* If we have allocated memory, free it here. Note: Memory will not always
+     * be freed if we run into an error, but that's no problem. Adding more
+     * code to work around it will use more memory than the chunk that's lost.
+     */
+    Xfree (NewName);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+    int I;
+
+    /* Evaluate the CC65_LIB environment variable */
+    LibPath = getenv ("CC65_LIB");
+    if (LibPath == 0) {
+       /* Use some default path */
+#ifdef CC65_LIB
+       LibPath = CC65_LIB;
+#else
+       LibPath = "/usr/lib/cc65/lib/";
+#endif
+    }
+    LibPathLen = strlen (LibPath);
+
+    /* Check the parameters */
+    I = 1;
+    while (I < argc) {
+
+       /* Get the argument */
+       const char* Arg = argv [I];
+
+       /* Check for an option */
+       if (Arg [0] == '-') {
+
+           /* An option */
+           switch (Arg [1]) {
+
+               case '-':
+                   LongOption (&I, argv);
+                   break;
+
+               case 'm':
+                   MapFileName = GetArg (&I, argv, 2);
+                   break;
+
+               case 'o':
+                   OutputName = GetArg (&I, argv, 2);
+                   break;
+
+               case 't':
+                   if (CfgAvail ()) {
+                       Error ("Cannot use -C/-t twice");
+                   }
+                   TgtSet (GetArg (&I, argv, 2));
+                   break;
+
+               case 'v':
+                   switch (Arg [2]) {
+                       case 'm':   VerboseMap = 1;     break;
+                       case '\0':  ++Verbose;          break;
+                       default:    UnknownOption (Arg);
+                   }
+                   break;
+
+               case 'C':
+                   if (CfgAvail ()) {
+                       Error ("Cannot use -C/-t twice");
+                   }
+                   CfgSetName (GetArg (&I, argv, 2));
+                   break;
+
+               case 'L':
+                   switch (Arg [2]) {
+                       case 'n': LabelFileName = GetArg (&I, argv, 3); break;
+                       case 'p': WProtSegs = 1;                        break;
+                       default:  UnknownOption (Arg);
+                   }
+                   break;
+
+               case 'S':
+                   StartAddr = CvtNumber (Arg, GetArg (&I, argv, 2));
+                   break;
+
+               case 'V':
+                   fprintf (stderr,
+                            "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
+                            VER_MAJOR, VER_MINOR, VER_PATCH);
+                   break;
+
+               default:
+                   UnknownOption (Arg);
+                   break;
+           }
+
+       } else {
+
+           /* A filename */
+           LinkFile (Arg);
+
+       }
+
+       /* Next argument */
+       ++I;
+    }
+
+    /* Check if we had any object files */
+    if (ObjFiles == 0) {
+       fprintf (stderr, "No object files to link\n");
+       Usage ();
+    }
+
+    /* Check if we have a valid configuration */
+    if (!CfgAvail ()) {
+       fprintf (stderr, "Memory configuration missing\n");
+       Usage ();
+    }
+
+    /* Read the config file */
+    CfgRead ();
+
+    /* Assign start addresses for the segments, define linker symbols */
+    CfgAssignSegments ();
+
+    /* Create the output file */
+    CfgWriteTarget ();
+
+    /* Check for segments not written to the output file */
+    CheckSegments ();
+
+    /* If requested, create a map file and a label file for VICE */
+    if (MapFileName) {
+       CreateMapFile ();
+    }
+    if (LabelFileName) {
+       CreateLabelFile ();
+    }
+
+    /* Dump the data for debugging */
+    if (Verbose > 1) {
+       SegDump ();
+    }
+
+    /* Return an apropriate exit code */
+    return EXIT_SUCCESS;
+}
+
+
+
diff --git a/src/ld65/make/gcc.mak b/src/ld65/make/gcc.mak
new file mode 100644 (file)
index 0000000..ab0ec91
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# gcc Makefile for ld65
+#
+
+# Default for the compiler lib search path as compiler define
+CDEFS=-DCC65_LIB=\"/usr/lib/cc65/lib/\"
+CFLAGS = -g -O2 -Wall $(CDEFS)
+CC=gcc
+LDFLAGS=
+
+OBJS =         bin.o           \
+       binfmt.o        \
+       config.o        \
+       dbgsyms.o       \
+       error.o         \
+       exports.o       \
+       expr.o          \
+       extsyms.o       \
+       fileio.o        \
+       global.o        \
+       library.o       \
+       main.o          \
+       mapfile.o       \
+        mem.o          \
+       o65.o           \
+       objdata.o       \
+       objfile.o       \
+       scanner.o       \
+       segments.o      \
+       target.o
+
+LIBS = ../common/common.a
+
+
+EXECS = ld65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all:   depend
+       @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ld65:   $(OBJS) $(LIBS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+       rm -f *~ core *.map
+
+zap:   clean
+       rm -f *.o $(EXECS) .depend
+
+       
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep:    $(OBJS:.o=.c)
+       @echo "Creating dependency information"
+       $(CC) -MM $^ > .depend
+
+
diff --git a/src/ld65/make/watcom.mak b/src/ld65/make/watcom.mak
new file mode 100644 (file)
index 0000000..06b3d41
--- /dev/null
@@ -0,0 +1,136 @@
+#
+# ld65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES      .ASM .C .CC .CPP
+.SWAP
+
+AR     = WLIB
+LD     = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG  = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+  $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All OBJ files
+
+OBJS = bin.obj         \
+       binfmt.obj      \
+       config.obj      \
+       dbgsyms.obj     \
+       error.obj       \
+       exports.obj     \
+       expr.obj        \
+       extsyms.obj     \
+       fileio.obj      \
+       global.obj      \
+       library.obj     \
+       main.obj        \
+       mapfile.obj     \
+       mem.obj         \
+       o65.obj         \
+       objdata.obj     \
+       objfile.obj     \
+       scanner.obj     \
+       segments.obj    \
+       target.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all:           ld65
+
+ld65:          ld65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ld65.exe:      $(OBJS) $(LIBS)
+       $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE bin.obj
+FILE binfmt.obj
+FILE config.obj
+FILE dbgsyms.obj
+FILE error.obj
+FILE exports.obj
+FILE expr.obj
+FILE extsyms.obj
+FILE fileio.obj
+FILE global.obj
+FILE library.obj
+FILE main.obj
+FILE mapfile.obj
+FILE mem.obj
+FILE o65.obj
+FILE objdata.obj
+FILE objfile.obj
+FILE scanner.obj
+FILE segments.obj
+FILE target.obj
+LIBRARY ..\common\common.lib
+|
+
+clean:
+       @if exist *.obj del *.obj
+       @if exist *.obj del ld65.exe
+
+strip:
+       @-wstrip ld65.exe
+
diff --git a/src/ld65/mapfile.c b/src/ld65/mapfile.c
new file mode 100644 (file)
index 0000000..8e3582d
--- /dev/null
@@ -0,0 +1,170 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                mapfile.c                                 */
+/*                                                                           */
+/*                  Map file creation for the ld65 linker                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "global.h"
+#include "error.h"
+#include "objdata.h"
+#include "segments.h"
+#include "dbgsyms.h"
+#include "exports.h"
+#include "config.h"
+#include "mapfile.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void CreateMapFile (void)
+/* Create a map file */
+{
+    ObjData* O;
+    unsigned I;
+
+    /* Open the map file */
+    FILE* F = fopen (MapFileName, "w");
+    if (F == 0) {
+       Error ("Cannot create map file `%s': %s", MapFileName, strerror (errno));
+    }
+
+    /* Write a modules list */
+    fprintf (F, "Modules list:\n"
+               "-------------\n");
+    O = ObjRoot;
+    while (O) {
+       if (O->Flags & OBJ_HAVEDATA) {
+           /* We've linked this module */
+           if (O->LibName) {
+               /* The file is from a library */
+               fprintf (F, "%s(%s):\n", O->LibName, O->Name);
+           } else {
+               fprintf (F, "%s:\n", O->Name);
+           }
+           for (I = 0; I < O->SectionCount; ++I) {
+               const Section* S = O->Sections [I];
+               /* Don't include zero sized sections if not explicitly
+                * requested
+                */
+               if (VerboseMap || S->Size > 0) {
+                           fprintf (F, "    %-15s   Offs = %06lX   Size = %06lX\n",
+                            S->Seg->Name, S->Offs, S->Size);
+               }
+           }
+       }
+       O = O->Next;
+    }
+
+    /* Write the segment list */
+    fprintf (F, "\n\n"
+                       "Segment list:\n"
+               "-------------\n");
+    PrintSegmentMap (F);
+
+    /* Write the exports list */
+    fprintf (F, "\n\n"
+               "Exports list:\n"
+               "-------------\n");
+    PrintExportMap (F);
+
+    /* Write the imports list */
+    fprintf (F, "\n\n"
+               "Imports list:\n"
+               "-------------\n");
+    PrintImportMap (F);
+
+    /* Close the file */
+    if (fclose (F) != 0) {
+       Error ("Error closing map file `%s': %s", MapFileName, strerror (errno));
+    }
+}
+
+
+
+void CreateLabelFile (void)
+/* Create a label file */
+{
+    ObjData* O;
+
+    /* Open the map file */
+    FILE* F = fopen (LabelFileName, "w");
+    if (F == 0) {
+       Error ("Cannot create label file `%s': %s", LabelFileName, strerror (errno));
+    }
+
+    /* Print the labels for the export symbols */
+    PrintExportLabels (F);
+
+    /* Print debug symbols from all modules we have linked into the output file */
+    O = ObjRoot;
+    while (O) {
+       if (O->Flags & OBJ_HAVEDATA) {
+           /* We've linked this module */
+           PrintDbgSymLabels (O, F);
+
+       }
+       O = O->Next;
+    }
+
+    /* If we should mark write protected areas as such, do it */
+    if (WProtSegs) {
+       SegDesc* S = SegDescList;
+       while (S) {
+           /* Is this segment write protected and contains data? */
+           if (S->Flags & SF_WPROT && S->Seg->Size > 0) {
+               /* Write protect the memory area in VICE */
+               fprintf (F, "wp %04lX %04lX\n",
+                        S->Seg->PC,
+                        S->Seg->PC + S->Seg->Size - 1);
+           }
+           /* Next segment */
+           S = S->Next;
+       }
+    }
+
+    /* Close the file */
+    if (fclose (F) != 0) {
+       Error ("Error closing map file `%s': %s", LabelFileName, strerror (errno));
+    }
+}
+
+
+
diff --git a/src/ld65/mapfile.h b/src/ld65/mapfile.h
new file mode 100644 (file)
index 0000000..5e63d41
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                mapfile.h                                 */
+/*                                                                           */
+/*                  Map file creation for the ld65 linker                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MAPFILE_H
+#define MAPFILE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void CreateMapFile (void);
+/* Create a map file */
+
+void CreateLabelFile (void);
+/* Create a label file */
+
+
+
+/* End of mapfile.h */
+
+#endif
+
+
+
diff --git a/src/ld65/mem.c b/src/ld65/mem.c
new file mode 100644 (file)
index 0000000..58a8851
--- /dev/null
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                  mem.c                                   */
+/*                                                                          */
+/*                  Memory allocation for the ld65 linker                   */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/*                                  code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+    void* p;
+
+    p = malloc (size);
+    if (p == 0 && size != 0) {
+       Error ("Out of memory");
+    }
+
+    /* Return a pointer to the block */
+    return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+    free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+    unsigned len;
+
+    len = strlen (s) + 1;
+    return memcpy (Xmalloc (len), s, len);
+}
+
+
+
diff --git a/src/ld65/mem.h b/src/ld65/mem.h
new file mode 100644 (file)
index 0000000..b4ecf57
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  mem.h                                   */
+/*                                                                           */
+/*                  Memory allocation for the ld65 linker                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
diff --git a/src/ld65/o65.c b/src/ld65/o65.c
new file mode 100644 (file)
index 0000000..ae67ca0
--- /dev/null
@@ -0,0 +1,1067 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  o65.c                                   */
+/*                                                                           */
+/*                 Module to handle the o65 binary format                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "exports.h"
+#include "expr.h"
+#include "o65.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Header mode bits */
+#define MF_SIZE_32BIT  0x2000          /* All size words are 32bit */
+#define MF_CPU_816             0x8000          /* Executable is for 65816 */
+
+/* The four o65 segment types. Note: These values are identical to the values
+ * needed for the segmentID in the o65 spec.
+ */
+#define O65SEG_UNDEF   0x00
+#define O65SEG_ABS     0x01
+#define O65SEG_TEXT    0x02
+#define O65SEG_DATA    0x03
+#define O65SEG_BSS     0x04
+#define O65SEG_ZP      0x05
+
+/* Relocation type codes for the o65 format */
+#define O65RELOC_WORD  0x80
+#define O65RELOC_HIGH  0x40
+#define O65RELOC_LOW   0x20
+#define O65RELOC_SEGADR        0xc0
+#define O65RELOC_SEG   0xa0
+
+/* O65 executable file header */
+typedef struct O65Header_ O65Header;
+struct O65Header_ {
+    unsigned       Version;            /* Version number for o65 format */
+    unsigned        Mode;                      /* Mode word */
+    unsigned long   TextBase;          /* Base address of text segment */
+    unsigned long   TextSize;          /* Size of text segment */
+    unsigned long   DataBase;          /* Base of data segment */
+    unsigned long   DataSize;          /* Size of data segment */
+    unsigned long   BssBase;           /* Base of bss segment */
+    unsigned long   BssSize;           /* Size of bss segment */
+    unsigned long   ZPBase;            /* Base of zeropage segment */
+    unsigned long   ZPSize;            /* Size of zeropage segment */
+    unsigned long   StackSize;         /* Requested stack size */
+};
+
+/* An o65 option */
+typedef struct O65Option_ O65Option;
+struct O65Option_ {
+    O65Option*     Next;               /* Next in option list */
+    unsigned char   Type;              /* Type of option */
+    unsigned char   Len;               /* Data length */
+    unsigned char   Data [1];          /* Data, dynamically allocated */
+};
+
+/* A o65 relocation table */
+#define RELOC_BLOCKSIZE        4096
+typedef struct O65RelocTab_ O65RelocTab;
+struct O65RelocTab_ {
+    unsigned       Size;               /* Size of the table */
+    unsigned       Fill;               /* Amount used */
+    unsigned char*  Buf;               /* Buffer, dynamically allocated */
+};
+
+/* Structure describing the format */
+struct O65Desc_ {
+    O65Header      Header;             /* File header */
+    O65Option*     Options;            /* List of file options */
+    ExtSymTab*     Exports;            /* Table with exported symbols */
+    ExtSymTab*     Imports;            /* Table with imported symbols */
+    unsigned       Undef;              /* Count of undefined symbols */
+    FILE*          F;                  /* The file we're writing to */
+    char*          Filename;           /* Name of the output file */
+    O65RelocTab*    TextReloc;         /* Relocation table for text segment */
+    O65RelocTab*    DataReloc;         /* Relocation table for data segment */
+
+    unsigned       TextCount;          /* Number of segments assigned to .text */
+    SegDesc**      TextSeg;            /* Array of text segments */
+    unsigned       DataCount;          /* Number of segments assigned to .data */
+    SegDesc**      DataSeg;            /* Array of data segments */
+    unsigned       BssCount;           /* Number of segments assigned to .bss */
+    SegDesc**      BssSeg;             /* Array of bss segments */
+    unsigned       ZPCount;            /* Number of segments assigned to .zp */
+    SegDesc**      ZPSeg;              /* Array of zp segments */
+
+    /* Temporary data for writing segments */
+    unsigned long   SegSize;
+    O65RelocTab*    CurReloc;
+    long           LastOffs;
+};
+
+/* Structure for parsing expression trees */
+typedef struct ExprDesc_ ExprDesc;
+struct ExprDesc_ {
+    O65Desc*       D;                  /* File format descriptor */
+    long           Val;                /* The offset value */
+    int                    TooComplex;         /* Expression too complex */
+    Section*       SegRef;             /* Section referenced if any */
+    ExtSym*        ExtRef;             /* External reference if any */
+};
+
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static void WriteSize (const O65Desc* D, unsigned long Val)
+/* Write a "size" word to the file */
+{
+    if (D->Header.Mode & MF_SIZE_32BIT) {
+       Write32 (D->F, Val);
+    } else {
+       Write16 (D->F, (unsigned) Val);
+    }
+}
+
+
+
+static unsigned O65SegType (const SegDesc* S)
+/* Map our own segment types into something o65 compatible */
+{
+    /* Check the segment type. Readonly segments are assign to the o65
+     * text segment, writeable segments that contain data are assigned
+     * to data, bss and zp segments are handled respectively.
+     * Beware: Zeropage segments have the SF_BSS flag set, so be sure
+     * to check SF_ZP first.
+     */
+    if (S->Flags & SF_RO) {
+       return O65SEG_TEXT;
+    } else if (S->Flags & SF_ZP) {
+       return O65SEG_ZP;
+    } else if (S->Flags & SF_BSS) {
+       return O65SEG_BSS;
+    } else {
+       return O65SEG_DATA;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                           Expression handling                            */
+/*****************************************************************************/
+
+
+
+static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign)
+/* Extract and evaluate all constant factors in an subtree that has only
+ * additions and subtractions. If anything other than additions and
+ * subtractions are found, D->TooComplex is set to true.
+ */
+{
+    Export* E;
+
+    switch (Expr->Op) {
+
+       case EXPR_LITERAL:
+           if (Sign < 0) {
+               D->Val -= Expr->V.Val;
+           } else {
+               D->Val += Expr->V.Val;
+           }
+           break;
+
+       case EXPR_SYMBOL:
+           /* Get the referenced Export */
+           E = GetExprExport (Expr);
+           /* If this export has a mark set, we've already encountered it.
+            * This means that the export is used to define it's own value,
+            * which in turn means, that we have a circular reference.
+            */
+           if (ExportHasMark (E)) {
+               CircularRefError (E);
+           } else if (E->Expr == 0) {
+               /* Dummy export, must be an o65 imported symbol */
+               ExtSym* S = O65GetImport (D->D, E->Name);
+               CHECK (S != 0);
+               if (D->ExtRef) {
+                   /* We cannot have more than one external reference in o65 */
+                   D->TooComplex = 1;
+               } else {
+                   /* Remember the external reference */
+                   D->ExtRef = S;
+               }
+           } else {
+               MarkExport (E);
+               O65ParseExpr (E->Expr, D, Sign);
+               UnmarkExport (E);
+           }
+           break;
+
+       case EXPR_SEGMENT:
+           if (D->SegRef) {
+               /* We cannot handle more than one segment reference in o65 */
+               D->TooComplex = 1;
+           } else {
+               /* Remember the segment reference */
+               D->SegRef = GetExprSection (Expr);
+           }
+           break;
+
+       case EXPR_PLUS:
+           O65ParseExpr (Expr->Left, D, Sign);
+           O65ParseExpr (Expr->Right, D, Sign);
+           break;
+
+       case EXPR_MINUS:
+           O65ParseExpr (Expr->Left, D, Sign);
+           O65ParseExpr (Expr->Right, D, -Sign);
+           break;
+
+       default:
+           /* Expression contains illegal operators */
+           D->TooComplex = 1;
+           break;
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                            Relocation tables                             */
+/*****************************************************************************/
+
+
+
+static O65RelocTab* NewO65RelocTab (void)
+/* Create a new relocation table */
+{
+    /* Allocate a new structure */
+    O65RelocTab* R = Xmalloc (sizeof (O65RelocTab));
+
+    /* Initialize the data */
+    R->Size = RELOC_BLOCKSIZE;
+    R->Fill = 0;
+    R->Buf  = Xmalloc (RELOC_BLOCKSIZE);
+
+    /* Return the created struct */
+    return R;
+}
+
+
+
+static void FreeO65RelocTab (O65RelocTab* R)
+/* Free a relocation table */
+{
+    Xfree (R->Buf);
+    Xfree (R);
+}
+
+
+
+static void O65RelocPutByte (O65RelocTab* R, unsigned char B)
+/* Put the byte into the relocation table */
+{
+    /* Do we have enough space in the buffer? */
+    if (R->Fill == R->Size) {
+       /* We need to grow the buffer */
+               unsigned char* NewBuf = Xmalloc (R->Size + RELOC_BLOCKSIZE);
+       memcpy (NewBuf, R->Buf, R->Size);
+       Xfree (R->Buf);
+       R->Buf = NewBuf;
+    }
+
+    /* Put the byte into the buffer */
+    R->Buf [R->Fill++] = B;
+}
+
+
+
+static void O65RelocPutWord (O65RelocTab* R, unsigned W)
+/* Put a word into the relocation table */
+{
+    O65RelocPutByte (R, W);
+    O65RelocPutByte (R, W >> 8);
+}
+
+
+
+static void O65WriteReloc (O65RelocTab* R, FILE* F)
+/* Write the relocation table to the given file */
+{
+    WriteData (F, R->Buf, R->Fill);
+}
+
+
+
+/*****************************************************************************/
+/*                             Option handling                              */
+/*****************************************************************************/
+
+
+
+static O65Option* NewO65Option (unsigned Type, const void* Data, unsigned DataLen)
+/* Allocate and initialize a new option struct */
+{
+    O65Option* O;
+
+    /* Check the length */
+    CHECK (DataLen <= 253);
+
+    /* Allocate memory */
+    O = Xmalloc (sizeof (O65Option) - 1 + DataLen);
+
+    /* Initialize the structure */
+    O->Next            = 0;
+    O->Type            = Type;
+    O->Len             = DataLen;
+    memcpy (O->Data, Data, DataLen);
+
+    /* Return the created struct */
+    return O;
+}
+
+
+
+static void FreeO65Option (O65Option* O)
+/* Free        an O65Option struct */
+{
+    Xfree (O);
+}
+
+
+
+/*****************************************************************************/
+/*                    Subroutines to write o65 sections                     */
+/*****************************************************************************/
+
+
+
+static void O65WriteHeader (O65Desc* D)
+/* Write the header of the executable to the given file */
+{
+    static unsigned char Trailer [5] = {
+               0x01, 0x00, 0x6F, 0x36, 0x35
+    };
+
+    O65Option* O;
+
+
+    /* Write the fixed header */
+    WriteData (D->F, Trailer, sizeof (Trailer));
+    Write8    (D->F, D->Header.Version);
+    Write16   (D->F, D->Header.Mode);
+    WriteSize (D, D->Header.TextBase);
+    WriteSize (D, D->Header.TextSize);
+    WriteSize (D, D->Header.DataBase);
+    WriteSize (D, D->Header.DataSize);
+    WriteSize (D, D->Header.BssBase);
+    WriteSize (D, D->Header.BssSize);
+    WriteSize (D, D->Header.ZPBase);
+    WriteSize (D, D->Header.ZPSize);
+    WriteSize (D, D->Header.StackSize);
+
+    /* Write the options */
+    O = D->Options;
+    while (O) {
+               Write8 (D->F, O->Len + 2);              /* Account for len and type bytes */
+       Write8 (D->F, O->Type);
+       if (O->Len) {
+           WriteData (D->F, O->Data, O->Len);
+       }
+       O = O->Next;
+    }
+
+    /* Write the end-of-options byte */
+    Write8 (D->F, 0);
+}
+
+
+
+static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size,
+                                     unsigned long Offs, void* Data)
+/* Called from SegWrite for an expression. Evaluate the expression, check the
+ * range and write the expression value to the file, update the relocation
+ * table.
+ */
+{
+    long Diff;
+    long BinVal;
+    ExprNode* Expr;
+    ExprDesc ED;
+    unsigned char RelocType;
+
+    /* Cast the Data pointer to its real type, an O65Desc */
+    O65Desc* D = (O65Desc*) Data;
+
+    /* Check for a constant expression */
+    if (IsConstExpr (E)) {
+               /* Write out the constant expression */
+               return SegWriteConstExpr (((O65Desc*)Data)->F, E, Signed, Size);
+    }
+
+    /* We have a relocatable expression that needs a relocation table entry.
+     * Calculate the number of bytes between this entry and the last one, and
+     * setup all necessary intermediate bytes in the relocation table.
+     */
+    Offs += D->SegSize;                /* Calulate full offset */
+    Diff = ((long) Offs) - D->LastOffs;
+    while (Diff > 0xFE) {
+       O65RelocPutByte (D->CurReloc, 0xFF);
+       Diff -= 0xFE;
+    }
+    O65RelocPutByte (D->CurReloc, Diff);
+
+    /* Remember this offset for the next time */
+    D->LastOffs = Offs;
+
+    /* Determine the expression to relocate */
+    Expr = E;
+    if (E->Op == EXPR_LOBYTE || E->Op == EXPR_HIBYTE) {
+       /* Use the real expression */
+               Expr = E->Left;
+    }
+
+    /* Initialize the descriptor for expression parsing */
+    ED.D         = D;
+    ED.Val       = 0;
+    ED.TooComplex = 0;
+    ED.SegRef     = 0;
+    ED.ExtRef     = 0;
+
+    /* Recursively collect information about this expression */
+    O65ParseExpr (Expr, &ED, 1);
+
+    /* We cannot handle both, an imported symbol and a segment ref */
+    if (ED.SegRef != 0 && ED.ExtRef != 0) {
+       ED.TooComplex = 1;
+    }
+
+    /* Bail out if we cannot handle the expression */
+    if (ED.TooComplex) {
+       return SEG_EXPR_TOO_COMPLEX;
+    }
+
+    /* Safety: Check that we are really referencing a symbol or a segment */
+    CHECK (ED.SegRef != 0 || ED.ExtRef != 0);
+
+    /* Write out the offset that goes into the segment. */
+    BinVal = ED.Val;
+    if (E->Op == EXPR_LOBYTE) {
+       BinVal &= 0x00FF;
+    } else if (E->Op == EXPR_HIBYTE) {
+               BinVal = (BinVal >> 8) & 0x00FF;
+    }
+    WriteVal (D->F, BinVal, Size);
+
+    /* Determine the actual type of relocation entry needed from the
+     * information gathered about the expression.
+     */
+    if (E->Op == EXPR_LOBYTE) {
+       RelocType = O65RELOC_LOW;
+    } else if (E->Op == EXPR_HIBYTE) {
+       RelocType = O65RELOC_HIGH;
+    } else {
+       switch (Size) {
+
+           case 1:
+               RelocType = O65RELOC_LOW;
+               break;
+
+           case 2:
+               RelocType = O65RELOC_WORD;
+               break;
+
+           case 3:
+               RelocType = O65RELOC_SEGADR;
+               break;
+
+           case 4:
+               /* 4 byte expression not supported by o65 */
+               return SEG_EXPR_TOO_COMPLEX;
+
+           default:
+               Internal ("O65WriteExpr: Invalid expression size: %u", Size);
+               RelocType = 0;          /* Avoid gcc warnings */
+       }
+    }
+
+    /* Determine which segment we're referencing */
+    if (ED.ExtRef) {
+       /* Imported symbol */
+       RelocType |= O65SEG_UNDEF;
+               O65RelocPutByte (D->CurReloc, RelocType);
+               /* Put the number of the imported symbol into the table */
+               O65RelocPutWord (D->CurReloc, ExtSymNum (ED.ExtRef));
+    } else {
+       /* Segment reference */
+
+
+
+    }
+
+    /* Success */
+    return SEG_EXPR_OK;
+}
+
+
+
+static void O65WriteSeg (O65Desc* D, SegDesc** Seg, unsigned Count, int DoWrite)
+/* Write one segment to the o65 output file */
+{
+    SegDesc* S;
+    unsigned I;
+
+    /* Initialize variables */
+    D->SegSize  = 0;
+    D->LastOffs = -1;
+
+    /* Write out all segments */
+    for (I = 0; I < Count; ++I) {
+
+       /* Get the segment from the list node */
+               S = Seg [I];
+
+       /* Keep the user happy */
+       if (Verbose) {
+           printf ("    Writing `%s'\n", S->Name);
+       }
+
+       /* Write this segment */
+       if (DoWrite) {
+                   SegWrite (D->F, S->Seg, O65WriteExpr, D);
+       }
+
+       /* Mark the segment as dumped */
+       S->Seg->Dumped = 1;
+
+       /* Calculate the total size */
+       D->SegSize += S->Seg->Size;
+    }
+
+    /* Terminate the relocation table for the this segment */
+    if (D->CurReloc) {
+        O65RelocPutByte (D->CurReloc, 0);
+    }
+
+    /* Check the size of the segment for overflow */
+    if ((D->Header.Mode & MF_SIZE_32BIT) == 0 && D->SegSize > 0xFFFF) {
+       Error ("Segment overflow in file `%s'", D->Filename);
+    }
+
+}
+
+
+
+static void O65WriteTextSeg (O65Desc* D, Memory* M)
+/* Write the code segment to the o65 output file */
+{
+    /* Initialize variables */
+    D->CurReloc        = D->TextReloc;
+
+    /* Dump all text segments */
+    O65WriteSeg (D, D->TextSeg, D->TextCount, 1);
+
+    /* Set the size of the segment */
+    D->Header.TextSize = D->SegSize;
+}
+
+
+
+static void O65WriteDataSeg (O65Desc* D, Memory* M)
+/* Write the data segment to the o65 output file */
+{
+    /* Initialize variables */
+    D->CurReloc        = D->DataReloc;
+
+    /* Dump all data segments */
+    O65WriteSeg (D, D->DataSeg, D->DataCount, 1);
+
+    /* Set the size of the segment */
+    D->Header.DataSize = D->SegSize;
+}
+
+
+
+static void O65WriteBssSeg (O65Desc* D, Memory* M)
+/* "Write" the bss segments to the o65 output file. This will only update
+ * the relevant header fields.
+ */
+{
+    /* Initialize variables */
+    D->CurReloc        = 0;
+
+    /* Dump all data segments */
+    O65WriteSeg (D, D->BssSeg, D->BssCount, 0);
+
+    /* Set the size of the segment */
+    D->Header.BssSize = D->SegSize;
+}
+
+
+
+static void O65WriteZPSeg (O65Desc* D, Memory* M)
+/* "Write" the zeropage segments to the o65 output file. This will only update
+ * the relevant header fields.
+ */
+{
+    /* Initialize variables */
+    D->CurReloc        = 0;
+
+    /* Dump all data segments */
+    O65WriteSeg (D, D->ZPSeg, D->ZPCount, 0);
+
+    /* Set the size of the segment */
+    D->Header.ZPSize = D->SegSize;
+}
+
+
+
+static void O65WriteImports (O65Desc* D)
+/* Write the list of imported symbols to the O65 file */
+{
+    const ExtSym* E;
+
+    /* Write the number of external symbols */
+    WriteSize (D, ExtSymCount (D->Imports));
+
+    /* Write out the symbol names, zero terminated */
+    E = ExtSymList (D->Imports);
+    while (E) {
+       /* Get the name */
+       const char* Name = ExtSymName (E);
+       /* And write it to the output file */
+       WriteData (D->F, Name, strlen (Name) + 1);
+       /* Next symbol */
+       E = ExtSymNext (E);
+    }
+}
+
+
+
+static void O65WriteTextReloc (O65Desc* D)
+/* Write the relocation for the text segment to the output file */
+{
+    O65WriteReloc (D->TextReloc, D->F);
+}
+
+
+
+static void O65WriteDataReloc (O65Desc* D)
+/* Write the relocation for the data segment to the output file */
+{
+    O65WriteReloc (D->DataReloc, D->F);
+}
+
+
+
+static void O65WriteExports (O65Desc* D)
+/* Write the list of exports */
+{
+    /* For now... */
+    WriteSize (D, 0);
+}
+
+
+
+/*****************************************************************************/
+/*                               Public code                                */
+/*****************************************************************************/
+
+
+
+O65Desc* NewO65Desc (void)
+/* Create, initialize and return a new O65 descriptor struct */
+{
+    /* Allocate a new structure */
+    O65Desc* D = Xmalloc (sizeof (O65Desc));
+
+    /* Initialize the header */
+    D->Header.Version  = 0;
+    D->Header.Mode      = 0;
+    D->Header.TextBase = 0;
+    D->Header.TextSize  = 0;
+    D->Header.DataBase  = 0;
+    D->Header.DataSize  = 0;
+    D->Header.BssBase   = 0;
+    D->Header.BssSize   = 0;
+    D->Header.ZPBase    = 0;
+    D->Header.ZPSize    = 0;
+    D->Header.StackSize = 0;           /* Let OS choose a good value */
+
+    /* Initialize other data */
+    D->Options         = 0;
+    D->Exports         = NewExtSymTab ();
+    D->Imports         = NewExtSymTab ();
+    D->Undef           = 0;
+    D->F               = 0;
+    D->Filename                = 0;
+    D->TextReloc       = NewO65RelocTab ();
+    D->DataReloc       = NewO65RelocTab ();
+    D->TextCount       = 0;
+    D->TextSeg         = 0;
+    D->DataCount       = 0;
+    D->DataSeg         = 0;
+    D->BssCount                = 0;
+    D->BssSeg          = 0;
+    D->ZPCount         = 0;
+    D->ZPSeg           = 0;
+
+    /* Return the created struct */
+    return D;
+}
+
+
+
+void FreeO65Desc (O65Desc* D)
+/* Delete the descriptor struct with cleanup */
+{
+    /* Free the segment arrays */
+    Xfree (D->ZPSeg);
+    Xfree (D->BssSeg);
+    Xfree (D->DataSeg);
+    Xfree (D->TextSeg);
+
+    /* Free the relocation tables */
+    FreeO65RelocTab (D->DataReloc);
+    FreeO65RelocTab (D->TextReloc);
+
+    /* Free the option list */
+    while (D->Options) {
+        O65Option* O = D->Options;
+       D->Options = D->Options->Next;
+       FreeO65Option (O);
+    }
+
+    /* Free the external symbol tables */
+    FreeExtSymTab (D->Exports);
+    FreeExtSymTab (D->Imports);
+
+    /* Free the struct itself */
+    Xfree (D);
+}
+
+
+
+void O65Set816 (O65Desc* D)
+/* Enable 816 mode */
+{
+    D->Header.Mode |= MF_CPU_816;
+}
+
+
+
+void O65SetLargeModel (O65Desc* D)
+/* Enable a large memory model executable */
+{
+    D->Header.Mode |= MF_SIZE_32BIT;
+}
+
+
+
+void O65SetAlignment (O65Desc* D, unsigned Align)
+/* Set the executable alignment */
+{
+    /* Remove all alignment bits from the mode word */
+    D->Header.Mode &= ~0x0003;
+
+    /* Set the alignment bits */
+    switch (Align) {
+       case 1:                           break;
+       case 2:   D->Header.Mode |= 0x01; break;
+       case 4:   D->Header.Mode |= 0x02; break;
+        case 256: D->Header.Mode |= 0x03; break;
+        default:  Error ("Invalid alignment for O65 format: %u", Align);
+    }
+}
+
+
+
+void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen)
+/* Set an o65 header option */
+{
+    /* Create a new option structure */
+    O65Option* O = NewO65Option (Type, Data, DataLen);
+
+    /* Insert it into the linked list */
+    O->Next = D->Options;
+    D->Options = O;
+}
+
+
+
+void O65SetOS (O65Desc* D, unsigned OS)
+/* Set an option describing the target operating system */
+{
+    static const unsigned char OSA65 [2] = { O65OS_OSA65, 0 };
+    static const unsigned char Lunix [2] = { O65OS_LUNIX, 0 };
+
+    /* Write the correct option */
+    switch (OS) {
+
+       case O65OS_OSA65:
+           O65SetOption (D, O65OPT_OS, OSA65, sizeof (OSA65));
+           break;
+
+       case O65OS_LUNIX:
+           O65SetOption (D, O65OPT_OS, Lunix, sizeof (Lunix));
+           break;
+
+       default:
+           Internal ("Trying to set invalid O65 operating system: %u", OS);
+
+    }
+}
+
+
+
+ExtSym* O65GetImport (O65Desc* D, const char* Ident)
+/* Return the imported symbol or NULL if not found */
+{
+    /* Retrieve the symbol from the table */
+    return GetExtSym (D->Imports, Ident);
+}
+
+
+
+void O65SetImport (O65Desc* D, const char* Ident)
+/* Set an imported identifier */
+{
+    /* Insert the entry into the table */
+    NewExtSym (D->Imports, Ident);
+}
+
+
+
+ExtSym* O65GetExport (O65Desc* D, const char* Ident)
+/* Return the exported symbol or NULL if not found */
+{
+    /* Retrieve the symbol from the table */
+    return GetExtSym (D->Exports, Ident);
+}
+
+
+
+void O65SetExport (O65Desc* D, const char* Ident)
+/* Set an exported identifier */
+{
+    /* Insert the entry into the table */
+    NewExtSym (D->Exports, Ident);
+}
+
+
+
+static void O65SetupSegments (O65Desc* D, Memory* M)
+/* Setup segment assignments */
+{
+    MemListNode* N;
+    SegDesc* S;
+    unsigned TextIdx, DataIdx, BssIdx, ZPIdx;
+
+    /* Initialize the counters */
+    D->TextCount = 0;
+    D->DataCount = 0;
+    D->BssCount  = 0;
+    D->ZPCount   = 0;
+
+    /* Walk through the memory list and count the segment types */
+    N = M->SegList;
+    while (N) {
+
+               /* Get the segment from the list node */
+               S = N->Seg;
+
+               /* Check the segment type. */
+       switch (O65SegType (S)) {
+           case O65SEG_TEXT:   D->TextCount++; break;
+           case O65SEG_DATA:   D->DataCount++; break;
+           case O65SEG_BSS:    D->BssCount++;  break;
+           case O65SEG_ZP:     D->ZPCount++;   break;
+           default:            Internal ("Invalid return from O65SegType");
+       }
+
+       /* Next segment node */
+       N = N->Next;
+    }
+
+    /* Allocate memory according to the numbers */
+    D->TextSeg = Xmalloc (D->TextCount * sizeof (SegDesc*));
+    D->DataSeg = Xmalloc (D->DataCount * sizeof (SegDesc*));
+    D->BssSeg  = Xmalloc (D->BssCount  * sizeof (SegDesc*));
+    D->ZPSeg   = Xmalloc (D->ZPCount   * sizeof (SegDesc*));
+
+    /* Walk again through the list and setup the segment arrays */
+    TextIdx = DataIdx = BssIdx = ZPIdx = 0;
+    N = M->SegList;
+    while (N) {
+
+       /* Get the segment from the list node */
+       S = N->Seg;
+
+       /* Check the segment type. */
+       switch (O65SegType (S)) {
+           case O65SEG_TEXT:   D->TextSeg [TextIdx++] = S;     break;
+           case O65SEG_DATA:   D->DataSeg [DataIdx++] = S;     break;
+           case O65SEG_BSS:    D->BssSeg [BssIdx++]   = S;     break;
+           case O65SEG_ZP:     D->ZPSeg [ZPIdx++]     = S;     break;
+           default:            Internal ("Invalid return from O65SegType");
+       }
+
+       /* Next segment node */
+       N = N->Next;
+    }
+}
+
+
+
+static int O65Unresolved (const char* Name, void* D)
+/* Called if an unresolved symbol is encountered */
+{
+    /* Check if the symbol is an imported o65 symbol */
+    if (O65GetImport (D, Name) != 0) {
+       /* This is an external symbol, relax... */
+       return 1;
+    } else {
+       /* This is actually an unresolved external. Bump the counter */
+       ((O65Desc*) D)->Undef++;
+       return 0;
+    }
+}
+
+
+
+void O65WriteTarget (O65Desc* D, File* F)
+/* Write an o65 output file */
+{
+    Memory* M;
+    char OptBuf [256]; /* Buffer for option strings */
+    time_t T;
+
+    /* Place the filename in the control structure */
+    D->Filename = F->Name;
+
+    /* The o65 format uses only one memory area per file. Check that. */
+    M = F->MemList;
+    if (M->Next != 0) {
+       Warning ("Cannot handle more than one memory area for o65 format");
+    }
+
+    /* Check for unresolved symbols. The function O65Unresolved is called
+     * if we get an unresolved symbol.
+     */
+    D->Undef = 0;              /* Reset the counter */
+    CheckExports (O65Unresolved, D);
+    if (D->Undef > 0) {
+       /* We had unresolved symbols, cannot create output file */
+               Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
+    }
+
+    /* Setup the segment arrays */
+    O65SetupSegments (D, M);
+
+    /* Open the file */
+    D->F = fopen (F->Name, "wb");
+    if (D->F == 0) {
+       Error ("Cannot open `%s': %s", F->Name, strerror (errno));
+    }
+
+    /* Keep the user happy */
+    if (Verbose) {
+       printf ("Opened `%s'...\n", F->Name);
+    }
+
+    /* Define some more options: A timestamp and the linker version */
+    T = time (0);
+    strcpy (OptBuf, ctime (&T));
+    O65SetOption (D, O65OPT_TIMESTAMP, OptBuf, strlen (OptBuf) + 1);
+    sprintf (OptBuf, "ld65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+    O65SetOption (D, O65OPT_ASM, OptBuf, strlen (OptBuf) + 1);
+
+    /* Write the header */
+    O65WriteHeader (D);
+
+    /* Write the text segment */
+    O65WriteTextSeg (D, M);
+
+    /* Write the data segment */
+    O65WriteDataSeg (D, M);
+
+    /* "Write" the bss segments */
+    O65WriteBssSeg (D, M);
+
+    /* "Write" the zeropage segments */
+    O65WriteZPSeg (D, M);
+
+    /* Write the undefined references list */
+    O65WriteImports (D);
+
+    /* Write the text segment relocation table */
+    O65WriteTextReloc (D);
+
+    /* Write the data segment relocation table */
+    O65WriteDataReloc (D);
+
+    /* Write the list of exports */
+    O65WriteExports (D);
+
+    /* Seek back to the start and write the updated header */
+    fseek (D->F, 0, SEEK_SET);
+    O65WriteHeader (D);
+
+    /* Close the file */
+    if (fclose (D->F) != 0) {
+       Error ("Cannot write to `%s': %s", F->Name, strerror (errno));
+    }
+
+    /* Reset the file and filename */
+    D->F        = 0;
+    D->Filename = 0;
+}
+
+
+
+
diff --git a/src/ld65/o65.h b/src/ld65/o65.h
new file mode 100644 (file)
index 0000000..d1e6609
--- /dev/null
@@ -0,0 +1,119 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                  o65.h                                   */
+/*                                                                           */
+/*                 Module to handle the o65 binary format                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1999     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef O65_H
+#define O65_H
+
+
+
+#include <stdio.h>
+
+#include "extsyms.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Structure describing the format */
+typedef struct O65Desc_ O65Desc;
+
+/* Option tags */
+#define O65OPT_FILENAME                0
+#define O65OPT_OS              1
+#define O65OPT_ASM             2
+#define O65OPT_AUTHOR          3
+#define O65OPT_TIMESTAMP       4
+
+/* Operating system codes for O65OPT_OS */
+#define O65OS_OSA65            1
+#define O65OS_LUNIX            2
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+O65Desc* NewO65Desc (void);
+/* Create, initialize and return a new O65 descriptor struct */
+
+void FreeO65Desc (O65Desc* D);
+/* Delete the descriptor struct with cleanup */
+
+void O65Set816 (O65Desc* D);
+/* Enable 816 mode */
+
+void O65SetLargeModel (O65Desc* D);
+/* Enable a large memory model executable */
+
+void O65SetAlignment (O65Desc* D, unsigned Align);
+/* Set the executable alignment */
+
+void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen);
+/* Set an o65 header option */
+
+void O65SetOS (O65Desc* D, unsigned OS);
+/* Set an option describing the target operating system */
+
+ExtSym* O65GetImport (O65Desc* D, const char* Ident);
+/* Return the imported symbol or NULL if not found */
+
+void O65SetImport (O65Desc* D, const char* Ident);
+/* Set an imported identifier */
+
+ExtSym* O65GetExport (O65Desc* D, const char* Ident);
+/* Return the exported symbol or NULL if not found */
+
+void O65SetExport (O65Desc* D, const char* Ident);
+/* Set an exported identifier */
+
+void O65WriteTarget (O65Desc* D, File* F);
+/* Write an o65 output file */
+
+
+
+/* End of o65.h */
+
+#endif
+
+
+
diff --git a/src/ld65/objdata.c b/src/ld65/objdata.c
new file mode 100644 (file)
index 0000000..04028cd
--- /dev/null
@@ -0,0 +1,112 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objdata.c                                 */
+/*                                                                           */
+/*              Handling object file data for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Object data list management */
+unsigned       ObjCount = 0;   /* Count of object files in the list */
+ObjData*       ObjRoot  = 0;   /* List of object files */
+ObjData*       ObjLast  = 0;   /* Last entry in list */
+ObjData**              ObjPool  = 0;   /* Object files as array */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void)
+/* Allocate a new structure on the heap, insert it into the list, return it */
+{
+    /* Allocate memory */
+    ObjData* O = Xmalloc (sizeof (ObjData));
+
+    /* Initialize the data */
+    O->Next            = 0;
+    O->Name            = 0;
+    O->LibName         = 0;
+    O->Flags                   = 0;
+    O->Start           = 0;
+    O->ExportCount     = 0;
+    O->Exports         = 0;
+    O->ImportCount     = 0;
+    O->Imports         = 0;
+    O->DbgSymCount     = 0;
+    O->DbgSyms         = 0;
+
+    /* Link it into the list */
+    if (ObjLast) {
+       ObjLast->Next = O;
+       ObjLast       = O;
+    } else {
+       /* First entry */
+       ObjRoot = ObjLast = O;
+    }
+
+    /* One object file more now */
+    ++ObjCount;
+
+    /* Return the new entry */
+    return O;
+}
+
+
+
+void FreeObjData (ObjData* O)
+/* Free a complete struct */
+{
+    Xfree (O->Name);
+    Xfree (O->Imports);
+    Xfree (O->Exports);
+    Xfree (O->DbgSyms);
+    Xfree (O);
+}
+
+
+
diff --git a/src/ld65/objdata.h b/src/ld65/objdata.h
new file mode 100644 (file)
index 0000000..91d994a
--- /dev/null
@@ -0,0 +1,106 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objdata.h                                 */
+/*                                                                           */
+/*              Handling object file data for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDATA_H
+#define OBJDATA_H
+
+
+
+#include "../common/objdefs.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Values for the Flags field */
+#define        OBJ_REF         0x0001          /* We have a reference to this file */
+#define OBJ_HAVEDATA   0x0002          /* We have this object file already */
+#define OBJ_MARKED             0x0004          /* Generic marker bit */
+
+
+/* Internal structure holding object file data */
+typedef struct ObjData_ ObjData;
+struct ObjData_ {
+    ObjData*           Next;           /* Linked list of all objects */
+    char*              Name;           /* Module name */
+    char*                      LibName;        /* Name of library */
+    ObjHeader          Header;         /* Header of file */
+    unsigned long      Start;          /* Start offset of data in library */
+    unsigned           Flags;
+    unsigned           FileCount;      /* Input file count */
+    char**             Files;          /* List of input files */
+    unsigned           SectionCount;   /* Count of sections in this object */
+    struct Section_**          Sections;       /* List of all sections */
+    unsigned           ExportCount;    /* Count of exports */
+    struct Export_**   Exports;        /* List of all exports */
+    unsigned           ImportCount;    /* Count of imports */
+    struct Import_**   Imports;        /* List of all imports */
+    unsigned           DbgSymCount;    /* Count of debug symbols */
+    struct DbgSym_**           DbgSyms;        /* List of debug symbols */
+};
+
+
+
+/* Object data list management */
+extern unsigned                ObjCount;       /* Count of files in the list */
+extern ObjData*                ObjRoot;        /* List of object files */
+extern ObjData*                ObjLast;        /* Last entry in list */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void);
+/* Allocate a new structure on the heap, insert it into the list, return it */
+
+void FreeObjData (ObjData* O);
+/* Free a complete struct */
+
+
+
+/* End of objdata.h */
+
+#endif
+
+
+
diff --git a/src/ld65/objfile.c b/src/ld65/objfile.c
new file mode 100644 (file)
index 0000000..92c8308
--- /dev/null
@@ -0,0 +1,225 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                objfile.c                                 */
+/*                                                                          */
+/*                Object file handling for the ld65 linker                  */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "error.h"
+#include "mem.h"
+#include "objdata.h"
+#include "fileio.h"
+#include "segments.h"
+#include "exports.h"
+#include "dbgsyms.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+static const char* GetModule (const char* Name)
+/* Get a module name from the file name */
+{
+    /* Make a module name from the file name */
+    const char* Module = Name + strlen (Name);
+    while (Module > Name) {
+       --Module;
+       if (*Module == '/' || *Module == '\\') {
+           ++Module;
+           break;
+       }
+    }
+    if (*Module == 0) {
+       Error ("Cannot make module name from `%s'", Name);
+    }
+    return Module;
+}
+
+
+
+static void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
+/* Read the header of the object file checking the signature */
+{
+    H->Version   = Read16 (Obj);
+    if (H->Version != OBJ_VERSION) {
+               Error ("Object file `%s' has wrong version", Name);
+    }
+    H->Flags     = Read16 (Obj);
+    H->OptionOffs = Read32 (Obj);
+    H->OptionSize = Read32 (Obj);
+    H->FileOffs   = Read32 (Obj);
+    H->FileSize   = Read32 (Obj);
+    H->SegOffs   = Read32 (Obj);
+    H->SegSize   = Read32 (Obj);
+    H->ImportOffs = Read32 (Obj);
+    H->ImportSize = Read32 (Obj);
+    H->ExportOffs = Read32 (Obj);
+    H->ExportSize = Read32 (Obj);
+    H->DbgSymOffs = Read32 (Obj);
+    H->DbgSymSize = Read32 (Obj);
+}
+
+
+
+void ObjReadFiles (FILE* F, ObjData* O)
+/* Read the files list from a file at the current position */
+{
+    unsigned I;
+
+    O->FileCount  = Read8 (F);
+    O->Files      = Xmalloc (O->FileCount * sizeof (char*));
+    for (I = 0; I < O->FileCount; ++I) {
+               /* Skip MTime and size */
+               Read32 (F);
+               Read32 (F);
+               /* Read the filename */
+               O->Files [I] = ReadMallocedStr (F);
+    }
+}
+
+
+
+void ObjReadImports (FILE* F, ObjData* O)
+/* Read the imports from a file at the current position */
+{
+    unsigned I;
+
+    O->ImportCount = Read16 (F);
+    O->Imports     = Xmalloc (O->ImportCount * sizeof (Import*));
+    for (I = 0; I < O->ImportCount; ++I) {
+       O->Imports [I] = ReadImport (F, O);
+       InsertImport (O->Imports [I]);
+    }
+}
+
+
+
+void ObjReadExports (FILE* F, ObjData* O)
+/* Read the exports from a file at the current position */
+{
+    unsigned I;
+
+    O->ExportCount = Read16 (F);
+    O->Exports     = Xmalloc (O->ExportCount * sizeof (Export*));
+    for (I = 0; I < O->ExportCount; ++I) {
+       O->Exports [I] = ReadExport (F, O);
+       InsertExport (O->Exports [I]);
+    }
+}
+
+
+
+void ObjReadDbgSyms (FILE* F, ObjData* O)
+/* Read the debug symbols from a file at the current position */
+{
+    unsigned I;
+
+    O->DbgSymCount = Read16 (F);
+    O->DbgSyms    = Xmalloc (O->DbgSymCount * sizeof (DbgSym*));
+    for (I = 0; I < O->DbgSymCount; ++I) {
+       O->DbgSyms [I] = ReadDbgSym (F, O);
+    }
+}
+
+
+
+void ObjReadSections (FILE* F, ObjData* O)
+/* Read the section data from a file at the current position */
+{
+    unsigned I;
+
+    O->SectionCount = Read8 (F);
+    O->Sections     = Xmalloc (O->SectionCount * sizeof (Section*));
+    for (I = 0; I < O->SectionCount; ++I) {
+       O->Sections [I] = ReadSection (F, O);
+    }
+}
+
+
+
+void ObjAdd (FILE* Obj, const char* Name)
+/* Add an object file to the module list */
+{
+    /* Create a new structure for the object file data */
+    ObjData* O = NewObjData ();
+
+    /* The magic was already read and checked, so set it in the header */
+    O->Header.Magic = OBJ_MAGIC;
+
+    /* Read and check the header */
+    ObjReadHeader (Obj, &O->Header, Name);
+
+    /* Initialize the object module data structure */
+    O->Name              = StrDup (GetModule (Name));
+    O->Flags             = OBJ_HAVEDATA;
+
+    /* Read the files list from the object file */
+    fseek (Obj, O->Header.FileOffs, SEEK_SET);
+    ObjReadFiles (Obj, O);
+
+    /* Read the imports list from the object file */
+    fseek (Obj, O->Header.ImportOffs, SEEK_SET);
+    ObjReadImports (Obj, O);
+
+    /* Read the object file exports and insert them into the exports list */
+    fseek (Obj, O->Header.ExportOffs, SEEK_SET);
+    ObjReadExports (Obj, O);
+
+    /* Read the object debug symbols from the object file */
+    fseek (Obj, O->Header.DbgSymOffs, SEEK_SET);
+    ObjReadDbgSyms (Obj, O);
+
+    /* Read the segment list from the object file. This must be last, since
+     * the expressions stored in the code may reference segments or imported
+     * symbols.
+     */
+    fseek (Obj, O->Header.SegOffs, SEEK_SET);
+    ObjReadSections (Obj, O);
+
+    /* Mark this object file as needed */
+    O->Flags |= OBJ_REF | OBJ_HAVEDATA;
+
+    /* Done, close the file (we read it only, so no error check) */
+    fclose (Obj);
+}
+
+
+
diff --git a/src/ld65/objfile.h b/src/ld65/objfile.h
new file mode 100644 (file)
index 0000000..f2046bb
--- /dev/null
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                objfile.h                                 */
+/*                                                                           */
+/*                Object file handling for the ld65 linker                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include <stdio.h>
+
+#include "../common/objdefs.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void ObjReadFiles (FILE* F, ObjData* O);
+/* Read the files list from a file at the current position */
+
+void ObjReadImports (FILE* F, ObjData* O);
+/* Read the imports from a file at the current position */
+
+void ObjReadExports (FILE* F, ObjData* O);
+/* Read the exports from a file at the current position */
+
+void ObjReadDbgSyms (FILE* F, ObjData* O);
+/* Read the debug symbols from a file at the current position */
+
+void ObjReadSections (FILE* F, ObjData* O);
+/* Read the section data from a file at the current position */
+
+void ObjAdd (FILE* F, const char* Name);
+/* Add an object file to the module list */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
diff --git a/src/ld65/scanner.c b/src/ld65/scanner.c
new file mode 100644 (file)
index 0000000..69db9f2
--- /dev/null
@@ -0,0 +1,535 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                scanner.c                                 */
+/*                                                                           */
+/*             Configuration file scanner for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "error.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Current token and attributes */
+unsigned        CfgTok;
+char                   CfgSVal [CFG_MAX_IDENT_LEN+1];
+unsigned long   CfgIVal;
+
+/* Error location */
+unsigned               CfgErrorLine;
+unsigned               CfgErrorCol;
+
+/* Input sources for the configuration */
+static const char*             CfgName         = 0;
+static const char*      CfgBuf                 = 0;
+
+/* Other input stuff */
+static int                     C               = ' ';
+static unsigned                InputLine       = 1;
+static unsigned                InputCol        = 0;
+static FILE*                   InputFile       = 0;
+
+
+
+/*****************************************************************************/
+/*                             Error handling                               */
+/*****************************************************************************/
+
+
+
+void CfgWarning (const char* Format, ...)
+/* Print a warning message adding file name and line number of the config file */
+{
+    char Buf [512];
+    va_list ap;
+    va_start (ap, Format);
+#ifdef __WATCOMC__
+    _vbprintf (Buf, sizeof (Buf), Format, ap);
+#else
+    vsnprintf (Buf, sizeof (Buf), Format, ap);
+#endif
+    Warning ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
+}
+
+
+
+void CfgError (const char* Format, ...)
+/* Print an error message adding file name and line number of the config file */
+{
+    char Buf [512];
+    va_list ap;
+    va_start (ap, Format);
+#ifdef __WATCOMC__
+    _vbprintf (Buf, sizeof (Buf), Format, ap);
+#else
+    vsnprintf (Buf, sizeof (Buf), Format, ap);
+#endif
+    Error ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
+}
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static void NextChar (void)
+/* Read the next character from the input file */
+{
+    if (CfgBuf) {
+       /* Read from buffer */
+       C = (unsigned char)(*CfgBuf);
+       if (C == 0) {
+           C = EOF;
+       } else {
+           ++CfgBuf;
+       }
+    } else {
+       /* Read from the file */
+       C = getc (InputFile);
+    }
+
+    /* Count columns */
+    if (C != EOF) {
+       ++InputCol;
+    }
+
+    /* Count lines */
+    if (C == '\n') {
+       ++InputLine;
+       InputCol = 0;
+    }
+}
+
+
+
+static unsigned DigitVal (int C)
+/* Return the value for a numeric digit */
+{
+    if (isdigit (C)) {
+       return C - '0';
+    } else {
+       return toupper (C) - 'A' + 10;
+    }
+}
+
+
+
+void CfgNextTok (void)
+/* Read the next token from the input stream */
+{
+    unsigned I;
+
+
+Again:
+    /* Skip whitespace */
+    while (isspace (C)) {
+       NextChar ();
+    }
+
+    /* Remember the current position */
+    CfgErrorLine = InputLine;
+    CfgErrorCol  = InputCol;
+
+    /* Identifier? */
+    if (C == '_' || isalpha (C)) {
+
+       /* Read the identifier */
+       I = 0;
+       while (C == '_' || isalnum (C)) {
+           if (I < CFG_MAX_IDENT_LEN) {
+               CfgSVal [I++] = C;
+           }
+           NextChar ();
+       }
+       CfgSVal [I] = '\0';
+       CfgTok = CFGTOK_IDENT;
+       return;
+    }
+
+    /* Hex number? */
+    if (C == '$') {
+       NextChar ();
+       if (!isxdigit (C)) {
+           Error ("%s(%u): Hex digit expected", CfgName, InputLine);
+       }
+       CfgIVal = 0;
+       while (isxdigit (C)) {
+                   CfgIVal = CfgIVal * 16 + DigitVal (C);
+           NextChar ();
+       }
+       CfgTok = CFGTOK_INTCON;
+       return;
+    }
+
+    /* Decimal number? */
+    if (isdigit (C)) {
+       CfgIVal = 0;
+       while (isdigit (C)) {
+                   CfgIVal = CfgIVal * 10 + DigitVal (C);
+           NextChar ();
+       }
+       CfgTok = CFGTOK_INTCON;
+       return;
+    }
+
+    /* Other characters */
+    switch (C) {
+
+       case '{':
+           NextChar ();
+           CfgTok = CFGTOK_LCURLY;
+           break;
+
+       case '}':
+           NextChar ();
+           CfgTok = CFGTOK_RCURLY;
+           break;
+
+       case ';':
+           NextChar ();
+           CfgTok = CFGTOK_SEMI;
+           break;
+
+       case '.':
+           NextChar ();
+           CfgTok = CFGTOK_DOT;
+           break;
+
+       case ',':
+           NextChar ();
+           CfgTok = CFGTOK_COMMA;
+           break;
+
+       case '=':
+           NextChar ();
+           CfgTok = CFGTOK_EQ;
+           break;
+
+        case ':':
+           NextChar ();
+           CfgTok = CFGTOK_COLON;
+           break;
+
+        case '\"':
+           NextChar ();
+           I = 0;
+           while (C != '\"') {
+               if (C == EOF || C == '\n') {
+                   Error ("%s(%u): Unterminated string", CfgName, InputLine);
+               }
+               if (I < CFG_MAX_IDENT_LEN) {
+                   CfgSVal [I++] = C;
+               }
+               NextChar ();
+           }
+                   NextChar ();
+           CfgSVal [I] = '\0';
+           CfgTok = CFGTOK_STRCON;
+           break;
+
+        case '#':
+           /* Comment */
+           while (C != '\n' && C != EOF) {
+               NextChar ();
+           }
+           if (C != EOF) {
+               goto Again;
+           }
+           CfgTok = CFGTOK_EOF;
+           break;
+
+        case '%':
+           NextChar ();
+           switch (C) {
+
+               case 'O':
+                   NextChar ();
+                   if (OutputName) {
+                       strncpy (CfgSVal, OutputName, CFG_MAX_IDENT_LEN);
+                       CfgSVal [CFG_MAX_IDENT_LEN] = '\0';
+                   } else {
+                       CfgSVal [0] = '\0';
+                   }
+                   CfgTok = CFGTOK_STRCON;
+                   break;
+
+               case 'S':
+                   NextChar ();
+                   CfgIVal = StartAddr;
+                   CfgTok = CFGTOK_INTCON;
+                   break;
+
+               default:
+                   CfgError ("Invalid format specification");
+           }
+           break;
+
+        case EOF:
+           CfgTok = CFGTOK_EOF;
+           break;
+
+       default:
+           Error ("%s(%u): Invalid character `%c'", CfgName, InputLine, C);
+
+    }
+}
+
+
+
+void CfgConsume (unsigned T, const char* Msg)
+/* Skip a token, print an error message if not found */
+{
+    if (CfgTok != T) {
+               CfgError (Msg);
+    }
+    CfgNextTok ();
+}
+
+
+
+void CfgConsumeSemi (void)
+/* Consume a semicolon */
+{
+    CfgConsume (CFGTOK_SEMI, "`;' expected");
+}
+
+
+
+void CfgConsumeColon (void)
+/* Consume a colon */
+{
+    CfgConsume (CFGTOK_COLON, "`:' expected");
+}
+
+
+
+void CfgOptionalComma (void)
+/* Consume a comma if there is one */
+{
+    if (CfgTok == CFGTOK_COMMA) {
+               CfgNextTok ();
+    }
+}
+
+
+
+void CfgOptionalAssign (void)
+/* Consume an equal sign if there is one */
+{
+    if (CfgTok == CFGTOK_EQ) {
+               CfgNextTok ();
+    }
+}
+
+
+
+void CfgAssureInt (void)
+/* Make sure the next token is an integer */
+{
+    if (CfgTok != CFGTOK_INTCON) {
+               CfgError ("Integer constant expected");
+    }
+}
+
+
+
+void CfgAssureStr (void)
+/* Make sure the next token is a string constant */
+{
+    if (CfgTok != CFGTOK_STRCON) {
+               CfgError ("String constant expected");
+    }
+}
+
+
+
+void CfgAssureIdent (void)
+/* Make sure the next token is an identifier */
+{
+    if (CfgTok != CFGTOK_IDENT) {
+               CfgError ("Identifier expected");
+    }
+}
+
+
+
+void CfgRangeCheck (unsigned long Lo, unsigned long Hi)
+/* Check the range of CfgIVal */
+{
+    if (CfgIVal < Lo || CfgIVal > Hi) {
+       CfgError ("Range error");
+    }
+}
+
+
+
+void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
+/* Map an identifier to one of the special tokens in the table */
+{
+    unsigned I;
+
+    /* We need an identifier */
+    if (CfgTok == CFGTOK_IDENT) {
+
+       /* Make it upper case */
+       I = 0;
+       while (CfgSVal [I]) {
+           CfgSVal [I] = toupper (CfgSVal [I]);
+           ++I;
+       }
+
+               /* Linear search */
+       for (I = 0; I < Size; ++I) {
+           if (strcmp (CfgSVal, Table [I].Ident) == 0) {
+               CfgTok = Table [I].Tok;
+               return;
+           }
+       }
+
+    }
+
+    /* Not found or no identifier */
+    Error ("%s(%u): %s expected", CfgName, InputLine, Name);
+}
+
+
+
+void CfgBoolToken (void)
+/* Map an identifier or integer to a boolean token */
+{
+    static const IdentTok Booleans [] = {
+               {   "YES",      CFGTOK_TRUE     },
+       {   "NO",       CFGTOK_FALSE    },
+        {   "TRUE",     CFGTOK_TRUE     },
+        {   "FALSE",    CFGTOK_FALSE    },
+    };
+
+    /* If we have an identifier, map it to a boolean token */
+    if (CfgTok == CFGTOK_IDENT) {
+       CfgSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
+    } else {
+       /* We expected an integer here */
+       if (CfgTok != CFGTOK_INTCON) {
+           CfgError ("Boolean value expected");
+       }
+       CfgTok = (CfgIVal == 0)? CFGTOK_FALSE : CFGTOK_TRUE;
+    }
+}
+
+
+
+void CfgSetName (const char* Name)
+/* Set a name for a config file */
+{
+    CfgName = Name;
+}
+
+
+
+const char* CfgGetName (void)
+/* Get the name of the config file */
+{
+    return CfgName? CfgName : "";
+}
+
+
+
+void CfgSetBuf (const char* Buf)
+/* Set a memory buffer for the config */
+{
+    CfgBuf = Buf;
+}
+
+
+
+int CfgAvail (void)
+/* Return true if we have a configuration available */
+{
+    return CfgName != 0 || CfgBuf != 0;
+}
+
+
+
+void CfgOpenInput (void)
+/* Open the input file if we have one */
+{
+    /* If we have a config name given, open the file, otherwise we will read
+     * from a buffer.
+     */
+    if (!CfgBuf) {
+
+       /* Open the file */
+       InputFile = fopen (CfgName, "r");
+       if (InputFile == 0) {
+           Error ("Cannot open `%s': %s", CfgName, strerror (errno));
+       }
+
+    }
+
+    /* Initialize variables */
+    C         = ' ';
+    InputLine = 1;
+    InputCol  = 0;
+
+    /* Start the ball rolling ... */
+    CfgNextTok ();
+}
+
+
+
+void CfgCloseInput (void)
+/* Close the input file if we have one */
+{
+    /* Close the input file if we had one */
+    if (InputFile) {
+        (void) fclose (InputFile);
+       InputFile = 0;
+    }
+}
+
+
+
diff --git a/src/ld65/scanner.h b/src/ld65/scanner.h
new file mode 100644 (file)
index 0000000..2c0a5ac
--- /dev/null
@@ -0,0 +1,198 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                scanner.h                                 */
+/*                                                                           */
+/*             Configuration file scanner for the ld65 linker               */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998     Ullrich von Bassewitz                                        */
+/*              Wacholderweg 14                                              */
+/*              D-70597 Stuttgart                                            */
+/* EMail:       uz@musoftware.de                                             */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Config file tokens */
+#define        CFGTOK_NONE             0
+#define CFGTOK_INTCON          1
+#define CFGTOK_STRCON          2
+#define CFGTOK_IDENT           3
+#define CFGTOK_LCURLY          4
+#define CFGTOK_RCURLY          5
+#define CFGTOK_SEMI            6
+#define CFGTOK_COMMA           7
+#define CFGTOK_EQ              8
+#define CFGTOK_COLON           9
+#define CFGTOK_DOT             10
+#define CFGTOK_EOF             11
+
+/* Special identifiers */
+#define CFGTOK_MEMORY                  20
+#define CFGTOK_FILES           21
+#define CFGTOK_SEGMENTS        22
+#define CFGTOK_FORMATS         23
+
+#define CFGTOK_START           30
+#define CFGTOK_SIZE            31
+#define CFGTOK_TYPE            32
+#define CFGTOK_FILE            33
+#define CFGTOK_DEFINE          34
+#define CFGTOK_FILL            35
+#define CFGTOK_FILLVAL         36
+#define CFGTOK_EXPORT          37
+#define CFGTOK_IMPORT          38
+#define CFGTOK_OS                      39
+#define CFGTOK_FORMAT          40
+
+#define CFGTOK_LOAD            50
+#define CFGTOK_RUN                     51
+#define CFGTOK_ALIGN                   52
+#define CFGTOK_OFFSET                  53
+
+#define CFGTOK_RO                      60
+#define CFGTOK_RW                      61
+#define CFGTOK_BSS                     62
+#define CFGTOK_ZP              63
+#define CFGTOK_WPROT           64
+
+#define CFGTOK_O65                     70
+#define CFGTOK_BIN                     71
+
+#define CFGTOK_SMALL           80
+#define CFGTOK_LARGE           81
+
+#define CFGTOK_TRUE            90
+#define CFGTOK_FALSE           91
+
+#define CFGTOK_LUNIX           100
+#define CFGTOK_OSA65           101
+
+
+
+/* Mapping table entry, special identifier --> token */
+typedef struct IdentTok_ IdentTok;
+struct IdentTok_ {
+    const char*                Ident;          /* Identifier */
+    unsigned           Tok;            /* Token for identifier */
+};
+#define ENTRY_COUNT(s)         (sizeof (s) / sizeof (s [0]))
+
+
+
+/* Current token and attributes */
+#define CFG_MAX_IDENT_LEN  255
+extern unsigned                CfgTok;
+extern char                    CfgSVal [CFG_MAX_IDENT_LEN+1];
+extern unsigned long   CfgIVal;
+
+/* Error location */
+extern unsigned                CfgErrorLine;
+extern unsigned                CfgErrorCol;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void CfgWarning (const char* Format, ...);
+/* Print a warning message adding file name and line number of the config file */
+
+void CfgError (const char* Format, ...);
+/* Print an error message adding file name and line number of the config file */
+
+void CfgNextTok (void);
+/* Read the next token from the input stream */
+
+void CfgConsume (unsigned T, const char* Msg);
+/* Skip a token, print an error message if not found */
+
+void CfgConsumeSemi (void);
+/* Consume a semicolon */
+
+void CfgConsumeColon (void);
+/* Consume a colon */
+
+void CfgOptionalComma (void);
+/* Consume a comma if there is one */
+
+void CfgOptionalAssign (void);
+/* Consume an equal sign if there is one */
+
+void CfgAssureInt (void);
+/* Make sure the next token is an integer */
+
+void CfgAssureStr (void);
+/* Make sure the next token is a string constant */
+
+void CfgAssureIdent (void);
+/* Make sure the next token is an identifier */
+
+void CfgRangeCheck (unsigned long Lo, unsigned long Hi);
+/* Check the range of CfgIVal */
+
+void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name);
+/* Map an identifier to one of the special tokens in the table */
+
+void CfgBoolToken (void);
+/* Map an identifier or integer to a boolean token */
+
+void CfgSetName (const char* Name);
+/* Set a name for a config file */
+
+const char* CfgGetName (void);
+/* Get the name of the config file */
+
+void CfgSetBuf (const char* Buf);
+/* Set a memory buffer for the config */
+
+int CfgAvail (void);
+/* Return true if we have a configuration available */
+
+void CfgOpenInput (void);
+/* Open the input file if we have one */
+
+void CfgCloseInput (void);
+/* Close the input file if we have one */
+
+
+
+/* End of scanner.h */
+#endif
+
+
+
diff --git a/src/ld65/segments.c b/src/ld65/segments.c
new file mode 100644 (file)
index 0000000..94a3149
--- /dev/null
@@ -0,0 +1,666 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               segments.c                                 */
+/*                                                                           */
+/*                  Segment handling for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/exprdefs.h"
+#include "../common/symdefs.h"
+#include "../common/segdefs.h"
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "global.h"
+#include "error.h"
+#include "fileio.h"
+#include "expr.h"
+#include "segments.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Fragment structure */
+typedef struct Fragment_ Fragment;
+struct Fragment_ {
+    Fragment*          Next;           /* Next fragment in list */
+    ObjData*           Obj;            /* Source of fragment */
+    unsigned long              Size;           /* Size of data/expression */
+    ExprNode*                  Expr;           /* Expression if FRAG_EXPR */
+    FilePos            Pos;            /* File position in source */
+    unsigned char      Type;           /* Type of fragment */
+    unsigned char              LitBuf [1];     /* Dynamically alloc'ed literal buffer */
+};
+
+
+
+/* Hash table */
+#define HASHTAB_SIZE   253
+static Segment*                HashTab [HASHTAB_SIZE];
+
+static unsigned                SegCount = 0;   /* Segment count */
+static Segment*                SegRoot = 0;    /* List of all segments */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static Fragment* NewFragment (unsigned char Type, unsigned long Size, Section* S)
+/* Create a new fragment and insert it into the segment S */
+{
+    /* Allocate memory */
+    Fragment* F = Xmalloc (sizeof (Fragment) - 1 + Size);      /* Portable? */
+
+    /* Initialize the data */
+    F->Next = 0;
+    F->Obj  = 0;
+    F->Size = Size;
+    F->Expr = 0;
+    F->Type = Type;
+
+    /* Insert the code fragment into the segment */
+    if (S->FragRoot == 0) {
+       /* First fragment */
+       S->FragRoot = F;
+    } else {
+       S->FragLast->Next = F;
+    }
+    S->FragLast = F;
+    S->Size += Size;
+
+    /* Return the new fragment */
+    return F;
+}
+
+
+
+static Segment* NewSegment (const char* Name, unsigned char Type)
+/* Create a new segment and initialize it */
+{
+    /* Get the length of the symbol name */
+    unsigned Len = strlen (Name);
+
+    /* Allocate memory */
+    Segment* S = Xmalloc (sizeof (Segment) + Len);
+
+    /* Initialize the fields */
+    S->Next    = 0;
+    S->SecRoot = 0;
+    S->SecLast = 0;
+    S->PC      = 0;
+    S->Size            = 0;
+    S->AlignObj        = 0;
+    S->Align    = 0;
+    S->FillVal = 0;
+    S->Type     = Type;
+    S->Dumped   = 0;
+    memcpy (S->Name, Name, Len);
+    S->Name [Len] = '\0';
+
+    /* Insert the segment into the segment list */
+    S->List = SegRoot;
+    SegRoot = S;
+    ++SegCount;
+
+    /* Return the new entry */
+    return S;
+}
+
+
+
+static Section* NewSection (Segment* Seg, unsigned char Align, unsigned char Type)
+/* Create a new section for the given segment */
+{
+    unsigned long V;
+
+
+    /* Allocate memory */
+    Section* S = Xmalloc (sizeof (Segment));
+
+    /* Initialize the data */
+    S->Next    = 0;
+    S->Seg     = Seg;
+    S->FragRoot = 0;
+    S->FragLast = 0;
+    S->Size    = 0;
+    S->Align    = Align;
+    S->Type     = Type;
+
+    /* Calculate the alignment bytes needed for the section */
+    V = (0x01UL << S->Align) - 1;
+    S->Fill = ((Seg->Size + V) & ~V) - Seg->Size;
+
+    /* Adjust the segment size and set the section offset */
+    Seg->Size  += S->Fill;
+    S->Offs    = Seg->Size;    /* Current size is offset */
+
+    /* Insert the section into the segment */
+    if (Seg->SecRoot == 0) {
+       /* First section in this segment */
+               Seg->SecRoot = S;
+    } else {
+       Seg->SecLast->Next = S;
+    }
+    Seg->SecLast = S;
+
+    /* Return the struct */
+    return S;
+}
+
+
+
+static Segment* SegFindInternal (const char* Name, unsigned HashVal)
+/* Try to find the segment with the given name, return a pointer to the
+ * segment structure, or 0 if not found.
+ */
+{
+    Segment* S = HashTab [HashVal];
+    while (S) {
+       if (strcmp (Name, S->Name) == 0) {
+           /* Found */
+           break;
+       }
+       S = S->Next;
+    }
+    /* Not found */
+    return S;
+}
+
+
+
+Section* ReadSection (FILE* F, ObjData* O)
+/* Read a section from a file */
+{
+    unsigned HashVal;
+    char Name [256];
+    unsigned long Size;
+    unsigned char Align;
+    unsigned char Type;
+    Segment* S;
+    Section* Sec;
+
+    /* Read the name */
+    ReadStr (F, Name);
+
+    /* Read the size */
+    Size = Read32 (F);
+
+    /* Read the alignment */
+    Align = Read8 (F);
+
+    /* Read the segment type */
+    Type = Read8 (F);
+
+    /* Print some data */
+    if (Verbose > 1) {
+               printf ("Module `%s': Found segment `%s', size = %lu, align = %u, type = %u\n",
+               O->Name, Name, Size, Align, Type);
+    }
+
+    /* Create a hash over the name and try to locate the segment in the table */
+    HashVal = HashStr (Name) % HASHTAB_SIZE;
+    S = SegFindInternal (Name, HashVal);
+
+    /* If we don't have that segment already, allocate it using the type of
+     * the first section.
+     */
+    if (S == 0) {
+       /* Create a new segment and insert it */
+       S = NewSegment (Name, Type);
+       S->Next = HashTab [HashVal];
+       HashTab [HashVal] = S;
+    }
+
+    /* Allocate the section we will return later */
+    Sec = NewSection (S, Align, Type);
+
+    /* Check if the section has the same type as the segment */
+    if (Sec->Type != S->Type) {
+       /* OOPS */
+       Error ("Module `%s': Type mismatch for segment `%s'", O->Name, S->Name);
+    }
+
+    /* Set up the minimum segment alignment */
+    if (Sec->Align > S->Align) {
+       /* Section needs larger alignment, use this one */
+       S->Align    = Sec->Align;
+       S->AlignObj = O;
+    }
+
+    /* Start reading fragments from the file and insert them into the section . */
+    while (Size) {
+
+       Fragment* Frag;
+
+       /* Read the fragment type */
+       unsigned char Type = Read8 (F);
+
+       /* Handle the different fragment types */
+       switch (Type) {
+
+           case FRAG_LITERAL8:
+               Frag = NewFragment (FRAG_LITERAL, Read8 (F), Sec);
+               break;
+
+           case FRAG_LITERAL16:
+               Frag = NewFragment (FRAG_LITERAL, Read16 (F), Sec);
+               break;
+
+           case FRAG_LITERAL24:
+               Frag = NewFragment (FRAG_LITERAL, Read24 (F), Sec);
+               break;
+
+           case FRAG_LITERAL32:
+               Frag = NewFragment (FRAG_LITERAL, Read32 (F), Sec);
+               break;
+
+           case FRAG_EXPR8:
+           case FRAG_EXPR16:
+                   case FRAG_EXPR24:
+           case FRAG_EXPR32:
+           case FRAG_SEXPR8:
+           case FRAG_SEXPR16:
+           case FRAG_SEXPR24:
+           case FRAG_SEXPR32:
+                       Frag = NewFragment (Type & FRAG_TYPEMASK, Type & FRAG_BYTEMASK, Sec);
+               break;
+
+           case FRAG_FILL:
+               /* Will allocate memory, but we don't care... */
+               Frag = NewFragment (FRAG_FILL, Read16 (F), Sec);
+               break;
+
+           default:
+               Error ("Unknown fragment type in module `%s', segment `%s': %02X",
+                      O->Name, S->Name, Type);
+               /* NOTREACHED */
+               return 0;
+               }
+
+       /* Now read the fragment data */
+       switch (Frag->Type) {
+
+           case FRAG_LITERAL:
+               /* Literal data */
+               ReadData (F, Frag->LitBuf, Frag->Size);
+               break;
+
+           case FRAG_EXPR:
+           case FRAG_SEXPR:
+               /* An expression */
+               Frag->Expr = ReadExpr (F, O);
+               break;
+
+       }
+
+       /* Read the file position of the fragment */
+       ReadFilePos (F, &Frag->Pos);
+
+       /* Remember the module we had this fragment from */
+       Frag->Obj = O;
+
+       /* Next one */
+       CHECK (Size >= Frag->Size);
+       Size -= Frag->Size;
+    }
+
+    /* Increment the segment size by the section size */
+    S->Size += Sec->Size;
+
+    /* Return the section */
+    return Sec;
+}
+
+
+
+Segment* SegFind (const char* Name)
+/* Return the given segment or NULL if not found. */
+{
+    return SegFindInternal (Name, HashStr (Name) % HASHTAB_SIZE);
+}
+
+
+
+int IsBSSType (Segment* S)
+/* Check if the given segment is a BSS style segment, that is, it does not
+ * contain non-zero data.
+ */
+{
+    /* Loop over all sections */
+    Section* Sec = S->SecRoot;
+    while (Sec) {
+       /* Loop over all fragments */
+       Fragment* F = Sec->FragRoot;
+       while (F) {
+           if (F->Type == FRAG_LITERAL) {
+               unsigned char* Data = F->LitBuf;
+               unsigned long Count = F->Size;
+               while (Count--) {
+                   if (*Data++ != 0) {
+                       return 0;
+                   }
+               }
+           } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+               if (GetExprVal (F->Expr) != 0) {
+                   return 0;
+               }
+           }
+           F = F->Next;
+       }
+       Sec = Sec->Next;
+    }
+    return 1;
+}
+
+
+
+void SegDump (void)
+/* Dump the segments and it's contents */
+{
+    unsigned I;
+    unsigned long Count;
+    unsigned char* Data;
+
+    Segment* Seg = SegRoot;
+    while (Seg) {
+       Section* S = Seg->SecRoot;
+               printf ("Segment: %s (%lu)\n", Seg->Name, Seg->Size);
+       while (S) {
+           Fragment* F = S->FragRoot;
+           printf ("  Section:\n");
+           while (F) {
+               switch (F->Type) {
+
+                   case FRAG_LITERAL:
+                       printf ("    Literal (%lu bytes):", F->Size);
+                       Count = F->Size;
+                       Data  = F->LitBuf;
+                       I = 100;
+                       while (Count--) {
+                           if (I > 75) {
+                               printf ("\n   ");
+                               I = 3;
+                           }
+                           printf (" %02X", *Data++);
+                           I += 3;
+                       }
+                       printf ("\n");
+                       break;
+
+                   case FRAG_EXPR:
+                       printf ("    Expression (%lu bytes):\n", F->Size);
+                       printf ("    ");
+                       DumpExpr (F->Expr);
+                       break;
+
+                   case FRAG_SEXPR:
+                       printf ("    Signed expression (%lu bytes):\n", F->Size);
+                       printf ("      ");
+                       DumpExpr (F->Expr);
+                       break;
+
+                   case FRAG_FILL:
+                       printf ("    Empty space (%lu bytes)\n", F->Size);
+                       break;
+
+                   default:
+                       Internal ("Invalid fragment type: %02X", F->Type);
+               }
+               F = F->Next;
+           }
+           S = S->Next;
+       }
+       Seg = Seg->List;
+    }
+}
+
+
+
+unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
+/* Write a supposedly constant expression to the target file. Do a range
+ * check and return one of the SEG_EXPR_xxx codes.
+ */
+{
+    static const unsigned long U_HighRange [4] = {
+               0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF
+    };
+    static const long S_HighRange [4] = {
+               0x0000007F, 0x00007FFF, 0x007FFFFF, 0x7FFFFFFF
+    };
+    static const long S_LowRange [4] = {
+               0xFFFFFF80, 0xFFFF8000, 0xFF800000, 0x80000000
+    };
+
+
+    /* Get the expression value */
+    long Val = GetExprVal (E);
+
+    /* Check the size */
+    CHECK (Size >= 1 && Size <= 4);
+
+    /* Check for a range error */
+    if (Signed) {
+       if (Val > S_HighRange [Size-1] || Val < S_LowRange [Size-1]) {
+           /* Range error */
+           return SEG_EXPR_RANGE_ERROR;
+       }
+    } else {
+       if (((unsigned long)Val) > U_HighRange [Size-1]) {
+           /* Range error */
+           return SEG_EXPR_RANGE_ERROR;
+       }
+    }
+
+    /* Write the value to the file */
+    WriteVal (F, Val, Size);
+
+    /* Success */
+    return SEG_EXPR_OK;
+}
+
+
+
+void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
+/* Write the data from the given segment to a file. For expressions, F is
+ * called (see description of SegWriteFunc above).
+ */
+{
+    int Sign;
+    unsigned long Offs = 0;
+
+    /* Loop over all sections in this segment */
+    Section* Sec = S->SecRoot;
+    while (Sec) {
+       Fragment* Frag;
+
+       /* If we have fill bytes, write them now */
+       WriteMult (Tgt, S->FillVal, Sec->Fill);
+
+       /* Loop over all fragments in this section */
+       Frag = Sec->FragRoot;
+       while (Frag) {
+
+           switch (Frag->Type) {
+
+               case FRAG_LITERAL:
+                   WriteData (Tgt, Frag->LitBuf, Frag->Size);
+                   break;
+
+               case FRAG_EXPR:
+               case FRAG_SEXPR:
+                   Sign = (Frag->Type == FRAG_SEXPR);
+                   /* Call the users function and evaluate the result */
+                   switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {
+
+                       case SEG_EXPR_OK:
+                           break;
+
+                       case SEG_EXPR_RANGE_ERROR:
+                           Error ("Range error in module `%s', line %lu",
+                                  Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
+                           break;
+
+                       case SEG_EXPR_TOO_COMPLEX:
+                           Error ("Expression too complex in module `%s', line %lu",
+                                  Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
+                           break;
+
+                       default:
+                           Internal ("Invalid return code from SegWriteFunc");
+                   }
+                   break;
+
+               case FRAG_FILL:
+                   WriteMult (Tgt, S->FillVal, Frag->Size);
+                   break;
+
+               default:
+                   Internal ("Invalid fragment type: %02X", Frag->Type);
+           }
+
+           /* Update the offset */
+           Offs += Frag->Size;
+
+           /* Next fragment */
+           Frag = Frag->Next;
+       }
+
+       /* Next section */
+       Sec = Sec->Next;
+    }
+}
+
+
+
+static int CmpSegStart (const void* K1, const void* K2)
+/* Compare function for qsort */
+{
+    /* Get the real segment pointers */
+    const Segment* S1 = *(const Segment**)K1;
+    const Segment* S2 = *(const Segment**)K2;
+
+    /* Compare the start addresses */
+    if (S1->PC > S2->PC) {
+       return 1;
+    } else if (S1->PC < S2->PC) {
+       return -1;
+    } else {
+       /* Sort segments with equal starts by name */
+       return strcmp (S1->Name, S2->Name);
+    }
+}
+
+
+
+void PrintSegmentMap (FILE* F)
+/* Print a segment map to the given file */
+{
+    unsigned I;
+    Segment* S;
+    Segment** SegPool;
+
+    /* Allocate memory for the segment pool */
+    SegPool = Xmalloc (SegCount * sizeof (Segment*));
+
+    /* Collect pointers to the segments */
+    I = 0;
+    S = SegRoot;
+    while (S) {
+
+       /* Check the count for safety */
+       CHECK (I < SegCount);
+
+       /* Remember the pointer */
+       SegPool [I] = S;
+
+       /* Follow the linked list */
+       S = S->List;
+
+       /* Next array index */
+       ++I;
+    }
+    CHECK (I == SegCount);
+
+    /* Sort the array by increasing start addresses */
+    qsort (SegPool, SegCount, sizeof (Segment*), CmpSegStart);
+
+    /* Print a header */
+    fprintf (F, "Name                  Start   End     Size\n"
+               "--------------------------------------------\n");
+
+    /* Print the segments */
+    for (I = 0; I < SegCount; ++I) {
+
+       /* Get a pointer to the segment */
+       S = SegPool [I];
+
+       /* Print empty segments only if explicitly requested */
+       if (VerboseMap || S->Size > 0) {
+           /* Print the segment data */
+           fprintf (F, "%-20s  %06lX  %06lX  %06lX\n",
+                    S->Name, S->PC, S->PC + S->Size, S->Size);
+       }
+    }
+
+    /* Free the segment pool */
+    Xfree (SegPool);
+}
+
+
+
+void CheckSegments (void)
+/* Walk through the segment list and check if there are segments that were
+ * not written to the output file. Output an error if this is the case.
+ */
+{
+    Segment* S = SegRoot;
+    while (S) {
+       if (S->Size > 0 && S->Dumped == 0) {
+                   Error ("Missing memory area assignment for segment `%s'", S->Name);
+       }
+       S = S->List;
+    }
+}
+
+
+
diff --git a/src/ld65/segments.h b/src/ld65/segments.h
new file mode 100644 (file)
index 0000000..f69e9c2
--- /dev/null
@@ -0,0 +1,152 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                               segments.h                                 */
+/*                                                                           */
+/*                  Segment handling for the ld65 linker                    */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SEGMENTS_H
+#define SEGMENTS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Forward for the section structure (a section is a part of a segment) */
+typedef struct Section_ Section;
+
+/* Segment structure */
+typedef struct Segment_ Segment;
+struct Segment_ {
+    Segment*           Next;           /* Hash list */
+    Segment*           List;           /* List of all segments */
+    Section*           SecRoot;        /* Section list */
+    Section*           SecLast;        /* Pointer to last section */
+    unsigned long      PC;             /* PC were this segment is located */
+    unsigned long      Size;           /* Size of data so far */
+    ObjData*           AlignObj;       /* Module that requested the alignment */
+    unsigned char      Align;          /* Alignment needed */
+    unsigned char      FillVal;        /* Value to use for fill bytes */
+    unsigned char      Type;           /* Type of segment */
+    char               Dumped;         /* Did we dump this segment? */
+    char                       Name [1];       /* Name, dynamically allocated */
+};
+
+
+
+/* Section structure (a section is a part of a segment) */
+struct Section_ {
+    Section*           Next;           /* List of sections in a segment */
+    Segment*           Seg;            /* Segment that contains the section */
+    struct Fragment_*  FragRoot;       /* Fragment list */
+    struct Fragment_*  FragLast;       /* Pointer to last fragment */
+    unsigned long      Offs;           /* Offset into the segment */
+    unsigned long      Size;           /* Size of the section */
+    unsigned char      Align;          /* Alignment */
+    unsigned char      Fill;           /* Fill bytes for alignment */
+    unsigned char      Type;           /* Type of segment */
+};
+
+
+
+/* Prototype for a function that is used to write expressions to the target
+ * file (used in SegWrite). It returns one of the following values:
+ */
+#define SEG_EXPR_OK            0       /* Ok */
+#define SEG_EXPR_RANGE_ERROR   1       /* Range error */
+#define SEG_EXPR_TOO_COMPLEX   2       /* Expression too complex */
+
+typedef unsigned (*SegWriteFunc) (ExprNode* E,               /* The expression to write */
+                                 int Signed,         /* Signed expression? */
+                                 unsigned Size,      /* Size (=range) */
+                                 unsigned long Offs, /* File offset */
+                                 void* Data);        /* Callers data */
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+Section* ReadSection (FILE* F, ObjData* O);
+/* Read a section from a file */
+
+Segment* SegFind (const char* Name);
+/* Return the given segment or NULL if not found. */
+
+int IsBSSType (Segment* S);
+/* Check if the given segment is a BSS style segment, that is, it does not
+ * contain non-zero data.
+ */
+
+void SegDump (void);
+/* Dump the segments and it's contents */
+
+unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size);
+/* Write a supposedly constant expression to the target file. Do a range
+ * check and return one of the SEG_EXPR_xxx codes.
+ */
+
+void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data);
+/* Write the data from the given segment to a file. For expressions, F is
+ * called (see description of SegWriteFunc above).
+ */
+
+void PrintSegmentMap (FILE* F);
+/* Print a segment map to the given file */
+
+void CheckSegments (void);
+/* Walk through the segment list and check if there are segments that were
+ * not written to the output file. Output an error if this is the case.
+ */
+
+
+
+/* End of segments.h */
+
+#endif
+
+
+
diff --git a/src/ld65/target.c b/src/ld65/target.c
new file mode 100644 (file)
index 0000000..a97fe32
--- /dev/null
@@ -0,0 +1,351 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                              target.c                                    */
+/*                                                                           */
+/*                Target system support for the ld65 linker                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "error.h"
+#include "global.h"
+#include "binfmt.h"
+#include "scanner.h"
+#include "config.h"
+#include "target.h"
+
+
+
+/*****************************************************************************/
+/*                          Target configurations                           */
+/*****************************************************************************/
+
+
+
+static const char CfgNone [] =
+    "MEMORY {"
+       "RAM: start = %S, size = $10000, file = %O;"
+    "}"
+    "SEGMENTS {"
+        "CODE: load = RAM, type = rw;"
+       "RODATA: load = RAM, type = rw;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgAtari [] =
+    "MEMORY {"
+        "HEADER: start = $0000, size = $6, file = %O;"
+        "RAM: start = $1F00, size = $6100, file = %O;"
+    "}"
+    "SEGMENTS {"
+        "EXEHDR: load = HEADER, type = wprot;"
+        "CODE: load = RAM, type = wprot, define = yes;"
+        "RODATA: load = RAM, type = wprot;"
+        "DATA: load = RAM, type = rw;"
+        "BSS: load = RAM, type = bss, define = yes;"
+        "AUTOSTRT: load = RAM, type = wprot;"
+    "}";
+
+static const char CfgC64 [] =
+    "MEMORY {"
+       "RAM: start = $7FF, size = $c801, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = RAM, type = wprot;"
+       "RODATA: load = RAM, type = wprot;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgC128 [] =
+    "MEMORY {"
+       "RAM: start = $1bff, size = $a401, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = RAM, type = wprot;"
+       "RODATA: load = RAM, type = wprot;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgAce [] =
+    "";
+
+static const char CfgPlus4 [] =
+    "MEMORY {"
+       "RAM: start = $0fff, size = $7001, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = RAM, type = wprot;"
+       "RODATA: load = RAM, type = wprot;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgCBM610 [] =
+    "MEMORY {"
+       "RAM: start = $0001, size = $FFF0, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = RAM, type = wprot;"
+       "RODATA: load = RAM, type = wprot;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgPET [] =
+    "MEMORY {"
+       "RAM: start = $03FF, size = $7BFF, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = RAM, type = wprot;"
+       "RODATA: load = RAM, type = wprot;"
+       "DATA: load = RAM, type = rw;"
+       "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgNES [] =
+    "MEMORY {"
+       "RAM: start = $0200, size = $0600, file = \"\";"
+               "ROM: start = $8000, size = $8000, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = ROM, type = ro;"
+       "RODATA: load = ROM, type = ro;"
+       "DATA: load = ROM, run = RAM, type = rw, define = yes;"
+       "BSS: load = RAM, type = bss, define = yes;"
+       "VECTORS: load = ROM, type = ro, start = $FFFA;"
+    "}";
+
+static const char CfgLunix [] =
+    "MEMORY {"
+       "COMBINED: start = $0000, size = $FFFF, file = %O;"
+       "ZEROPAGE: start = $0000, size = $0100, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = COMBINED, type = wprot;"
+       "RODATA: load = COMBINED, type = wprot;"
+       "DATA: load = COMBINED, type = rw, define = yes;"
+       "BSS: load = COMBINED, type = bss, define = yes;"
+       "ZEROPAGE: load = ZEROPAGE, type = zp;"
+    "}"
+    "FILES {"
+               "%O: format = o65;"
+    "}"
+    "FORMATS {"
+               "o65: os = lunix, type = small,"
+                     "extsym = \"LUNIXKERNAL\", extsym = \"LIB6502\";"
+    "}";
+
+static const char CfgOSA65 [] =
+    "MEMORY {"
+               "COMBINED: start = $0000, size = $FFFF, file = %O;"
+       "ZEROPAGE: start = $0000, size = $0100, file = %O;"
+    "}"
+    "SEGMENTS {"
+               "CODE: load = COMBINED, type = wprot;"
+               "RODATA: load = COMBINED, type = wprot;"
+               "DATA: load = COMBINED, type = rw, define = yes;"
+               "BSS: load = COMBINED, type = bss, define = yes;"
+       "ZEROPAGE: load = ZEROPAGE, type = zp;"
+    "}"
+    "FILES {"
+       "%O: format = o65;"
+    "}"
+    "FORMATS {"
+       "o65: os = osa65, type = small,"
+             "extsym = \"OSA2KERNAL\", extsym = \"LIB6502\";"
+    "}";
+
+static const char CfgApple2 [] =
+    "MEMORY {"
+       "RAM: start = $800, size = $8E00, file = %O;"
+    "}"
+    "SEGMENTS { "
+        "CODE: load = RAM, type = ro;"
+        "RODATA: load = RAM, type = ro;"
+        "DATA: load = RAM, type = rw;"
+        "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+static const char CfgGeos [] =
+    "MEMORY {"
+       "HEADER: start = $204, size = 508, file = %O;"
+               "RAM: start = $400, size = $7C00, file = %O;"
+    "}"
+    "SEGMENTS { "
+       "HEADER: load = HEADER, type = ro;"
+        "CODE: load = RAM, type = ro;"
+        "RODATA: load = RAM, type = ro;"
+        "DATA: load = RAM, type = rw;"
+        "BSS: load = RAM, type = bss, define = yes;"
+    "}";
+
+
+
+/*****************************************************************************/
+/*                                          Data                                    */
+/*****************************************************************************/
+
+
+
+/* Supported systems */
+#define TGT_NONE        0
+#define TGT_ATARI       1              /* Atari 8 bit machines */
+#define TGT_C64                 2
+#define TGT_C128        3
+#define TGT_ACE                 4
+#define TGT_PLUS4       5
+#define TGT_CBM610      6              /* CBM 600/700 family */
+#define TGT_PET                 7              /* CBM PET family */
+#define TGT_NES                 8              /* Nintendo Entertainment System */
+#define TGT_LUNIX       9
+#define TGT_OSA65      10
+#define TGT_APPLE2     11
+#define TGT_GEOS       12
+#define TGT_COUNT      13              /* Count of supported systems */
+
+
+
+/* Structure describing a target */
+typedef struct TargetCfg_ TargetCfg;
+struct TargetCfg_ {
+    const char*                Name;           /* Name of the system */
+    unsigned char              BinFmt;         /* Default binary format for the target */
+    const char*                Cfg;            /* Pointer to configuration */
+};
+
+static const TargetCfg Targets [TGT_COUNT] = {
+    {          "none",   BINFMT_BINARY,        CfgNone         },
+    {          "atari",  BINFMT_BINARY,        CfgAtari        },
+    {          "c64",    BINFMT_BINARY,        CfgC64          },
+    {          "c128",   BINFMT_BINARY,        CfgC128         },
+    {          "ace",    BINFMT_BINARY,        CfgAce          },
+    {          "plus4",  BINFMT_BINARY,        CfgPlus4        },
+    {          "cbm610", BINFMT_BINARY,        CfgCBM610       },
+    {          "pet",    BINFMT_BINARY,        CfgPET          },
+    {          "nes",    BINFMT_BINARY,        CfgNES          },
+    {   "lunix",  BINFMT_O65,           CfgLunix       },
+    {   "osa65",  BINFMT_O65,          CfgOSA65        },
+    {   "apple2", BINFMT_BINARY,       CfgApple2       },
+    {   "geos",          BINFMT_BINARY,        CfgGeos         },
+};
+
+/* Selected target system type */
+static const TargetCfg* Target;
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+static int StrICmp (const char* S1, const char* S2)
+/* Compare two strings case insensitive */
+{
+    int Diff = 0;
+    while (1) {
+       Diff = tolower (*S1) - tolower (*S2);
+       if (Diff != 0 || *S1 == '\0') {
+           return Diff;
+       }
+       ++S1;
+       ++S2;
+    }
+}
+
+
+
+static int TgtMap (const char* Name)
+/* Map a target name to a system code. Return -1 in case of an error */
+{
+    unsigned I;
+
+    /* Check for a numeric target */
+    if (isdigit (*Name)) {
+       int Target = atoi (Name);
+       if (Target >= 0 && Target < TGT_COUNT) {
+           return Target;
+       }
+    }
+
+    /* Check for a target string */
+    for (I = 0; I < TGT_COUNT; ++I) {
+               if (StrICmp (Targets [I].Name, Name) == 0) {
+           return I;
+       }
+    }
+
+    /* Not found */
+    return -1;
+}
+
+
+
+void TgtSet (const char* T)
+/* Set the target system, initialize internal stuff for this target */
+{
+    /* Map the target to a number */
+    int TgtNum = TgtMap (T);
+    if (TgtNum == -1) {
+       Error ("Invalid target system: %s", T);
+    }
+    Target = &Targets [TgtNum];
+
+    /* Set the target data */
+    DefaultBinFmt = Target->BinFmt;
+    CfgSetBuf (Target->Cfg);
+}
+
+
+
+void TgtPrintList (FILE* F)
+/* Print a list of the available target systems */
+{
+    unsigned I;
+
+    /* Print a header */
+    fprintf (F, "Available targets:\n");
+
+    /* Print a list of the target systems */
+    for (I = 0; I < TGT_COUNT; ++I) {
+       fprintf (F, "  %s\n", Targets [I].Name);
+    }
+}
+
+
+
diff --git a/src/ld65/target.h b/src/ld65/target.h
new file mode 100644 (file)
index 0000000..43cf6ab
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                              target.h                                    */
+/*                                                                           */
+/*                Target system support for the ld65 linker                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2000 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@musoftware.de                                            */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef TARGET_H
+#define TARGET_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/*                                          Code                                    */
+/*****************************************************************************/
+
+
+
+void TgtSet (const char* T);
+/* Set the target system, initialize internal stuff for this target */
+
+void TgtPrintList (FILE* F);
+/* Print a list of the available target systems */
+
+
+
+/* End of target.h */
+
+#endif
+
+
+
diff --git a/src/ld65/version.h b/src/ld65/version.h
new file mode 100644 (file)
index 0000000..7aeac12
--- /dev/null
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+/*                                                                          */
+/*                                version.h                                 */
+/*                                                                          */
+/*                 Version information for the ld65 linker                  */
+/*                                                                          */
+/*                                                                          */
+/*                                                                          */
+/* (C) 1998    Ullrich von Bassewitz                                        */
+/*             Wacholderweg 14                                              */
+/*             D-70597 Stuttgart                                            */
+/* EMail:      uz@musoftware.de                                             */
+/*                                                                          */
+/*                                                                          */
+/* This software is provided 'as-is', without any expressed or implied      */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                   */
+/*                                                                          */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                           */
+/*                                                                          */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                      */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                             */
+/* 3. This notice may not be removed or altered from any source                     */
+/*    distribution.                                                         */
+/*                                                                          */
+/*****************************************************************************/
+
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+
+
+/*****************************************************************************/
+/*                                  Data                                    */
+/*****************************************************************************/
+
+
+
+#define VER_MAJOR      2U
+#define VER_MINOR      4U
+#define VER_PATCH      0U
+
+
+
+/* End of version.h */
+
+#endif
+
+
+
diff --git a/src/make/gcc.mak b/src/make/gcc.mak
new file mode 100644 (file)
index 0000000..0167f90
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# gcc Makefile for the program sources
+#
+
+CFLAGS         = -g -O2 -Wall
+CC     = gcc
+LDFLAGS        =
+
+SUBDIRS        =               \
+       common          \
+       ar65            \
+       ca65            \
+       cc65            \
+       cl65            \
+       ld65
+
+.PHONY: all
+all:
+       for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak all; done
+
+.PHONY: dist
+dist:
+       for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak dist; done
+
+.PHONY: clean
+clean:
+       for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak clean; done
+
+.PHONY: zap
+zap:
+       for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak zap; done
+
diff --git a/src/make/watcom.mak b/src/make/watcom.mak
new file mode 100644 (file)
index 0000000..d9a341a
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# Watcom Makefile for the cc65 binutils
+#
+
+SUBDIRS =              \
+       common          \
+       ar65            \
+       ca65            \
+       ld65
+
+all:
+       cd common
+       make -f make\watcom.mak
+       cd ..\ar65
+       make -f make\watcom.mak
+       cd ..\ca65
+       make -f make\watcom.mak
+       cd ..\ld65
+       make -f make\watcom.mak
+       cd ..
+
+clean:
+       cd common
+       make -f make\watcom.mak clean
+       cd ..\ar65
+       make -f make\watcom.mak clean
+       cd ..\ca65
+       make -f make\watcom.mak clean
+       cd ..\ld65
+       make -f make\watcom.mak clean
+       cd ..
+
+strip:
+       @cd ar65
+       @-make -f make\watcom.mak strip
+       @cd ..\ca65
+       @-make -f make\watcom.mak strip
+       @cd ..\ld65
+       @-make -f make\watcom.mak strip
+       @cd ..
+
+
diff --git a/testcode/compiler/pptest1.c b/testcode/compiler/pptest1.c
new file mode 100644 (file)
index 0000000..b80c8b7
--- /dev/null
@@ -0,0 +1,6 @@
+#define hash_hash      # ## #
+#define mkstr(a)       # a
+#define in_between(a)  mkstr(a)
+#define join(c, d)     in_between(c hash_hash d)
+
+char p[] = join(x, y);         // Comment
diff --git a/testcode/compiler/pptest2.c b/testcode/compiler/pptest2.c
new file mode 100644 (file)
index 0000000..0d613cd
--- /dev/null
@@ -0,0 +1,19 @@
+#define x      3
+#define f(a)   f(x * (a))
+#undef x
+#define x      2
+#define g      f
+#define z      z[0]
+#define h      g(~
+#define m(a)   a(w)
+#define w      0,1
+#define t(a)   a
+#define p()    int
+#define q(x)   x
+#define r(x,y) x ## y
+#define str(x) # x
+
+f(y+1) + f(f(z)) % t(t(g) (0) + t)(1);
+g(x+(3,4)-w) | h 5) & m(f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
+char c[2][6] = { str(hello), str() };
diff --git a/testcode/compiler/pptest3.c b/testcode/compiler/pptest3.c
new file mode 100644 (file)
index 0000000..2c2df87
--- /dev/null
@@ -0,0 +1,16 @@
+#define str(s)         # s
+#define xstr(s)                str(s)
+#define debug(s, t)    printf("x" # s "= %d, x" # t "= %s", \
+                              x ## s, x ## t)
+#define INCFILE(n)     vers ## n       // Comment
+#define glue(a,b)      a ## b
+#define xglue(a,b)     glue(a,b)
+#define HIGHLOW                "hello"
+#define LOW            LOW ", world"
+
+debug (1, 2);
+fputs (str (strncmp("abc\0d", "abc", '\4') // Comment
+           == 0) str (: @\n), s);
+glue (HIGH, LOW);
+xglue (HIGH, LOW);
+
diff --git a/testcode/compiler/pptest4.c b/testcode/compiler/pptest4.c
new file mode 100644 (file)
index 0000000..abb0d24
--- /dev/null
@@ -0,0 +1,3 @@
+#define t(x,y,z)       x ## y ## z
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), 
+           t(10,,), t(,11,), t(,,12), t(,,) };
diff --git a/util/atari/ataricvt.c b/util/atari/ataricvt.c
new file mode 100644 (file)
index 0000000..35a8ebb
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int main (void)
+{
+    int C;
+    while ((C = getchar ()) != EOF) {
+       if (C == 0x9B) {
+           putchar ('\n');
+       } else if (C == 0x7F) {
+           putchar ('\t');
+       } else {  
+           putchar (C);
+       }
+    }
+    return 0;
+}
+