From e95549dfd1339070b5a3cacd602a87eeb13b859d Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Sun, 19 Nov 2023 21:24:38 +0100 Subject: [PATCH] official xa-2.4.0 --- xa/ChangeLog | 41 ++ xa/Makefile | 20 +- xa/README.1st | 25 +- xa/TODO | 16 +- xa/attic/README | 6 + xa/{ => attic}/doc/README | 0 xa/{ => attic}/doc/fileformat.txt | 0 xa/{ => attic}/doc/xa-de.log | 0 xa/{ => attic}/doc/xa-de.txt | 0 xa/{ => attic}/doc/xa.html | 0 xa/{ => attic}/doc/xa.log | 0 xa/{ => attic}/doc/xa.txt | 0 xa/{ => attic}/doc/xaannounce | 0 xa/{ => attic}/loader/Makefile | 0 xa/attic/loader/Makefile.test | 19 + xa/{ => attic}/loader/README | 0 xa/{ => attic}/loader/ex2 | Bin xa/{ => attic}/loader/example2 | Bin xa/{ => attic}/loader/file.def | 0 xa/{ => attic}/loader/loader.a65 | 0 xa/attic/loader/rom65.ok | Bin 0 -> 186 bytes xa/{ => attic}/loader/test.a | 0 xa/{ => attic}/loader/test2.a | 0 xa/{ => attic}/loader/test3.a | 0 xa/man/README | 2 +- xa/man/file65.1 | 7 +- xa/man/ldo65.1 | 18 +- xa/man/printcbm.1 | 14 +- xa/man/reloc65.1 | 10 +- xa/man/uncpk.1 | 2 +- xa/man/xa.1 | 379 +++++++++--- xa/misc/Makefile | 2 +- xa/misc/file65.c | 74 ++- xa/misc/ldo65.c | 766 ++++++++++++++++++----- xa/misc/printcbm.c | 4 +- xa/misc/reloc65.c | 57 +- xa/misc/uncpk.c | 2 +- xa/src/Makefile | 5 +- xa/src/version.h | 4 +- xa/src/xa.c | 448 +++++++++----- xa/src/xa.h | 8 +- xa/src/xaa.c | 75 ++- xa/src/xad.h | 3 +- xa/src/xah.h | 99 ++- xa/src/xal.c | 544 ++++++++++++---- xa/src/xal.h | 13 +- xa/src/xalisting.c | 750 ++++++++++++++++++++++ xa/src/xalisting.h | 34 + xa/src/xam.c | 5 +- xa/src/xao.c | 2 +- xa/src/xap.c | 635 ++++++++++++------- xa/src/xap.h | 3 + xa/src/xar.c | 30 +- xa/src/xar.h | 2 +- xa/src/xar2.c | 12 +- xa/src/xat.c | 993 ++++++++++++++++++++++++------ xa/src/xat.h | 6 +- xa/src/xau.c | 12 +- xa/tests/README | 18 +- xa/tests/aserr/Makefile | 16 + xa/tests/aserr/ok | 1 + xa/tests/aserr/test.s | 41 ++ xa/tests/ca65/Makefile | 39 ++ xa/tests/ca65/escape1.a65 | 6 + xa/tests/ca65/escape1.out | 1 + xa/tests/ca65/escape2.a65 | 6 + xa/tests/ca65/escape2.ca65 | 1 + xa/tests/ca65/unnamed1.a65 | 15 + xa/tests/ca65/unnamed1.ca65 | Bin 0 -> 16 bytes xa/tests/ca65/unnamed2.a65 | 17 + xa/tests/ca65/unnamed2.ca65 | Bin 0 -> 16 bytes xa/tests/chardelimiter/ok | 2 +- xa/tests/chardelimiter/test.s | 6 +- xa/tests/cpktest/Makefile | 4 +- xa/tests/csapiec/testseg.ok | Bin 220 -> 220 bytes xa/tests/expando/ok | 1 + xa/tests/expando/test.s | 23 + xa/tests/harness | 41 +- xa/tests/ldoreloc/10.s | 3 + xa/tests/ldoreloc/20.s | 6 + xa/tests/ldoreloc/30.s | 2 + xa/tests/ldoreloc/31.s | 2 + xa/tests/ldoreloc/40.s | 4 + xa/tests/ldoreloc/41.s | 7 + xa/tests/ldoreloc/50.s | 8 + xa/tests/ldoreloc/51.s | 11 + xa/tests/ldoreloc/60.s | 13 + xa/tests/ldoreloc/61.s | 15 + xa/tests/ldoreloc/Makefile | 134 +++- xa/tests/ldoreloc/t1.ok | 1 + xa/tests/ldoreloc/t10.ok | Bin 0 -> 10 bytes xa/tests/ldoreloc/t11.ok | Bin 0 -> 10 bytes xa/tests/ldoreloc/t2.ok | Bin 0 -> 7 bytes xa/tests/ldoreloc/t20.ok | Bin 0 -> 15 bytes xa/tests/ldoreloc/t21.ok | Bin 0 -> 15 bytes xa/tests/ldoreloc/t30.ok | 1 + xa/tests/ldoreloc/t31.ok | 1 + xa/tests/ldoreloc/t40.ok | 1 + xa/tests/ldoreloc/t41.ok | 1 + xa/tests/ldoreloc/t50.ok | Bin 0 -> 94 bytes xa/tests/ldoreloc/t51.ok | Bin 0 -> 94 bytes xa/tests/ldoreloc/t60.ok | Bin 0 -> 113 bytes xa/tests/ldoreloc/t61.ok | Bin 0 -> 113 bytes xa/tests/line/ok | Bin 0 -> 74 bytes xa/tests/line/test.s | 20 + xa/tests/listing/Makefile | 51 ++ xa/tests/listing/a.o65 | Bin 0 -> 16 bytes xa/tests/listing/assert.a65 | 8 + xa/tests/listing/assert.html | 12 + xa/tests/listing/assert.o65 | Bin 0 -> 5 bytes xa/tests/listing/assert.out | 10 + xa/tests/listing/include1.a65 | 8 + xa/tests/listing/include1.out | 23 + xa/tests/listing/include1a.a65 | 3 + xa/tests/listing/linebreak.a65 | 160 +++++ xa/tests/listing/linebreak.out | 162 +++++ xa/tests/listing/listblocks.a65 | 23 + xa/tests/listing/listblocks.html | 24 + xa/tests/listing/listca65.a65 | 24 + xa/tests/listing/listca65.ca65 | Bin 0 -> 18 bytes xa/tests/listing/listca65.html | 30 + xa/tests/listing/listca65_2.a65 | 15 + xa/tests/listing/listca65_2.ca65 | Bin 0 -> 11 bytes xa/tests/listing/listca65_2.html | 32 + xa/tests/listing/listca65_2b.a65 | 7 + xa/tests/listing/operators.a65 | 16 + xa/tests/listing/operators.out | 17 + xa/tests/mvnmvp/Makefile | 1 + xa/tests/mvnmvp/test.s | 16 + xa/tests/pparity/Makefile | 12 + xa/tests/pparity/bad.s | 3 + xa/tests/pparity/bad2.s | 3 + xa/tests/pparity/bad3.s | 10 + xa/tests/pparity/bad4.s | 4 + xa/tests/pparity/good.ok | 1 + xa/tests/pparity/good.s | 10 + xa/tests/ppdefines/Makefile | 21 + xa/tests/ppdefines/test1.a65 | 32 + xa/tests/ppdefines/test1.o65 | Bin 0 -> 22 bytes xa/tests/ppdefines/test2.a65 | 33 + xa/tests/ppdefines/test2.o65 | 1 + xa/tests/ppdefines/test3.a65 | 11 + xa/tests/ppdefines/test3.o65 | 1 + xa/tests/ppdefines/test4.a65 | 13 + xa/tests/ppdefines/test4.o65 | 1 + xa/tests/ppdefines/test5.a65 | 28 + xa/tests/ppdefines/test5.o65 | 1 + xa/tests/ppdefines/test6.a65 | 45 ++ xa/tests/ppdefines/test6.o65 | 0 xa/tests/ppdefines/test6a.a65 | 28 + xa/tests/ppdefines/test6a.o65 | 0 xa/tests/ppdefines/test6b.a65 | 20 + xa/tests/ppdefines/test6b.o65 | 0 xa/tests/ppdefines/test7.a65 | 23 + xa/tests/ppdefines/test7.o65 | 1 + xa/tests/ppstrings/ok | Bin 21 -> 23 bytes xa/tests/ppstrings/test.s | 2 +- xa/tests/recucom/ok | Bin 0 -> 16 bytes xa/tests/recucom/test.s | 34 + xa/tests/relmode/Makefile | 34 + xa/tests/relmode/b.ok | Bin 0 -> 86 bytes xa/tests/relmode/mix1.a65 | 11 + xa/tests/relmode/mix1.ok | Bin 0 -> 54 bytes xa/tests/relmode/mix2.a65 | 11 + xa/tests/relmode/mix2.ok | Bin 0 -> 54 bytes xa/tests/relmode/mixabsolute.a65 | 23 + xa/tests/relmode/testseg.ok | Bin 0 -> 220 bytes xa/tests/relocundef/Makefile | 2 +- xa/tests/reset_segment/Makefile | 2 +- xa/tests/reset_segment/test2a.s | 8 + xa/tests/stringcom/ok | Bin 79 -> 111 bytes xa/tests/stringcom/test.s | 5 +- xa/tests/undef/Makefile | 65 ++ xa/tests/undef/undef.a65 | 23 + xa/tests/undef/undef2.ok | Bin 0 -> 73 bytes xa/tests/undef/undef4.a65 | 14 + xa/tests/undef/undef5.a65 | 16 + xa/tests/undef/undef5.ok | Bin 0 -> 48 bytes xa/tests/undef/undef6.a65 | 26 + xa/tests/undef/undef6.ok | Bin 0 -> 53 bytes xa/tests/usb65/Makefile | 8 + xa/tests/usb65/test1.a65 | 42 ++ xa/tests/usb65/test1.o65 | Bin 0 -> 96 bytes xa/tests/usb65/test2.a65 | 16 + xa/tests/usb65/test2.o65 | Bin 0 -> 55 bytes 185 files changed, 5779 insertions(+), 1122 deletions(-) create mode 100644 xa/attic/README rename xa/{ => attic}/doc/README (100%) rename xa/{ => attic}/doc/fileformat.txt (100%) rename xa/{ => attic}/doc/xa-de.log (100%) rename xa/{ => attic}/doc/xa-de.txt (100%) rename xa/{ => attic}/doc/xa.html (100%) rename xa/{ => attic}/doc/xa.log (100%) rename xa/{ => attic}/doc/xa.txt (100%) rename xa/{ => attic}/doc/xaannounce (100%) rename xa/{ => attic}/loader/Makefile (100%) create mode 100644 xa/attic/loader/Makefile.test rename xa/{ => attic}/loader/README (100%) rename xa/{ => attic}/loader/ex2 (100%) rename xa/{ => attic}/loader/example2 (100%) rename xa/{ => attic}/loader/file.def (100%) rename xa/{ => attic}/loader/loader.a65 (100%) create mode 100644 xa/attic/loader/rom65.ok rename xa/{ => attic}/loader/test.a (100%) rename xa/{ => attic}/loader/test2.a (100%) rename xa/{ => attic}/loader/test3.a (100%) create mode 100644 xa/src/xalisting.c create mode 100644 xa/src/xalisting.h create mode 100644 xa/tests/aserr/Makefile create mode 100644 xa/tests/aserr/ok create mode 100644 xa/tests/aserr/test.s create mode 100644 xa/tests/ca65/Makefile create mode 100644 xa/tests/ca65/escape1.a65 create mode 100644 xa/tests/ca65/escape1.out create mode 100644 xa/tests/ca65/escape2.a65 create mode 100644 xa/tests/ca65/escape2.ca65 create mode 100644 xa/tests/ca65/unnamed1.a65 create mode 100644 xa/tests/ca65/unnamed1.ca65 create mode 100644 xa/tests/ca65/unnamed2.a65 create mode 100644 xa/tests/ca65/unnamed2.ca65 create mode 100644 xa/tests/expando/ok create mode 100644 xa/tests/expando/test.s create mode 100644 xa/tests/ldoreloc/10.s create mode 100644 xa/tests/ldoreloc/20.s create mode 100644 xa/tests/ldoreloc/30.s create mode 100644 xa/tests/ldoreloc/31.s create mode 100644 xa/tests/ldoreloc/40.s create mode 100644 xa/tests/ldoreloc/41.s create mode 100644 xa/tests/ldoreloc/50.s create mode 100644 xa/tests/ldoreloc/51.s create mode 100644 xa/tests/ldoreloc/60.s create mode 100644 xa/tests/ldoreloc/61.s create mode 100644 xa/tests/ldoreloc/t1.ok create mode 100644 xa/tests/ldoreloc/t10.ok create mode 100644 xa/tests/ldoreloc/t11.ok create mode 100644 xa/tests/ldoreloc/t2.ok create mode 100644 xa/tests/ldoreloc/t20.ok create mode 100644 xa/tests/ldoreloc/t21.ok create mode 100644 xa/tests/ldoreloc/t30.ok create mode 100644 xa/tests/ldoreloc/t31.ok create mode 100644 xa/tests/ldoreloc/t40.ok create mode 100644 xa/tests/ldoreloc/t41.ok create mode 100644 xa/tests/ldoreloc/t50.ok create mode 100644 xa/tests/ldoreloc/t51.ok create mode 100644 xa/tests/ldoreloc/t60.ok create mode 100644 xa/tests/ldoreloc/t61.ok create mode 100644 xa/tests/line/ok create mode 100644 xa/tests/line/test.s create mode 100644 xa/tests/listing/Makefile create mode 100644 xa/tests/listing/a.o65 create mode 100644 xa/tests/listing/assert.a65 create mode 100644 xa/tests/listing/assert.html create mode 100644 xa/tests/listing/assert.o65 create mode 100644 xa/tests/listing/assert.out create mode 100644 xa/tests/listing/include1.a65 create mode 100644 xa/tests/listing/include1.out create mode 100644 xa/tests/listing/include1a.a65 create mode 100644 xa/tests/listing/linebreak.a65 create mode 100644 xa/tests/listing/linebreak.out create mode 100644 xa/tests/listing/listblocks.a65 create mode 100644 xa/tests/listing/listblocks.html create mode 100644 xa/tests/listing/listca65.a65 create mode 100644 xa/tests/listing/listca65.ca65 create mode 100644 xa/tests/listing/listca65.html create mode 100644 xa/tests/listing/listca65_2.a65 create mode 100644 xa/tests/listing/listca65_2.ca65 create mode 100644 xa/tests/listing/listca65_2.html create mode 100644 xa/tests/listing/listca65_2b.a65 create mode 100644 xa/tests/listing/operators.a65 create mode 100644 xa/tests/listing/operators.out create mode 100644 xa/tests/pparity/Makefile create mode 100644 xa/tests/pparity/bad.s create mode 100644 xa/tests/pparity/bad2.s create mode 100644 xa/tests/pparity/bad3.s create mode 100644 xa/tests/pparity/bad4.s create mode 100644 xa/tests/pparity/good.ok create mode 100644 xa/tests/pparity/good.s create mode 100644 xa/tests/ppdefines/Makefile create mode 100644 xa/tests/ppdefines/test1.a65 create mode 100644 xa/tests/ppdefines/test1.o65 create mode 100644 xa/tests/ppdefines/test2.a65 create mode 100644 xa/tests/ppdefines/test2.o65 create mode 100644 xa/tests/ppdefines/test3.a65 create mode 100644 xa/tests/ppdefines/test3.o65 create mode 100644 xa/tests/ppdefines/test4.a65 create mode 100644 xa/tests/ppdefines/test4.o65 create mode 100644 xa/tests/ppdefines/test5.a65 create mode 100644 xa/tests/ppdefines/test5.o65 create mode 100644 xa/tests/ppdefines/test6.a65 create mode 100644 xa/tests/ppdefines/test6.o65 create mode 100644 xa/tests/ppdefines/test6a.a65 create mode 100644 xa/tests/ppdefines/test6a.o65 create mode 100644 xa/tests/ppdefines/test6b.a65 create mode 100644 xa/tests/ppdefines/test6b.o65 create mode 100644 xa/tests/ppdefines/test7.a65 create mode 100644 xa/tests/ppdefines/test7.o65 create mode 100644 xa/tests/recucom/ok create mode 100644 xa/tests/recucom/test.s create mode 100644 xa/tests/relmode/Makefile create mode 100644 xa/tests/relmode/b.ok create mode 100644 xa/tests/relmode/mix1.a65 create mode 100644 xa/tests/relmode/mix1.ok create mode 100644 xa/tests/relmode/mix2.a65 create mode 100644 xa/tests/relmode/mix2.ok create mode 100644 xa/tests/relmode/mixabsolute.a65 create mode 100644 xa/tests/relmode/testseg.ok create mode 100644 xa/tests/reset_segment/test2a.s create mode 100644 xa/tests/undef/Makefile create mode 100644 xa/tests/undef/undef.a65 create mode 100644 xa/tests/undef/undef2.ok create mode 100644 xa/tests/undef/undef4.a65 create mode 100644 xa/tests/undef/undef5.a65 create mode 100644 xa/tests/undef/undef5.ok create mode 100644 xa/tests/undef/undef6.a65 create mode 100644 xa/tests/undef/undef6.ok create mode 100644 xa/tests/usb65/Makefile create mode 100644 xa/tests/usb65/test1.a65 create mode 100644 xa/tests/usb65/test1.o65 create mode 100644 xa/tests/usb65/test2.a65 create mode 100644 xa/tests/usb65/test2.o65 diff --git a/xa/ChangeLog b/xa/ChangeLog index 169bf18..b648897 100644 --- a/xa/ChangeLog +++ b/xa/ChangeLog @@ -397,3 +397,44 @@ xa-2.3.14 -- Cameron Kaiser 7 February 2023 +xa-2.4.0 + + * Listing feature in plain text or HTML, along with .listbytes to control + how hex bytes get listed in the output. + * Add -E commandline option to not stop after 20 errors, but show all + of them. + * Introduce -X compatibility set commandline option, to distinguish + between MASM and CA65 compatibility options; also adds C option for + 0x and 0 to specify hex or octal. As a result, -M is now deprecated, + and colons in comments may become the default in a future version. + * Implement CA65 "cheap local labels", ":=" label definitions, + and various pseudo-opcodes (.include, .import, .importzp, + .zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc). + * -U option to allow all undefined labels in relocation mode; this + allows exporting them to an o65 file and link at a later time (or + specify one at a time with -L). + * Globals may also be specified manually with -g. + * #error allows preprocessor-level assertions. + * .assert allows assembler-level assertions. + * Better fix for segfault with smaller arity macro issue. + * Main Makefile fixes. + * Fixed parallel make in tests, incorporating a patch from Sergei + Trofimovich. + * Added a test case that failed in 2.3.14 from Tom Hargreaves. + * Some 2.3.x features still allowed with -XXA23, which is obviously + deprecated. + * The quote escape character is now the \ (backslash), except if -XXA23. + * Recursive /* */ comments are no longer allowed, except if -XXA23. + * XA_MAJOR and XA_MINOR predefined macros, except if -XXA23. + * Testsuite greatly expanded. + * The old loader/ testsuite and doc/ archive are now in attic/, which is + the repository for old unsupported components. It may be purged in a + future version. + * -M is now deprecated (use -XMASM), just in case you forgot. + * printcbm(1) is now deprecated (use VICE petcat, it does a lot more). + * Previously deprecated options (16-bit mvn/mvp argument, -S, -x) finally + removed. If you need this support, you must use 2.3.x. + + -- André Fachat and + -- Cameron Kaiser , 18 November, 2023 + diff --git a/xa/Makefile b/xa/Makefile index ae0ccf3..fb0204f 100644 --- a/xa/Makefile +++ b/xa/Makefile @@ -1,5 +1,6 @@ # Unix gcc or DOS go32 cross-compiling gcc # +VERS = 2.4.0 CC = gcc LD = gcc # for testing. not to be used; build failures in misc/. @@ -37,8 +38,8 @@ killxa: xa: (cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE}) -load: - (cd loader && CC="${CC} ${CFLAGS}" ${MAKE}) +#load: +# (cd loader && CC="${CC} ${CFLAGS}" ${MAKE}) uncpk: (cd misc && CC="${CC} ${CFLAGS}" ${MAKE}) @@ -54,11 +55,11 @@ mingw: clean clean: (cd src && ${MAKE} clean) - (cd loader && ${MAKE} clean) + #(cd loader && ${MAKE} clean) (cd misc && ${MAKE} mrproper) rm -f xa *.exe *.o65 *.s core -install: xa uncpk +install: all $(MKDIR) $(BINDIR) $(MKDIR) $(MANDIR) $(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR) @@ -66,9 +67,14 @@ install: xa uncpk #$(MKDIR) $(DOCDIR)/xa65 dist: clean - cd .. ; tar cvf xa-2.3.14.tar xa-2.3.14 ; gzip xa-2.3.14.tar + cd .. ; tar cvf xa-$(VERS).tar xa-$(VERS) ; gzip xa-$(VERS).tar -test: xa uncpk +# no prereqs to force parallel make to play nice +test: + rm -rf xa + $(MAKE) xa + $(MAKE) uncpk cd tests && ./harness \ -tests="$(TESTS)" \ - -make="$(MAKE)" -cc="$(CC)" -cflags="$(CFLAGS)" + -cc="$(CC)" -cflags="$(CFLAGS)" \ + -make="$(MAKE)" -makeflags="$(MAKEFLAGS)" diff --git a/xa/README.1st b/xa/README.1st index 25fbe2f..d7e4ede 100644 --- a/xa/README.1st +++ b/xa/README.1st @@ -3,10 +3,20 @@ derivatives). xa is a small, fast, portable two-pass assembler that compiles under most ANSI C compilers. It is distributed under the GNU Public License (see COPYING). -The current version is 2.3.10, a bug fix to the long-lived 2.3.0, itself with -compatibility improvements and new man-based documentation. It also completed -the merge of the 65816 and 6502/R65C02 versions and thus the current xa can -generate code for all targets now. +The current version is 2.4.0, the first new feature release literally in +years. It builds upon the improvements in 2.3.x and its unified 6502/65816 +assembler core by adding listing capability, greater flexibility with +relocatable objects, and better cross-compatibility with other popular +cross-assemblers (notably ca65) because once you use xa, you'll want to keep +on using it. :) + +Certain long-deprecated options and non-standard syntaxes have also been +removed in this release, so it is possible some very old code may not +assemble without errors. These changes have been a long time coming and we +gave lots of warnings, so if you require these features and cannot change +your code to work without them, you must use xa 2.3.14. Fortunately, most +code should continue to work just fine and the test suite is even bigger to +catch these sorts of regressions. To install on a generic Unixy thing, you should be able to just type @@ -17,9 +27,8 @@ To install on a generic Unixy thing, you should be able to just type This will create xa along with its various support utilities. Try assembling the cpk depacker in examples/ as a test. xa also comes with uncpk (a program for generating cpk archives) and printcbm (a program for listing Commodore -BASIC test) and file65, ldo65 and reloc65 for displaying, linking and -relocating o65 files in Andre's relocatable format (see doc/fileformats.txt). -The loader/ directory also has goodies for managing relocatable binaries. +BASIC test, now deprecated as of 2.4) and file65, ldo65 and reloc65 for +displaying, linking and relocating o65 files in Andre's relocatable format. Don't forget the man pages in man/. Install these into your MANPATH at your leisure, or read them with nroff -man (and/or groff -man). @@ -38,6 +47,8 @@ Fabian Nunez. For mingw, use make mingw +(but do it from within MSYS2). + Similarly, Amiga and Atari ST compilation should still also function with their particular compatible packages. diff --git a/xa/TODO b/xa/TODO index 0944889..7c13eae 100644 --- a/xa/TODO +++ b/xa/TODO @@ -1,10 +1,18 @@ o nm65 that prints labels from o65 files -o `-L' option for ldo65, such that globals can be suppressed, - but KERNEL can be kept - o inc a -> ina, dec a -> dea (right now uses bare inc and dec) o VICE label file support -o Smarter -X that can cope with non-block-aligned segment sizes +o Smarter -X that can cope with non-block-aligned segment sizes (in reloc65) + +o The listing feature is not bug-free yet: + - ca65 and other assembler compatibility pseudo-opcodes will be + listed as xa specific ones, not the original in the source + E.g. a CA65 ".scope" will appear as ".(" in the listing + - The assembler has no pre-processor handling, so pp constants are + resolved at parse time. Thus they appear as their value + in the listing. + - One situation is ".listbytes unlimited", + which will show as ".listbytes 0" in the listing + diff --git a/xa/attic/README b/xa/attic/README new file mode 100644 index 0000000..90b909e --- /dev/null +++ b/xa/attic/README @@ -0,0 +1,6 @@ +These are files that have been superseded and may be removed in the future. + +loader/ Rewritten as tests/loader/ +doc/ Replaced by man/ + (for o65, see http://www.6502.org/users/andre/o65/ ) + diff --git a/xa/doc/README b/xa/attic/doc/README similarity index 100% rename from xa/doc/README rename to xa/attic/doc/README diff --git a/xa/doc/fileformat.txt b/xa/attic/doc/fileformat.txt similarity index 100% rename from xa/doc/fileformat.txt rename to xa/attic/doc/fileformat.txt diff --git a/xa/doc/xa-de.log b/xa/attic/doc/xa-de.log similarity index 100% rename from xa/doc/xa-de.log rename to xa/attic/doc/xa-de.log diff --git a/xa/doc/xa-de.txt b/xa/attic/doc/xa-de.txt similarity index 100% rename from xa/doc/xa-de.txt rename to xa/attic/doc/xa-de.txt diff --git a/xa/doc/xa.html b/xa/attic/doc/xa.html similarity index 100% rename from xa/doc/xa.html rename to xa/attic/doc/xa.html diff --git a/xa/doc/xa.log b/xa/attic/doc/xa.log similarity index 100% rename from xa/doc/xa.log rename to xa/attic/doc/xa.log diff --git a/xa/doc/xa.txt b/xa/attic/doc/xa.txt similarity index 100% rename from xa/doc/xa.txt rename to xa/attic/doc/xa.txt diff --git a/xa/doc/xaannounce b/xa/attic/doc/xaannounce similarity index 100% rename from xa/doc/xaannounce rename to xa/attic/doc/xaannounce diff --git a/xa/loader/Makefile b/xa/attic/loader/Makefile similarity index 100% rename from xa/loader/Makefile rename to xa/attic/loader/Makefile diff --git a/xa/attic/loader/Makefile.test b/xa/attic/loader/Makefile.test new file mode 100644 index 0000000..e3b1d00 --- /dev/null +++ b/xa/attic/loader/Makefile.test @@ -0,0 +1,19 @@ + +all: loader example test2 rom65 +clean: + rm -f loader test2 example a.o65 rom65 + +loader: loader.a65 file.def + ../../xa loader.a65 -o loader + +example: test.a + ../../xa -R test.a -o example + +test2: test2.a + ../../xa test2.a -o test2 + +rom65: test.a + # ugly! + # don't run if this system doesn't have bash + test -f /bin/bash || exit 0 && ( cd .. && ../mkrom.sh -O "-G" -S "-bd 1234" -R loader/rom65 loader/test.a loader/test.a ) && ( ../hextool -cmp=rom65.ok < rom65 ) + diff --git a/xa/loader/README b/xa/attic/loader/README similarity index 100% rename from xa/loader/README rename to xa/attic/loader/README diff --git a/xa/loader/ex2 b/xa/attic/loader/ex2 similarity index 100% rename from xa/loader/ex2 rename to xa/attic/loader/ex2 diff --git a/xa/loader/example2 b/xa/attic/loader/example2 similarity index 100% rename from xa/loader/example2 rename to xa/attic/loader/example2 diff --git a/xa/loader/file.def b/xa/attic/loader/file.def similarity index 100% rename from xa/loader/file.def rename to xa/attic/loader/file.def diff --git a/xa/loader/loader.a65 b/xa/attic/loader/loader.a65 similarity index 100% rename from xa/loader/loader.a65 rename to xa/attic/loader/loader.a65 diff --git a/xa/attic/loader/rom65.ok b/xa/attic/loader/rom65.ok new file mode 100644 index 0000000000000000000000000000000000000000..081dd282a93155ea9f3e56f669fbc61b241c13e1 GIT binary patch literal 186 zcma!PU}VTQGi6|4P;ZcAxWvN3z~CUlz``H`6yah_%gjm5OUzAWSlMuab*%wIz`uw#|NjBI`7v(* literal 0 HcmV?d00001 diff --git a/xa/loader/test.a b/xa/attic/loader/test.a similarity index 100% rename from xa/loader/test.a rename to xa/attic/loader/test.a diff --git a/xa/loader/test2.a b/xa/attic/loader/test2.a similarity index 100% rename from xa/loader/test2.a rename to xa/attic/loader/test2.a diff --git a/xa/loader/test3.a b/xa/attic/loader/test3.a similarity index 100% rename from xa/loader/test3.a rename to xa/attic/loader/test3.a diff --git a/xa/man/README b/xa/man/README index 4d54849..50282cd 100644 --- a/xa/man/README +++ b/xa/man/README @@ -1,3 +1,3 @@ -Also look at ../doc/ for previous documentation files and the Change log. +Also look at ../attic/doc/ for previous documentation files. Cameron Kaiser diff --git a/xa/man/file65.1 b/xa/man/file65.1 index 603db67..713fd01 100644 --- a/xa/man/file65.1 +++ b/xa/man/file65.1 @@ -1,4 +1,4 @@ -.TH FILE65 "1" "11 April 2006" +.TH FILE65 "1" "18 November 2023" .SH NAME file65 \- print information for o65 object files @@ -13,9 +13,12 @@ prints file information for files in the o65 object format. .SH OPTIONS .TP -.B \-V +.B \-v Print undefined and global labels. .TP +.B \-vv +Print undefined and global labels, and relocation tables. +.TP .B \-P Print the segment end addresses (suitable for the .BR xa (1) diff --git a/xa/man/ldo65.1 b/xa/man/ldo65.1 index 594ce92..9a4c366 100644 --- a/xa/man/ldo65.1 +++ b/xa/man/ldo65.1 @@ -1,4 +1,4 @@ -.TH LDO65 "1" "11 April 2006" +.TH LDO65 "1" "18 November 2023" .SH NAME ldo65 \- linker for o65 object files @@ -9,7 +9,7 @@ ldo65 \- linker for o65 object files .SH DESCRIPTION .B ldo65 -is a linker for files in the `o65' object format, formerly +is a linker for files in the o65 object format, formerly .B ld65 but renamed to avoid conflicts with the .B cc65 @@ -32,9 +32,23 @@ man page for an explanation. Set output filename. The default is .BR a.o65 \&. .TP +.B \-L name +Allow label +.B name +to remain undefined, even after linking. +This option may be specified multiple times for multiple labels. +.TP +.B \-U +Allow any label to remain undefined, even after linking. +.TP .B \-G Suppress writing of globals. .TP +.B \-g name +Only export global +.BR name . +This option may be specified multiple times for multiple globals. +.TP .B \-\-help Show summary of options. .TP diff --git a/xa/man/printcbm.1 b/xa/man/printcbm.1 index a327a4c..a79b64a 100644 --- a/xa/man/printcbm.1 +++ b/xa/man/printcbm.1 @@ -1,7 +1,17 @@ -.TH PRINTCBM "1" "11 April 2006" +.TH PRINTCBM "1" "DEPRECATED" .SH NAME -printcbm \- list a Commodore BASIC file +printcbm \- list a Commodore BASIC file (DEPRECATED) + +.SH NOTICE +As of +.B xa +2.4, +.B printcbm +is deprecated and will be removed in a future version. Please consider +migrating your usage to VICE +.BR petcat(1) , +which has many more options. .SH SYNOPSIS .B printcbm diff --git a/xa/man/reloc65.1 b/xa/man/reloc65.1 index 6a90214..eda869b 100644 --- a/xa/man/reloc65.1 +++ b/xa/man/reloc65.1 @@ -1,4 +1,4 @@ -.TH RELOC65 "1" "11 April 2006" +.TH RELOC65 "1" "18 November 2023" .SH NAME reloc65 \- relocator for o65 object files @@ -19,6 +19,9 @@ object format. Set output filename. The default is .BR a.o65 \&. .TP +.B \-v +Verbose output. +.TP .B \-b? addr Relocate segment .B ? @@ -40,8 +43,9 @@ respectively. Not valid for bss or zero. .B \-X Extract text and data segment together from the file instead of writing back the whole -file. Relocating data segment to the end of the text segment -(ignoring the \-xd option) before extracting. +file. Relocating data segment to the end of the text segment and +bss segment to the end of the data segment +(\-xd and \-xb options override the derived address) before extracting. .TP .B \-\-help Show summary of options. diff --git a/xa/man/uncpk.1 b/xa/man/uncpk.1 index 3be6e34..d97dbb7 100644 --- a/xa/man/uncpk.1 +++ b/xa/man/uncpk.1 @@ -1,4 +1,4 @@ -.TH UNCPK "1" "11 April 2006" +.TH UNCPK "1" "18 November 2023" .SH NAME uncpk \- manage c64 cpk archives diff --git a/xa/man/xa.1 b/xa/man/xa.1 index 2729ce1..a91a3cf 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -1,4 +1,4 @@ -.TH XA "1" "24 November 2021" +.TH XA "1" "18 November 2023" .SH NAME xa \- 6502/R65C02/65816 cross-assembler @@ -18,6 +18,9 @@ further in this manual page. .SH OPTIONS .TP +.B \-E +Do not stop after 20 errors, but show all errors. +.TP .B \-v Verbose output. .TP @@ -45,11 +48,22 @@ use the special filename .BR \- to output to standard output. .TP +.B \-P filename +Set listing filename. The default is none; use the special filename +.BR \- +to print the listing to standard output. +.TP +.B \-F format +Set listing format; default is +.BR plain . +The only other currently supported format is +.BR html . +.TP .B \-e filename -Set errorlog filename, default is none. +Set errorlog filename; default is none. .TP .B \-l filename -Set labellist filename, default is none. This is the symbol table and can +Set labellist filename; default is none. This is the symbol table and can be used by disassemblers such as .BR dxa (1) to reconstruct source. @@ -58,12 +72,70 @@ to reconstruct source. Add cross-reference list to labellist (requires .BR \-l ). .TP +.B \-Xcompatset +Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers and codebases. +Currently supported are compatibility sets +.BR MASM , +.BR CA65 +and +.BR C , +with +.B XA23 +available as a deprecated option for codebases relying on compatibility with +the previous version of +.BR xa . +Multiple compatibility sets may be specified and combined, e.g., +.B \-XMASM +.BR \-XXA23 . +.IP +.B \-XMASM +allows colons to appear in comments for MASM compatibility. +This does not affect colon interpretation elsewhere and may become the default in a future version. +.IP +.B \-XCA65 +adds syntactic features more compatible with +.BR ca65 (1). +It permits +.B := +for defining labels (instead of plain +.BR = ), +and adds support for unnamed labels and "cheap" local labels using the +.B @ +character, but disables its other meaning for 24-bit mode (see +.B ASSEMBLER +.BR SYNTAX ). +.IP +.B \-XC +enables the usage of +.B 0xHEX +and +.B 0OCTAL +C-style number encodings. +.IP +.B \-XXA23 +restores partial compatibility with +.B xa +2.3.x. In particular, it uses +.B ^ +for quote escapes instead of 2.4's +.BR \e , +allows nested multi-line comments, and disables all predefined +.B xa +preprocessor macros. This option is inherently deprecated and may be removed +in the next 2.x or 3.x release. +.TP .B \-M -Allow colons to appear in comments; for MASM compatibility. This does -not affect colon interpretation elsewhere. +This option is deprecated and will be removed in a future version; use +.B \-XMASM +instead. Allows colons to appear in comments for MASM compatibility. This does +not affect colon interpretation elsewhere, and may become the default in a +future version. .TP .B \-R -Start assembler in relocating mode. +Start assembler in relocating mode, i.e. use segments. +.TP +.B \-U +Do not allow undefined labels in relocating mode. .TP .B \-Llabel Defines @@ -121,27 +193,12 @@ Characters may need to be quoted for your shell (example: ). .TP .B \-\-help -Show summary of options. +Show summary of options +.RB ( -? +is a synonym). .TP .B \-\-version Show version of program. -.LP -The following options are -.BR deprecated -and will be removed in 2.4 and later versions: -.TP -.B \-x -Use old filename behaviour (overrides -.BR \-o , -.B \-e -and -.BR \-l ). -.TP -.B \-S -Allow preprocessor substitution within strings (this is now disallowed -for better -.BR cpp (1) -compatibility). .SH ASSEMBLER SYNTAX @@ -177,9 +234,15 @@ decimal value .TP .B $234 hexadecimal value +.RB ( 0x234 +accepted with +.BR -XC ) .TP .B &123 octal +.RB ( 0123 +accepted with +.BR -XC ) .TP .B %010110 binary @@ -221,7 +284,14 @@ statements such as .IP .B * = $c000 .LP -which sets the program counter to decimal location 49152. With the exception +which sets the program counter to decimal location 49152. If +.B \-XCA65 +is specified, you can also use +.B := +as well as +.BR = . +.LP +With the exception of the program counter, labels cannot be assigned multiple times. To explicitly declare redefinition of a label, place a - (dash) before it, e.g., .IP @@ -251,6 +321,52 @@ as a linker; see and .BR LINKING . .LP +If +.B \-XCA65 +is specified, "cheap" local labels may be used, marked by the +.B @ +prefix. Additionally, unnamed labels may be specified with +.B : +(i.e., no label, just a colon); branches may then reference these unnamed +labels with a colon and plus signs for forward branching or minus signs +for backward branching. For example (from the +.B ca65 +documentation), +.LP + : lda (ptr1),y ; #1 +.BR + cmp (ptr2),y +.BR + bne :+ ; -> #2 +.BR + tax +.BR + beq :+++ ; -> #4 +.BR + iny +.BR + bne :- ; -> #1 +.BR + inc ptr1+1 +.BR + inc ptr2+1 +.BR + bne :- ; -> #1 +.BR + +.BR + : bcs :+ ; #2 -> #3 +.BR + ldx #$FF +.BR + rts +.BR + +.BR + : ldx #$01 ; #3 +.BR + : rts ; #4 +.LP For those instructions where the accumulator is the implied argument (such as .B asl and @@ -308,10 +424,14 @@ less than or equal to (7) less than (7) .TP .B = -equal to (6) +equal to (6); +.B == +also accepted .TP .B <> >< -does not equal (6) +does not equal (6); +.B != +also accepted .TP .B & bitwise AND (5) @@ -360,11 +480,10 @@ or zero page value, do not attempt to optimize to a zero page argument for those opcodes that support it (i.e., keep as 16 bit word) .TP .B @ -render as 24-bit quantity for 65816 (must specify +render as 24-bit quantity for 65816, even if smaller than 24 bits (must specify .B \-w -command-line option). -.B This is required to specify any -.B 24-bit quantity! +command-line option, must not specify +.BR \-XCA65 ) .TP .B ` force further optimization, even if the length of the instruction cannot @@ -422,8 +541,9 @@ comments, such that .B ; a comment:lda #0 .LP is understood as a comment followed by an opcode. To defeat this, use the -.B \-M -command line option to allow colons within comments. This does not apply to +.B \-XMASM +compatibility mode to allow colons within comments; this may become the +default in a future version. Colon statement separation does not apply to .B /* */ and .B // @@ -464,7 +584,7 @@ and are synonymous, so you can mix things such as .B .byt $43, 22, """a character string""" and get the expected result. The string is subject to the current character -set, but the remaining bytes are inserted wtihout modification. +set, but the remaining bytes are inserted without modification. .TP .B .aasc """text1""","text2",... Specifies a character string that is @@ -487,7 +607,8 @@ repetitions of will be inserted into the assembled object. For example, .B .dsb 5,$10 will insert five bytes, each being 16 decimal, into the object. The arguments -may be expressions. See +may be expressions. If only a single argument is provided, then the argument +is treated as a number of null bytes to insert. See .B LINKING for how to use this pseudo-op to link multiple objects. .TP @@ -496,8 +617,10 @@ Inlines a binary file without further interpretation specified by .B filename from offset .B offset -to length -.BR length . +(relative to the beginning of the file) +for +.B length +bytes. This allows you to insert data such as a previously assembled object file or an image or other binary data structure, inlined directly into this file's object. If @@ -518,10 +641,23 @@ a block, precede the label with or precede it with .B & to declare it within the previous level only (or globally if you are only -one level deep). Sixteen levels of scoping are permitted. +one level deep). Sixteen levels of scoping are permitted. +.IP +.B \.block +is accepted as a synonym for +.BR \&.( , +as well as +.B \.proc +(but you cannot specify an explicit scope name as in +.BR ca65 ; +only anonymous blocks are supported). .TP .B \&.) Closes a block. +.B .bend +or +.B .endproc +are accepted as synonyms. .TP .B \.as \.al \.xs \.xl Only relevant in 65816 mode (with the @@ -548,31 +684,98 @@ and generate errors if .B \-w is not specified. +.TP +.B \.assert expression,"message" +Evaluates +.B expression +and if it is false (i.e., evaluates to zero), prints +.B message +as a fatal error, terminating assembly immediately. +For example, a block of assembly code +that creates high ROM might have +.IP +\&.assert *<$fffa, "hit vectors" +.IP +to ensure that assembled code does not leak into the 6502 high vectors. If +the preceding code is too long, the assertion will be false, and the +condition will be detected in a controlled fashion. Any operation may be +used as part of the expression, including logical comparisons such as +.BR = , +.BR == , +.BR < , +.BR <= , +.BR > , +.BR >= , +.B != +and +.BR <> . +.TP +.B \.include "filename" +Includes another file in place of the pseudo-op, as if the preprocessor had +done so with an +.B #include +directive (see +.BR PREPROCESSOR ), +but at the assembler +phase after preprocessing has already occurred. + .LP -The following pseudo-ops apply primarily to relocatable .o65 objects. +The following pseudo-op applies to listing mode. +.TP +.B \.listbytes number +In the listing output, sets the maximum number of hex bytes to be printed +in the listing for pseudo-ops like +.BR .byt , +by default 8. The special argument +.B unlimited +sets no upper limit. If listing mode is disabled, this pseudo-op has no +observable effect. + +.LP +The following pseudo-ops apply primarily to relocatable +.B .o65 +objects. A full discussion of the relocatable format is beyond the -scope of this manpage, as it is currently a format in flux. Documentation -on the proposed v1.2 format is in -.B doc/fileformat.txt -within the -.B xa -installation directory. +scope of this manpage; see +.B http://www.6502.org/users/andre/o65/ +for the most current specification. .TP .B .text .data .bss .zero -These pseudo-ops switch between the different segments, .text being the actual -code section, .data being the data segment, .bss being uninitialized label -space for allocation and .zero being uninitialized zero page space for -allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops -are valid in relative and absolute modes. +These pseudo-ops switch between the different segments, +.B .text +being the actual code section, +.B .data +being the data segment, +.B .bss +being uninitialized label space for allocation and +.B .zero +being uninitialized zero page space for allocation. In +.B .bss +and +.BR .zero , +only labels are evaluated. These pseudo-ops +are valid in relocating and absolute modes. +.TP +.B .code +For +.B ca65 +compatibility, this is currently mapped to +.BR .text . +.TP +.B .zeropage +For +.B ca65 +compatibility, this is currently mapped to +.BR .zero . .TP .B .align value Aligns the current segment to a byte boundary (2, 4 or 256) as specified by .B value -(and places it in the header when relative mode is enabled). Other values +(and places it in the header when relocating mode is enabled). Other values generate an error. .TP -.B .fopt type,value1,value2,value3,... +.B .fopt type, value1, value2, value3, ... Acts like .B .byt/.asc except that the values are embedded into the object file as file options. @@ -582,6 +785,17 @@ is used to specify the file option being referenced. A table of these options is in the relocatable o65 file format description. The remainder of the options are interpreted as values to insert. Any number of values may be specified, and may also be strings. +.TP +.B .import label1, label2, label3, ... +Defines the given labels as global labels which are imported and resolved during +the link stage, like the +.B -L +command line parameter. +.TP +.B .importzp label1, label2, label3, ... +Analogous to +.BR .import , +except that it only imports zeropage labels (i.e., byte values). .SH PREPROCESSOR @@ -665,8 +879,19 @@ may interpret too early until the file actually gets to .B xa itself for processing. .LP -The following preprocessor directives are supported. - +The following predefined macros are supported, except if +.B \-XXA23 +is specified: +.TP +.B XA_MAJOR +The current major version of +.BR xa . +.TP +.B XA_MINOR +The current minor version of +.BR xa . +.LP +The following preprocessor directives are supported: .TP .B #include """filename""" Inserts the contents of file @@ -691,6 +916,9 @@ Computes the value of expression .B expression and prints it into the errorlog file. .TP +.B #error message +Displays the message as an error and terminates assembly. +.TP .B #define DEFINE text Equates macro .B DEFINE @@ -724,12 +952,6 @@ satisfied, then the source code between the directive and its terminating .B #endif are expunged and not assembled. Up to fifteen levels of nesting are supported. .TP -.B #endif -Closes a conditional block. -.TP -.B #else -Implements alternate path for a conditional block. -.TP .B #ifdef DEFINE True only if macro .B DEFINE @@ -760,6 +982,12 @@ is defined .I and assigned with a value. .I This works on labels, not macros! +.TP +.B #else +Implements alternate path for a conditional block. +.TP +.B #endif +Closes a conditional block. .LP Unclosed conditional blocks at the end of included files generate warnings; unclosed conditional blocks at the end of assembly generate an error. @@ -920,8 +1148,8 @@ and use two eight bit parameters, the only instructions in the entire instruction set to do so. Older versions of .B xa -took a single 16-bit absolute value. Since 2.3.7, the standard syntax is -now accepted and the old syntax is deprecated (a warning will be generated). +took a single 16-bit absolute value. As of 2.4.0, this old syntax is +no longer accepted. .LP Forward-defined labels -- that is, labels that are defined after the current instruction is processed -- cannot be optimized into zero @@ -943,31 +1171,6 @@ Indiscriminately forcing the issue can be fraught with peril, however, and is not recommended; to discourage this, the assembler will complain about its use in addressing mode situations where no ambiguity exists, such as indirect indexed, branching and so on. -.LP -Also, as a further consequence of the way optimization is managed, we repeat -that -.B all -24-bit quantities and labels that reference a 24-bit quantity in 65816 mode, -anteriorly declared or otherwise, -.B MUST -be prepended with the -.B @ -prefix. Otherwise, the assembler will attempt to optimize to 16 bits, which -may be undesirable. - -.SH "IMMINENT DEPRECATION" -The following options and modes will be -.B REMOVED -in 2.4 and later versions of -.BR xa : -.LP -.B \-x -.LP -.B \-S -.LP -the original -.B mvn $xxxx -syntax .SH "SEE ALSO" .BR file65 (1), @@ -985,7 +1188,7 @@ Original xa package (C)1989-1997 Andre Fachat. Additional changes (C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall, Cameron Kaiser. The official maintainer is Cameron Kaiser. -.SH 30 YEARS OF XA +.SH OVER 30 YEARS OF XA Yay us? .SH WEBSITE diff --git a/xa/misc/Makefile b/xa/misc/Makefile index 2b450e0..1025094 100644 --- a/xa/misc/Makefile +++ b/xa/misc/Makefile @@ -2,7 +2,7 @@ XCBMLIB = .. # -Wall -ansi et al. cause compile problems. -CFLAGS = -O2 +CFLAGS = -O2 -g LIBS = #-lncurses -ltermcap -lm diff --git a/xa/misc/file65.c b/xa/misc/file65.c index cec2d98..064f588 100644 --- a/xa/misc/file65.c +++ b/xa/misc/file65.c @@ -48,6 +48,8 @@ int rompar = 0; int romoff = 0; int labels = 0; +int verbose = 0; + void usage(FILE *fp) { fprintf(fp, @@ -62,13 +64,14 @@ void usage(FILE *fp) " in the same ROM. Add offset to start address.\n" " -A offset same as `-a', but only print the start address of the next\n" " file in the ROM\n" - " -V print undefined and global labels\n" + " -v print undefined and global labels\n" + " -vv print undefined and global labels, and relocation tables\n" " --version output version information and exit\n" " --help display this help and exit\n"); } int main(int argc, char *argv[]) { - int i = 1, n, mode, hlen; + int i, j, n, mode, hlen; FILE *fp; char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"}; if(argc<=1) { @@ -76,12 +79,14 @@ int main(int argc, char *argv[]) { exit(1); } - if (strstr(argv[1], "--help")) { + i = 1; + + if (strstr(argv[i], "--help") || strstr(argv[i], "-?")) { usage(stdout); exit(0); } - if (strstr(argv[1], "--version")) { + if (strstr(argv[i], "--version")) { version(programname, progversion, author, copyright); exit(0); } @@ -90,11 +95,12 @@ int main(int argc, char *argv[]) { if(argv[i][0]=='-') { /* process options */ switch(argv[i][1]) { - case 'V': - labels = 1; - break; case 'v': - printf("file65: Version 0.2\n"); + j = 1; + while (argv[i][j] == 'v') { + verbose ++; + j++; + } break; case 'a': case 'A': @@ -142,7 +148,7 @@ int main(int argc, char *argv[]) { printf(" zero segment @ $%04x - $%04x [$%04x bytes]\n", hdr[21]*256+hdr[20], hdr[21]*256+hdr[20]+hdr[23]*256+hdr[22], hdr[23]*256+hdr[22]); printf(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24], (hdr[25]*256+hdr[24])==0?"(i.e. unknown)":""); - if(labels) { + if(verbose) { read_options(fp); print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]); } @@ -231,13 +237,13 @@ void print_option(unsigned char *buf, int len) { } int read_options(FILE *fp) { - int c, l=0; + int c, d, l=0; unsigned char tb[256]; c=fgetc(fp); l++; while(c && c!=EOF) { c&=255; - fread(tb, 1, c-1, fp); + d = fread(tb, 1, c-1, fp); if(labels) print_option(tb, c); l+=c; c=fgetc(fp); @@ -247,11 +253,17 @@ int read_options(FILE *fp) { int print_labels(FILE *fp, int offset) { int i, nud, c, seg, off; + const char *segments[] = { "undef", "abs", "text", "data", "bss", "zero" }; + const char *reltype[] = { "-", "LOW", "HIGH", "-", "WORD", "SEG", "SEGADDR" }; + /* printf("print_labels:offset=%d\n",offset); */ fseek(fp, offset, SEEK_CUR); + // ----------------------------------------------------------- + // print undefined labels + nud = (fgetc(fp) & 0xff); nud += ((fgetc(fp) << 8) & 0xff00); @@ -269,25 +281,59 @@ printf("print_labels:offset=%d\n",offset); printf("\n"); } + // --------------------------------------------------------- + // skip relocation tables + + // two tables, one for text one for data for(i=0;i<2;i++) { + unsigned char lowbyte; + unsigned short index; + unsigned short offset = 0; + + if (verbose > 1) { + printf("Relocation table for %s:\n", i ? "text":"data"); + } + c=fgetc(fp); while(c && c!=EOF) { c&= 0xff; while(c == 255 && c!= EOF) { + offset += 254; c=fgetc(fp); if(c==EOF) break; c&= 0xff; } if(c==EOF) break; + offset += c; c=fgetc(fp); - if( (c & 0xe0) == 0x40 ) fgetc(fp); - if( (c & 0x07) == 0 ) { fgetc(fp); fgetc(fp); } - + if( (c & 0xe0) == 0x40 ) { + lowbyte = fgetc(fp); + } + if( (c & 0x07) == 0 ) { + index = fgetc(fp) & 0xff; + index += (fgetc(fp) & 0xff) << 8; + } + if (verbose > 1) { + printf("\t%d:%s(%s (%d)", offset, reltype[ (c>>5) & 0xf], segments[c & 0x07], (c&0x07)); + if ( (c & 0xe0) == 0x40) { + printf(", %02x", lowbyte); + } + if ( (c & 0x07) == 0) { + printf(", %04x", index); + } + printf(")"); + } c=fgetc(fp); } + if (verbose > 1) { + printf("\n"); + } } + + // --------------------------------------------------------- + // print global labels nud = (fgetc(fp) & 0xff); nud += ((fgetc(fp) << 8) & 0xff00); printf("Global Labels: %d\n", nud); diff --git a/xa/misc/ldo65.c b/xa/misc/ldo65.c index 7dd6cdc..32ae45b 100644 --- a/xa/misc/ldo65.c +++ b/xa/misc/ldo65.c @@ -3,7 +3,7 @@ * * A part of the xa65 - 65xx/65816 cross-assembler and utility suite * - * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * Copyright (C) 1997-2023 André Fachat (fachat@web.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,13 +34,31 @@ #define BUF (9*2+8) /* 16 bit header */ #define programname "ldo65" -#define progversion "v0.1.1" +#define progversion "v0.2.0" #define author "Written by Andre Fachat" -#define copyright "Copyright (C) 1997-2002 Andre Fachat. Formerly ld65." +#define copyright "Copyright (C) 1997-2023 Andre Fachat. Formerly ld65." + +#undef DEBUG + +/* + +The process of linking works as follows: + +1. Every file is loaded in turn via load_file() +2. Calculate new base addresses per segment +3. Merge all globals from all files into a single table, checking for duplicates +4. Resolve undefined labels, and merge remaining into global list +5. relocate all segments, create global relocation tables +6. verify undefined labels +7. write out target file + +*/ typedef struct { char *name; int len; + int newidx; /* index in new global undef table (for reloc) */ + int resolved; /* index in current global label table after resolve (-1 is not found) */ } undefs; /* file information */ @@ -70,9 +88,6 @@ typedef struct { int drpos; /* position of data reloc tab in file */ int gpos; /* position of globals list in file */ - int lasttreloc; - int lastdreloc; - int nundef; /* number of undefined labels */ undefs *ud; /* undefined labels list NULL if none */ } file65; @@ -87,22 +102,30 @@ typedef struct { file65 *file; /* in which file is it? */ } glob; + file65 *load_file(char *fname); int read_options(unsigned char *f); int read_undef(unsigned char *f, file65 *fp); +int write_undef(FILE *f, file65 *fp); +int check_undef(file65 *fp, char *defined[], int ndefined); int len_reloc_seg(unsigned char *buf, int ri); -int reloc_seg(unsigned char *buf, int adr, int ri, int *lreloc, file65 *fp); +int reloc_seg(unsigned char *buf, int pos, int addr, int rdiff, int ri, unsigned char *obuf, int *lastaddrp, int *rop, file65 *fp); unsigned char *reloc_globals(unsigned char *, file65 *fp); int read_globals(file65 *file); int write_options(FILE *fp, file65 *file); int write_reloc(file65 *fp[], int nfp, FILE *f); int write_globals(FILE *fp); +int write_nglobals(FILE *fp, char **globdef, int nglobal); +int find_global(unsigned char *name); +int resolve_undef(file65 *file, int *remains); file65 file; unsigned char cmp[] = { 1, 0, 'o', '6', '5' }; unsigned char hdr[26] = { 1, 0, 'o', '6', '5', 0 }; +int verbose = 0; + void usage(FILE *fp) { fprintf(fp, @@ -114,6 +137,10 @@ void usage(FILE *fp) " address `addr'\n" " -o file uses `file' as output file. Default is `a.o65'\n" " -G suppress writing of globals\n" + " -U accept any undef'd labels after linking\n" + " -L accept specific given undef'd labels after linking\n" + " -g only export the globals defined with (multiple) -g options\n" + " -v verbose output\n" " --version output version information and exit\n" " --help display this help and exit\n", programname); @@ -121,20 +148,35 @@ void usage(FILE *fp) int main(int argc, char *argv[]) { int noglob=0; + int undefok=0; int i = 1; int tbase = 0x0400, dbase = 0x1000, bbase = 0x4000, zbase = 0x0002; - int ttlen, tdlen, tblen, tzlen; + int ttlen, tdlen, tblen, tzlen, routtlen, routdlen, tro, dro; + int lasttaddr, lastdaddr; + unsigned char *treloc, *dreloc; char *outfile = "a.o65"; int j, jm; file65 *file, **fp = NULL; FILE *fd; + int nundef = 0; // counter/index in list of remaining undef'd labels + + char *arg; + + char **defined = NULL; + int ndefined = 0; + int ndefalloc = 0; + + // globals allowed by -g + char **globdef = NULL; + int nglobal = 0; + int ngloballoc = 0; if (argc <= 1) { usage(stderr); exit(1); } - if (strstr(argv[1], "--help")) { + if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) { usage(stdout); exit(0); } @@ -148,13 +190,50 @@ int main(int argc, char *argv[]) { while(i= ngloballoc) { + ngloballoc *= 2; + globdef = realloc(globdef, ngloballoc * sizeof(char*)); + } + globdef[nglobal++] = arg; + break; + case 'L': + if(argv[i][2]) arg=argv[i]+2; + else arg=argv[++i]; + if (ndefalloc == 0) { + ndefalloc = 20; + defined = malloc(ndefalloc * sizeof(char*)); + } else + if (ndefined >= ndefalloc) { + ndefalloc *= 2; + defined = realloc(defined, ndefalloc * sizeof(char*)); + } + defined[ndefined++] = arg; + break; case 'b': switch(argv[i][2]) { case 't': @@ -184,6 +263,10 @@ int main(int argc, char *argv[]) { } i++; } + + // ------------------------------------------------------------------------- + // step 1 - load files + /* each file is loaded first */ j=0; jm=0; fp=NULL; while(i=jm) fp=realloc(fp, (jm=(jm?jm*2:10))*sizeof(file65*)); if(!fp) { fprintf(stderr,"Oops, no more memory\n"); exit(1); } fp[j++] = f; - } + } else { + exit(1); + } i++; } + // ------------------------------------------------------------------------- + // step 2 - calculate new segment base addresses per file, by + // concatenating the segments per type + /* now [tdbz]base holds new segment base address */ /* set total length to zero */ ttlen = tdlen = tblen = tzlen = 0; @@ -210,43 +299,178 @@ int main(int argc, char *argv[]) { file->ddiff = ((dbase + tdlen) - file->dbase); file->bdiff = ((bbase + tblen) - file->bbase); file->zdiff = ((zbase + tzlen) - file->zbase); -/*printf("tbase=%04x, file->tbase=%04x, ttlen=%04x -> tdiff=%04x\n", - tbase, file->tbase, ttlen, file->tdiff);*/ + +/* +printf("tbase=%04x+len=%04x->%04x, file->tbase=%04x, f.tlen=%04x -> tdiff=%04x\n", + tbase, ttlen, (tbase + ttlen), file->tbase, file->tlen, file->tdiff); +printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n", + zbase, tzlen, (zbase + tzlen), file->zbase, file->zlen, file->zdiff); +*/ + + if (verbose > 0) { + printf("Relocating file: %s\n", file->fname); + printf(" text: from %04x to %04x (diff is %04x, length is %04x)\n", + file->tbase, file->tbase + file->tdiff, file->tdiff, file->tlen); + printf(" data: from %04x to %04x (diff is %04x, length is %04x)\n", + file->dbase, file->dbase + file->ddiff, file->ddiff, file->dlen); + printf(" bss: from %04x to %04x (diff is %04x, length is %04x)\n", + file->bbase, file->bbase + file->bdiff, file->bdiff, file->blen); + printf(" zero: from %02x to %02x (diff is %02x, length is %02x)\n", + file->zbase, file->zbase + file->zdiff, file->zdiff, file->zlen); + } /* update globals (for result file) */ ttlen += file->tlen; tdlen += file->dlen; tblen += file->blen; tzlen += file->zlen; + } + // validate various situations. + { + int er = 0; + if (tbase + ttlen > 0x10000) { + fprintf(stderr, + "Overflow in text segment: end at %06x behind 64k limit\n", + tbase + ttlen); + er = 1; + } + if (dbase + tdlen > 0x10000) { + fprintf(stderr, + "Overflow in data segment: end at %06x behind 64k limit\n", + dbase + tdlen); + er = 1; + } + if (bbase + tblen > 0x10000) { + fprintf(stderr, + "Overflow in bss segment: end at %06x behind 64k limit\n", + bbase + tblen); + er = 1; + } + if (zbase + tzlen > 0x100) { + fprintf(stderr, + "Overflow in zero segment: end at %04x behind 256 byte limit\n", + zbase + tzlen); + er = 1; + } + if (er) { + exit (1); + } + } + + // ------------------------------------------------------------------------- + // step 3 - merge globals from all files into single table + // + + for(i=0;ibuf, - file->tpos, - file->trpos, - &(file->lasttreloc), + routtlen += (file->drpos - file->trpos); + routdlen += (file->gpos - file->drpos); + + reloc_globals(file->buf+file->gpos, file); + } + + // prep global reloc tables + treloc = malloc(routtlen); + dreloc = malloc(routdlen); + +#ifdef DEBUG + printf("prep'd text reloc table at %p (%d bytes)\n", treloc, routtlen); + printf("prep'd data reloc table at %p (%d bytes)\n", dreloc, routdlen); +#endif + tro = 0; + dro = 0; + + // segment position of last relocation entry to compute offsets across files + lasttaddr = tbase - 1; + lastdaddr = dbase - 1; + + for(i=0;ibuf, // input buffer + file->tpos, // position of segment in input buffer + file->tbase, // segment base address + file->tdiff, // reloc difference + file->trpos, // position of reloc table in input + treloc, // output reloc buffer + &lasttaddr, // last relocated target address + &tro, // pointer in output reloc bufer file); + reloc_seg(file->buf, file->dpos, + file->dbase, + file->ddiff, file->drpos, - &(file->lastdreloc), + dreloc, + &lastdaddr, + &dro, file); - reloc_globals(file->buf+file->gpos, file); + // change file information to relocated values file->tbase += file->tdiff; file->dbase += file->ddiff; file->bbase += file->bdiff; file->zbase += file->zdiff; - - file->lasttreloc += file->tbase - file->tpos; - file->lastdreloc += file->dbase - file->dpos; - } + // finalize global reloc table + treloc[tro++] = 0; + dreloc[dro++] = 0; + + // ------------------------------------------------------------------------- + // step 6 - validate undefined labels + // + + if (nundef > 0 && !undefok) { + int er = 0; + // we have undefined labels, but it's not ok (no -U) + // check -L defined labels + for(i=0;i>8) & 255; hdr[10] = ttlen & 255; hdr[11] = (ttlen >>8)& 255; @@ -258,32 +482,56 @@ int main(int argc, char *argv[]) { hdr[22] = tzlen & 255; hdr[23] = (tzlen >>8)& 255; hdr[24] = 0; hdr[25] = 0; + // open file fd = fopen(outfile, "wb"); if(!fd) { fprintf(stderr,"Couldn't open output file %s (%s)\n", outfile, strerror(errno)); exit(2); } + + // write header fwrite(hdr, 1, 26, fd); - /* this writes _all_ options from _all_files! */ + + // write options - this writes _all_ options from _all_files! for(i=0;ibuf + fp[i]->tpos, 1, fp[i]->tlen, fd); } - /* write data segment */ + + // write data segment for(i=0;ibuf + fp[i]->dpos, 1, fp[i]->dlen, fd); } - write_reloc(fp, j, fd); + + // write list of undefined labels + fputc(nundef & 0xff,fd); + fputc((nundef >> 8) & 0xff,fd); + if (nundef > 0) { + for(i=0;i 0) { + write_nglobals(fd, globdef, nglobal); + } else { + fputc(0,fd); + fputc(0,fd); + } } fclose(fd); @@ -308,35 +556,120 @@ int read_options(unsigned char *buf) { return ++l; } +/***************************************************************************/ + int read_undef(unsigned char *buf, file65 *file) { - int i, n, l = 2, ll; + int bufp; // pointer in input buffer + int startp; // pointer to start of label name + int nlabels; // number of labels in file + undefs *current = NULL; + int i; - n = buf[0] + 256*buf[1]; + bufp = 0; + nlabels = buf[bufp] + 256*buf[bufp+1]; + bufp += 2; - file->nundef = n; + file->nundef = nlabels; - if (n == 0) { + if (nlabels == 0) { file->ud = NULL; } else { - file->ud = malloc(n*sizeof(undefs)); + file->ud = malloc(nlabels*sizeof(undefs)); if(!file->ud) { fprintf(stderr,"Oops, no more memory\n"); exit(1); } i=0; - while(iud[i].name = (char*) buf+l; - ll=l; - while(buf[l++]); - file->ud[i].len = l-ll-1; + while(iud[i]; + current->name = (char*) buf+startp; + current->len = bufp-startp-1; + current->resolved = -1; /*printf("read undef '%s'(%p), len=%d, ll=%d, l=%d, buf[l]=%d\n", file->ud[i].name, file->ud[i].name, file->ud[i].len,ll,l,buf[l]);*/ i++; } } - return l; + return bufp; } +int resolve_undef(file65 *file, int *remains) { + int i; + undefs *current; + int nlabels = file->nundef; +#ifdef DEBUG +printf("resolved undef file %s (%d undef'd)\n", file->fname, nlabels); +#endif + if (nlabels == 0) { + return 0; + } + current = file->ud; + + for (i = 0; i < nlabels; i++) { + // store pointer to global in label info + // if NULL is returned, is not resolved + current->resolved = find_global(current->name); +#ifdef DEBUG +printf("resolved undef label %s to: resolved=%d, newidx=%d\n", current->name, current->resolved, *remains); +#endif + if (current->resolved == -1) { + // keep in global undef list + current->newidx = *remains; + *remains += 1; + } + current++; + } + return 0; +} + + +int write_undef(FILE *f, file65 *fp) { + int i; + for (i = 0; i < fp->nundef; i++) { + undefs *current = &fp->ud[i]; + + if (current->resolved == -1) { + // only write unresolved entries + fprintf(f, "%s%c", current->name, 0); + } + } + return 0; +} + +int check_undef(file65 *fp, char *defined[], int ndefined) { + + int er = 0; + int i, j; + for (i = 0; i < fp->nundef; i++) { + undefs *current = &fp->ud[i]; + + if (current->resolved == -1) { + // only check unresolved entries + int found = 0; + for (j = 0; j < ndefined; j++) { + if (defined && !strcmp(defined[j], current->name)) { + // label is found, so it's ok + found = 1; + break; + } + } + if (!found) { + fprintf(stderr, "Unresolved label '%s' from file '%s'\n", + current->name, fp->fname); + er = -1; + } + } + } + return er; +} + + +/***************************************************************************/ + /* compute and return the length of the relocation table */ int len_reloc_seg(unsigned char *buf, int ri) { int type, seg; @@ -369,17 +702,21 @@ int len_reloc_seg(unsigned char *buf, int ri) { unsigned char *reloc_globals(unsigned char *buf, file65 *fp) { int n, old, new, seg; + char *name; n = buf[0] + 256*buf[1]; buf +=2; while(n) { -/*printf("relocating %s, ", buf);*/ + name = buf; while(*(buf++)); - seg = *buf; + seg = *buf & 0x07; old = buf[1] + 256*buf[2]; new = old + reldiff(seg); -/*printf("old=%04x, seg=%d, rel=%04x, new=%04x\n", old, seg, reldiff(seg), new);*/ + if (verbose > 1) { + printf("%s:%s: old=%04x, seg=%d, rel=%04x, new=%04x\n", + fp->fname, name, old, seg, reldiff(seg), new); + } buf[1] = new & 255; buf[2] = (new>>8) & 255; buf +=3; @@ -438,7 +775,7 @@ file65 *load_file(char *fname) { file->bbase = file->buf[17]*256+file->buf[16]; file->blen = file->buf[19]*256+file->buf[18]; file->zbase = file->buf[21]*256+file->buf[20]; - file->zlen = file->buf[23]*256+file->buf[21]; + file->zlen = file->buf[23]*256+file->buf[22]; file->tpos = hlen; file->dpos = hlen + file->tlen; @@ -447,99 +784,26 @@ file65 *load_file(char *fname) { file->drpos= len_reloc_seg(file->buf, file->trpos); file->gpos = len_reloc_seg(file->buf, file->drpos); } - } else - fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno)); - } else + } else { + fprintf(stderr,"Error: %s: not an o65 file\n", fname); + return NULL; + } + } else { fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno)); - + return NULL; + } return file; } /***************************************************************************/ +// global list of all global labels glob *gp = NULL; -int gm=0; +// number of global labels int g=0; +// number of globals for which memory is already allocated +int gm=0; -int write_reloc(file65 *fp[], int nfp, FILE *f) { - int tpc, pc, i; - unsigned char *p; - int low = 0, seg, typ, lab; - - /* no undefined labels ? TODO */ - fputc(0,f); - fputc(0,f); - - tpc = fp[0]->tbase-1; - - for(i=0;itbase-1; - p = fp[i]->buf + fp[i]->trpos; - - while(*p) { - while((*p)==255) { pc+=254; p++; } - pc+=*(p++); - seg=(*p)&7; - typ=(*p)&0xe0; - if(typ==0x40) low=*(++p); - p++; - if(seg==0) { - lab=p[0]+256*p[1]; - seg=gp[lab].seg; - p+=2; - } - if(seg>1) { - while(pc-tpc>254) { - fputc(255,f); - tpc+=254; - } - fputc(pc-tpc, f); - tpc=pc; - fputc(typ | seg, f); - if(typ==0x40) { - fputc(low,f); - } - } - } - } - fputc(0,f); - - tpc = fp[0]->dbase-1; - - for(i=0;idbase-1; - p = fp[i]->buf + fp[i]->drpos; - - while(*p) { - while((*p)==255) { pc+=254; p++; } - pc+=*(p++); - seg=(*p)&7; - typ=(*p)&0xe0; - if(typ==0x40) low=*(++p); - p++; - if(seg==0) { - lab=p[0]+256*p[1]; - seg=gp[lab].seg; - p+=2; - } - if(seg>1) { - while(pc-tpc>254) { - fputc(255,f); - tpc+=254; - } - fputc(pc-tpc, f); - tpc=pc; - fputc(typ | seg, f); - if(typ==0x40) { - fputc(low,f); - } - } - } - } - fputc(0,f); - - return 0; -} int write_globals(FILE *fp) { int i; @@ -554,6 +818,55 @@ int write_globals(FILE *fp) { return 0; } +int write_nglobals(FILE *fp, char **globdef, int nglobal) { + int i, j; + int newnum = 0; + + // first check which defined globals are allowed to be exported + // and clear out the other ones + for (i = 0; i < g; i++) { + for (j = 0; j < nglobal; j++) { + if (!strcmp(gp[i].name, globdef[j])) { + // found + break; + } + } + if (j >= nglobal) { + // not found + gp[i].name = NULL; + } else { + // found, so we inc the counter + newnum++; + } + } + + // then check which globals from the -g list are actually used, and warn about unused ones + for (j = 0; j < nglobal; j++) { + for (i = 0; i < g; i++) { + if (gp[i].name != NULL && !strcmp(gp[i].name, globdef[j])) { + // found + break; + } + } + if (i >= g) { + // not found + fprintf(stderr,"Warning: command line allowed global '%s' is not defined!\n", globdef[j]); + } + } + + // write out only defined globals + fputc(newnum&255, fp); + fputc((newnum>>8)&255, fp); + + for(i=0;i>8)&255); + } + } + return 0; +} + int read_globals(file65 *fp) { int i, l, n, old, new, seg, ll; char *name; @@ -602,8 +915,10 @@ int read_globals(file65 *fp) { gp[g].val = new; gp[g].fl = 0; gp[g].file = fp; -/*printf("set label '%s' (l=%d, seg=%d, val=%04x)\n", gp[g].name, - gp[g].len, gp[g].seg, gp[g].val);*/ +#ifdef DEBUG +printf("set global label '%s' (l=%d, seg=%d, val=%04x)\n", gp[g].name, + gp[g].len, gp[g].seg, gp[g].val); +#endif g++; } @@ -613,7 +928,21 @@ int read_globals(file65 *fp) { return 0; } -int find_global(unsigned char *bp, file65 *fp, int *seg) { +int find_global(unsigned char *name) { + int i; + for (i = 0; i < g; i++) { + + if (!strcmp(gp[i].name, name)) { + // found + return i; + } + } + return -1; +} + +// searches for a global label in a file by name. +// returns the value of a found global value +int find_file_global(unsigned char *bp, file65 *fp, int *seg) { int i,l; char *n; int nl = bp[0]+256*bp[1]; @@ -635,64 +964,177 @@ int find_global(unsigned char *bp, file65 *fp, int *seg) { return 0; } -int reloc_seg(unsigned char *buf, int pos, int ri, int *lreloc, file65 *fp) { - int type, seg, old, new; +/***************************************************************************/ + +#define forwardpos() \ + while(addr-lastaddr>254){obuf[ro++]=255;lastaddr+=254;}obuf[ro++]=addr-lastaddr;lastaddr=addr + +int reloc_seg(unsigned char *buf, int pos, int addr, int rdiff, int ri, + unsigned char *obuf, int *lastaddrp, int *rop, file65 *fp) { + int type, seg, old, new, ro, lastaddr, diff; + int base; /* - pos = position of segment in *buf - ri = position of relocation table in *buf + pos = address of current position + ri = position of relocation table in *buf for reading the reloc entries + ro(p) = position of relocation table entry for writing the modified entries */ - pos--; -/*printf("reloc_seg: adr=%04x, tdiff=%04x, ddiff=%04x, bdiff=%04x, zdiff=%04x\n", pos, fp->tdiff, fp->ddiff, fp->bdiff, fp->zdiff); */ + base = addr; + addr--; + ro = *rop; + lastaddr = *lastaddrp - rdiff; + +#ifdef DEBUG +printf("reloc_seg: %s: addr=%04x, pos=%04x, lastaddr=%04x (%04x - %04x)\n", + fp->fname, addr, pos, lastaddr, *lastaddrp, rdiff); +#endif + while(buf[ri]) { + // still reloc entry if((buf[ri] & 255) == 255) { - pos += 254; + addr += 254; ri++; } else { - pos += buf[ri] & 255; - ri++; - type = buf[ri] & 0xe0; - seg = buf[ri] & 0x07; -/*printf("reloc entry @ ri=%04x, pos=%04x, type=%02x, seg=%d\n",ri, pos, type, seg);*/ - ri++; + addr += buf[ri] & 255; + type = buf[ri+1] & 0xe0; + seg = buf[ri+1] & 0x07; +#ifdef DEBUG +printf("reloc entry @ ri=%04x, pos=%04x, type=%02x, seg=%d, offset=%d, reldiff=%04x\n", + ri, pos, type, seg, addr-lastaddr, reldiff(seg)); +#endif switch(type) { case 0x80: - old = buf[pos] + 256*buf[pos+1]; + // address (word) relocation + old = buf[addr-base+pos] + 256*buf[addr-base+pos+1]; if(seg) { - new = old + reldiff(seg); + diff = reldiff(seg); + ri++; // skip position byte + forwardpos(); // re-write position offset + obuf[ro++] = buf[ri++]; // relocation byte ($8x for segments text, data, bss, zp) } else { - new = old + find_global(buf+ri, fp, &seg); - ri += 2; /* account for label number */ + // undefined + undefs *u = &fp->ud[buf[ri+2]+256*buf[ri+3]]; +#ifdef DEBUG +printf("found undef'd label %s, resolved=%d, newidx=%d, (ri=%d, ro=%d)\n", u->name, u->resolved, u->newidx, ri, ro); +#endif + if (u->resolved == -1) { + // not resolved + diff = 0; + ri++; // skip position byte + forwardpos(); // re-write position offset + obuf[ro++] = buf[ri++]; // relocation byte ($8x for segments text, data, bss, zp) + obuf[ro++] = u->newidx & 0xff; // output label number lo/hi + obuf[ro++] = (u->newidx >> 8) & 0xff; + ri += 2; // acount for label number in input + } else { + // resolved from global list + glob *gl = &gp[u->resolved]; + diff = gl->val; + seg = gl->seg; + if (seg != 1) { + // not an absolute value + forwardpos(); // re-write position offset + obuf[ro++] = 0x80 | seg;// relocation byte for new segment + } else { + // absolute value - do not write a new relocation entry + } + ri += 4; // account for position, segment byte, label number in reloc table + } } + new = old + diff; /*printf("old=%04x, new=%04x\n",old,new);*/ - buf[pos] = new & 255; - buf[pos+1] = (new>>8)&255; + buf[addr-base+pos] = new & 255; + buf[addr-base+pos+1] = (new>>8)&255; break; case 0x40: - old = buf[pos]*256 + buf[ri]; + // high byte relocation if(seg) { - new = old + reldiff(seg); + old = buf[addr-base+pos]*256 + buf[ri+2]; + diff = reldiff(seg); + forwardpos(); // re-write position offset + obuf[ro++] = buf[ri+1]; // relocation byte ($4x for segments text, data, bss, zp) + obuf[ro++] = (old + diff) & 255; + ri += 3; // skip position, segment, and low byte } else { - new = old + find_global(buf+ri+1, fp, &seg); - ri += 2; /* account for label number */ + undefs *u; + old = buf[addr-base+pos]*256 + buf[ri+4]; + // undefined + u = &fp->ud[buf[ri+2]+256*buf[ri+3]]; + if (u->resolved == -1) { + // not resolved + diff = 0; + forwardpos(); // re-write position offset + obuf[ro++] = buf[ri+1]; // relocation byte ($8x for segments text, data, bss, zp) + obuf[ro++] = u->newidx & 0xff; // output label number lo/hi + obuf[ro++] = (u->newidx >> 8) & 0xff; + obuf[ro++] = buf[ri+4]; // low byte for relocation + } else { + // resolved from global list + glob *gl = &gp[u->resolved]; + diff = gl->val; + seg = gl->seg; + if (seg != 1) { + // not an absolute value + forwardpos(); // re-write position offset + obuf[ro++] = 0x40 | seg; // relocation byte for new segment + obuf[ro++] = (old + diff) & 0xff; // low byte for relocation + } else { + // absolute value - do not write a new relocation entry + } + } + ri += 5; // account for position, segment byte, label number in reloc table, low byte } - buf[pos] = (new>>8)&255; - buf[ri] = new & 255; - ri++; + new = old + diff; + buf[addr-base+pos] = (new>>8)&255; break; case 0x20: - old = buf[pos]; + // low byte relocation + old = buf[addr-base+pos]; + diff = 0; if(seg) { - new = old + reldiff(seg); + diff = reldiff(seg); + forwardpos(); + obuf[ro++] = buf[ri+1]; // relocation byte ($4x for segments text, data, bss, zp) + ri += 2; // account for position & segment } else { - new = old + find_global(buf+ri, fp, &seg); - ri += 2; /* account for label number */ + // undefined + undefs *u = &fp->ud[buf[ri+2]+256*buf[ri+3]]; + if (u->resolved == -1) { + // not resolved + diff = 0; + forwardpos(); // re-write position offset + obuf[ro++] = buf[ri+1]; // relocation byte ($8x for segments text, data, bss, zp) + obuf[ro++] = u->newidx & 0xff; // output label number lo/hi + obuf[ro++] = (u->newidx >> 8) & 0xff; + } else { + // resolved from global list + glob *gl = &gp[u->resolved]; + diff = gl->val; + seg = gl->seg; + if (seg != 1) { + // not an absolute value + forwardpos(); // re-write position offset + obuf[ro++] = 0x20 | seg; // relocation byte for new segment + } else { + // absolute value - do not write a new relocation entry + } + } + ri += 4;// account for position, segment byte, label number in reloc table } - buf[pos] = new & 255; + new = old + diff; + buf[addr-base+pos] = new & 255; break; } } } - *lreloc = pos; + + *lastaddrp = lastaddr + rdiff; + *rop = ro; +#ifdef DEBUG + printf(" --> lastaddr=%04x (%04x - %04x), rop=%d\n", lastaddr, *lastaddrp, rdiff, ro); +#endif return ++ri; } + + + diff --git a/xa/misc/printcbm.c b/xa/misc/printcbm.c index 6a075e5..e00124b 100644 --- a/xa/misc/printcbm.c +++ b/xa/misc/printcbm.c @@ -46,6 +46,8 @@ void usage(FILE *fp) fprintf(fp, "Usage: %s [OPTION]... [FILE]...\n" "List CBM BASIC programs\n" + "This tool is deprecated as of xa 2.4 and will be removed in a future version.\n" + "Please consider migrating to VICE petcat, which has many more options.\n" "\n" " --version output version information and exit\n" " --help display this help and exit\n", @@ -62,7 +64,7 @@ int main(int argc, char *argv[]) exit(1); } - if (strstr(argv[1], "--help")) { + if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) { usage(stdout); exit(0); } diff --git a/xa/misc/reloc65.c b/xa/misc/reloc65.c index bd00eb0..7d4dec6 100644 --- a/xa/misc/reloc65.c +++ b/xa/misc/reloc65.c @@ -74,6 +74,7 @@ void usage(FILE *fp) " -X extracts the file such that text and data\n" " segments are chained, i.e. possibly relocating\n" " the data segment to the end of the text segment\n" + " -v verbose output\n" " --version output version information and exit\n" " --help display this help and exit\n"); } @@ -87,13 +88,14 @@ int main(int argc, char *argv[]) { int *base; char *outfile = "a.o65"; int extract = 0; + int verbose = 0; if (argc <= 1) { usage(stderr); exit(1); } - if (strstr(argv[1], "--help")) { + if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) { usage(stdout); exit(0); } @@ -107,6 +109,9 @@ int main(int argc, char *argv[]) { if(argv[i][0]=='-') { /* process options */ switch(argv[i][1]) { + case 'v': + verbose = 1; + break; case 'o': if(argv[i][2]) outfile=argv[i]+2; else if(i + 1 < argc) outfile=argv[++i]; @@ -192,25 +197,53 @@ int main(int argc, char *argv[]) { file.tbase = file.buf[ 9]*256+file.buf[ 8]; file.tlen = file.buf[11]*256+file.buf[10]; - file.tdiff = tflag? tbase - file.tbase : 0; + file.tdiff = tflag ? tbase - file.tbase : 0; + file.dbase = file.buf[13]*256+file.buf[12]; file.dlen = file.buf[15]*256+file.buf[14]; + file.ddiff = dflag ? dbase - file.dbase : 0; if (extract == 3) { if (dflag) { - fprintf(stderr,"reloc65: %s: Warning: data segment address ignored for -X option\n", argv[i]); - } - dbase = file.tbase + file.tdiff + file.tlen; - file.ddiff = dbase - file.dbase; - } else { - file.ddiff = dflag? dbase - file.dbase : 0; + fprintf(stderr,"reloc65: %s: Warning: data segment address overrides -X option\n", argv[i]); + } else { + dbase = file.tbase + file.tdiff + file.tlen; + file.ddiff = dbase - file.dbase; + } } + file.bbase = file.buf[17]*256+file.buf[16]; file.blen = file.buf[19]*256+file.buf[18]; - file.bdiff = bflag? bbase - file.bbase : 0; - file.zbase = file.buf[21]*256+file.buf[20]; - file.zlen = file.buf[23]*256+file.buf[21]; - file.zdiff = zflag? zbase - file.zbase : 0; + file.bdiff = bflag ? bbase - file.bbase : 0; + if (extract == 3) { + if (bflag) { + fprintf(stderr,"reloc65: %s: Warning: bss segment address overrides -X option\n", argv[i]); + } else { + bbase = file.dbase + file.ddiff + file.dlen; + file.bdiff = bbase - file.bbase; + } + } + file.zbase = file.buf[21]*256+file.buf[20]; + file.zlen = file.buf[23]*256+file.buf[22]; + file.zdiff = zflag ? zbase - file.zbase : 0; + + if (verbose) { + printf("Relocating segments to:\n"); + printf("text segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.tbase + file.tdiff, file.tbase + file.tdiff + file.tlen, + file.tlen, file.tlen, file.tdiff, file.tdiff & 0xffff); + printf("data segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.dbase + file.ddiff, file.dbase + file.ddiff + file.dlen, + file.dlen, file.dlen, file.ddiff, file.ddiff & 0xffff); + printf("bss segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.bbase + file.bdiff, file.bbase + file.bdiff + file.blen, + file.blen, file.blen, file.bdiff, file.bdiff & 0xffff); + printf("zero segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.zbase + file.zdiff, file.zbase + file.zdiff + file.zlen, + file.zlen, file.zlen, file.zdiff, file.zdiff & 0xffff); + } + + /* pointer of position in file */ file.segt = file.buf + hlen; file.segd = file.segt + file.tlen; file.utab = file.segd + file.dlen; diff --git a/xa/misc/uncpk.c b/xa/misc/uncpk.c index 5f2a2b6..5f2cfb5 100644 --- a/xa/misc/uncpk.c +++ b/xa/misc/uncpk.c @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) exit(1); } - if (strstr(argv[1], "--help")) { + if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) { usage(stdout); exit(0); } diff --git a/xa/src/Makefile b/xa/src/Makefile index dc15ea6..51259ef 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -1,7 +1,8 @@ -OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o +OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o xalisting.o -#CFLAGS=-W -Wall -pedantic -ansi #-g +#CFLAGS=-W -Wall -pedantic -ansi -g #CFLAGS=-W -Wall -ansi -O2 +#CFLAGS=-g -std=c11 -D_GNU_SOURCE #LD = ${CC} #LDFLAGS = "-lc" diff --git a/xa/src/version.h b/xa/src/version.h index cdfbd09..45d84c0 100644 --- a/xa/src/version.h +++ b/xa/src/version.h @@ -19,7 +19,7 @@ #ifndef __XA65_VERSION_H__ #define __XA65_VERSION_H__ -void version(const char *programname, const char *progversion, +void version(const char *programname, const char *version, const char *authors, const char *copyright) { fprintf(stdout, @@ -31,7 +31,7 @@ void version(const char *programname, const char *progversion, "copying conditions. There is NO\n" "warranty; not even for MERCHANTABILIY or " "FITNESS FOR A PARTICULAR PURPOSE.\n", - programname, progversion, authors, copyright); + programname, version, authors, copyright); } #endif /* __XA65_VERSION_H__ */ diff --git a/xa/src/xa.c b/xa/src/xa.c index 7d5a1b7..4bc4d4f 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -45,6 +45,7 @@ #include "xar.h" #include "xat.h" #include "xacharset.h" +#include "xalisting.h" #include "version.h" @@ -55,27 +56,34 @@ #define ANZWARN 13 #define programname "xa" -#define progversion "v2.3.14" +/* progversion now in xa.h */ #define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser" #define copyright "Copyright (C) 1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser." /* exported globals */ int ncmos, cmosfl, w65816, n65816; -int masm = 0; -int ppinstr = 0; + +/* compatibility flags */ +int masm = 0; /* MASM */ +int ca65 = 0; /* CA65 */ +int xa23 = 0; /* ^ and recursive comments, disable \ escape */ +int ctypes = 0; /* C compatibility, like "0xab" types */ int nolink = 0; int romable = 0; int romaddr = 0; int noglob = 0; int showblk = 0; int crossref = 0; +int undefok = 0; // -R only accepts -Llabels; with -U all undef'd labels are ok in -R mode char altppchar; /* local variables */ + static char out[MAXLINE]; static time_t tim1, tim2; -static FILE *fpout, *fperr, *fplab; +static FILE *fpout, *fperr, *fplab, *fplist; static int ner = 0; +static int ner_max = 20; static int align = 1; @@ -86,12 +94,14 @@ static int x_init(void); static int pass1(void); static int pass2(void); static int puttmp(int); +static int puttmpw(int); static int puttmps(signed char *, int); static void chrput(int); static int xa_getline(char *); static void lineout(void); static long ga_p1(void); static long gm_p1(void); +static int set_compat(char *compat_name); /* text */ int memode,xmode; @@ -111,16 +121,18 @@ int main(int argc,char *argv[]) signed char *s=NULL; char *tmpp; + char *listformat = NULL; + int mifiles = 5; int nifiles = 0; int verbose = 0; - int oldfile = 0; int no_link = 0; char **ifiles; - char *ofile; - char *efile; - char *lfile; + char *printfile; /* print listing to this file */ + char *ofile; /* output file */ + char *efile; /* error listing goes there */ + char *lfile; /* labels go here */ char *ifile; char old_e[MAXLINE]; @@ -161,7 +173,7 @@ int main(int argc,char *argv[]) exit(1); } - if (strstr(argv[1], "--help")) { + if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) { usage(w65816, stdout); exit(0); } @@ -174,6 +186,7 @@ int main(int argc,char *argv[]) ofile="a.o65"; efile=NULL; lfile=NULL; + printfile=NULL; if(pp_init()) { logout("fatal: pp: no memory!"); @@ -192,6 +205,9 @@ int main(int argc,char *argv[]) while(i 0) { fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0); + } else { + /* ner_max==0, i.e. show all errors */ + fprintf(stderr, "End after %d error%c\n",ner,ner?'s':0); + } /*unlink();*/ if(ofile) { unlink(ofile); @@ -649,39 +699,41 @@ static int pass2(void) filep=&datei; afile->mn.tmpe=0L; - while(ner<20 && afile->mn.tmpemn.tmpz) + while((ner_max==0 || nermn.tmpemn.tmpz) { - l=afile->mn.tmp[afile->mn.tmpe++]; + // get the length of the entry (now two byte - need to handle the sign) + l = 255 & afile->mn.tmp[afile->mn.tmpe++]; + l |= afile->mn.tmp[afile->mn.tmpe++] << 8; ll=l; + //printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]); + if(!l) { if(afile->mn.tmp[afile->mn.tmpe]==T_LINE) { datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); afile->mn.tmpe+=3; + list_line(datei.fline); /* set line number of next listing output */ } else if(afile->mn.tmp[afile->mn.tmpe]==T_FILE) { + // copy the current line number from the current file descriptor datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); - + // copy the pointer to the file name in the current file descriptor + // Note: the filename in the current file descriptor is separately malloc'd and + // thus save to store the pointer memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname)); afile->mn.tmpe+=3+sizeof(datei.fname); -/* - datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1); - if(!datei.fname) { - fprintf(stderr,"Oops, no more memory\n"); - exit(1); - } - strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3); - afile->mn.tmpe+=3+strlen(datei.fname); -*/ + + list_filename(datei.fname); /* set file name of next listing output */ } } else { /* do not attempt address mode optimization on pass 2 */ - er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al); - + + /* t_p2_l() includes the listing call to do_listing() */ + er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al); if(er==E_NOLINE) { } else @@ -786,16 +838,14 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n", static int pass1(void) { - signed char o[MAXLINE]; - int l,er,temp_er,al; + signed char o[2*MAXLINE]; /* doubled for token listing */ + int l,er,al; memode=0; xmode=0; tlen=0; ner=0; - temp_er = 0; - /*FIXIT*/ while(!(er=xa_getline(s))) { @@ -808,7 +858,7 @@ static int pass1(void) case SEG_ZERO: zlen += al; break; } - /*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */ + //printf(": er= %d, l=%d\n",er,l); if(l) { @@ -816,14 +866,14 @@ static int pass1(void) { if(er==E_OKDEF) { - if(!(er=puttmp(l))) + if(!(er=puttmpw(l))) er=puttmps(o,l); } else if(er==E_NOLINE) er=E_OK; } else { - if(!(er=puttmp(-l))) + if(!(er=puttmpw(-l))) er=puttmps(o,l); } } @@ -860,6 +910,7 @@ static void usage(int default816, FILE *fp) programname); fprintf(fp, " -v verbose output\n" + " -E do not break after 20 errors, but show all\n" " -C no CMOS-opcodes\n" " -W no 65816-opcodes%s\n" " -w allow 65816-opcodes%s\n", @@ -873,11 +924,19 @@ static void usage(int default816, FILE *fp) fprintf(fp, " -e filename sets errorlog filename, default is none\n" " -l filename sets labellist filename, default is none\n" + " -P filename sets filename for listing, default is none, '-' is stdout\n" + " -F format sets format for listing, default is plain, 'html' is current only other\n" + " supported format\n" " -r adds crossreference list to labellist (if `-l' given)\n" " -M allow ``:'' to appear in comments for MASM compatibility\n" - " -R start assembler in relocating mode\n"); + " (deprecated: prefer -XMASM)\n" + " -Xcompatset set compatibility flags for other assemblers, known values are:\n" + " C, MASM, CA65, XA23 (deprecated: for better 2.3 compatibility)\n" + " -R start assembler in relocating mode\n" + " -U allow all undefined labels in relocating mode\n"); fprintf(fp, " -Llabel defines `label' as absolute, undefined label even when linking\n" + " -p replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n" " -b? addr set segment base address to integer value addr\n" " `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n" " (address can be given more than once, last one is used)\n"); @@ -893,104 +952,89 @@ static void usage(int default816, FILE *fp) " -Idir add directory `dir' to include path (before XAINPUT)\n" " --version output version information and exit\n" " --help display this help and exit\n"); - fprintf(fp, - "== These options are deprecated and will be removed in 2.4+! ==\n" - " -x old filename behaviour (overrides `-o', `-e', `-l')\n" - " -S allow preprocessor substitution within strings\n"); } -/* -static char *ertxt[] = { "Syntax","Label definiert", - "Label nicht definiert","Labeltabelle voll", - "Label erwartet","Speicher voll","Illegaler Opcode", - "Falsche Adressierungsart","Branch ausserhalb des Bereichs", - "Ueberlauf","Division durch Null","Pseudo-Opcode erwartet", - "Block-Stack-Ueberlauf","Datei nicht gefunden", - "End of File","Block-Struktur nicht abgeschlossen", - "NoBlk","NoKey","NoLine","OKDef","DSB","NewLine", - "NewFile","CMOS-Befehl","pp:Falsche Anzahl Parameter" }; -*/ static char *ertxt[] = { - "Syntax", - "Label already defined", - "Label not defined", - "Label table full", - "Label expected", - "Out of memory", - "Illegal opcode", - "Wrong addressing mode", - "Branch out of range", - "Overflow", - "Division by zero", - "Pseudo-opcode expected", - "Block stack overflow", - "File not found", - "End of file", - "Unmatched block close", - "NoBlk", - "NoKey", - "NoLine", - "OKDef", - "DSB", - "NewLine", - "NewFile", - "CMOS instruction used with -C", - "pp:Wrong parameter count", - "Illegal pointer arithmetic", - "Illegal segment", - "File header option too long", - "File option not at file start (when ROM-able)", - "Illegal align value", - "65816 mode used/required", - "Exceeded recursion limit for label evaluation", - "Unresolved preprocessor directive at end of file", - "Data underflow", - "Illegal quantity", - ".bin", + "Syntax", // E_SYNTAX =-1 + "Label already defined", // E_LABDEF =-2 + "Label not defined", // E_NODEF =-3 + "Label table full", // E_LABFULL =-4 + "Label expected", // E_LABEXP =-5 + "Out of memory", // E_NOMEM =-6 + "Illegal opcode", // E_ILLCODE =-7 + "Wrong addressing mode", // E_ADRESS =-8 + "Branch out of range", // E_RANGE =-9 + "Overflow", // E_OVERFLOW =-10 + "Division by zero", // E_DIV =-11 + "Pseudo-opcode expected", // E_PSOEXP =-12 + "Block stack overflow", // E_BLKOVR =-13 + "File not found", // E_FNF =-14 + "End of file", // E_EOF =-15 + "Unmatched block close", // E_BLOCK =-16 + "NoBlk", // E_NOBLK =-17 + "NoKey", // E_NOKEY =-18 + "NoLine", // E_NOLINE =-19 + "OKDef", // E_OKDEF =-20 + "DSB", // E_DSB =-21 + "NewLine", // E_NEWLINE =-22 + "NewFile", // E_NEWFILE =-23 + "CMOS instruction used with -C", // E_DMOS =-24 + "pp:Wrong parameter count", // E_ANZPAR =-25 + "Illegal pointer arithmetic (-26)", // E_ILLPOINTER =-26 + "Illegal segment", // E_ILLSEGMENT =-27 + "File header option too long", // E_OPTLEN =-28 + "File option not at file start (when ROM-able)", // E_ROMOPT =-29 + "Illegal align value", // E_ILLALIGN =-30 + "65816 mode used/required", // E_65816 =-31 + "Exceeded recursion limit for label evaluation", // E_ORECMAC =-32 + "Unresolved preprocessor directive at end of file", // E_OPENPP =-33 + "Data underflow", // E_OUTOFDATA =-34 + "Illegal quantity", // E_ILLQUANT =-35 + ".bin", // E_BIN =-36 + "#error directive", // E_UERROR =-37 + "Assertion", // E_AERROR =-38 + "DSB has negative length", // E_NEGDSBLEN =-39 /* placeholders for future fatal errors */ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", + "", // -40 + "", // -41 + "", // -42 + "", // -43 + "", // -44 + "", // -45 + "", // -46 + "", // -47 + "", // -48 + "", // -49 + "", // -50 + "", // -51 + "", // -52 + "", // -53 + "", // -54 + "", // -55 + "", // -56 + "", // -57 + "", // -58 + "", // -59 + "", // -60 + "", // -61 + "", // -62 + "", // -63 + "", // -64 (was missing...) /* warnings */ - "Cutting word relocation in byte value", - "Byte relocation in word value", - "Illegal pointer arithmetic", - "Address access to low or high byte pointer", - "High byte access to low byte pointer", - "Low byte access to high byte pointer", - "Can't optimize forward-defined label; using absolute addressing", - "Open preprocessor directive at end of file (intentional?)", - "Included binary data exceeds 64KB", - "Included binary data exceeds 16MB", - "MVN/MVP $XXXX syntax is deprecated and will be removed", + "Cutting word relocation in byte value", // W_ADRRELOC =-65 + "Byte relocation in word value", // W_BYTERELOC =-66 + "Illegal pointer arithmetic (-66)", // E_WPOINTER =-67 + "Address access to low or high byte pointer", // W_ADDRACC =-68 + "High byte access to low byte pointer", // W_HIGHACC =-69 + "Low byte access to high byte pointer", // W_LOWACC =-70 + "Can't optimize forward-defined label; using absolute addressing", // W_FORLAB =-71 + "Open preprocessor directive at end of file (intentional?)", // W_OPENPP =-72 + "Included binary data exceeds 64KB", // W_OVER64K =-73 + "Included binary data exceeds 16MB", // W_OVER16M =-74 + "Subtracting pointer from constant not supported in -R mode", // W_SUBTRACT =-75 /* more placeholders */ - "", - "", + "", // -76 + "", // -77 }; @@ -1013,7 +1057,9 @@ static int x_init(void) static int puttmp(int c) { int er=E_NOMEM; -/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/ + + //printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz); + if(afile->mn.tmpzmn.tmp[afile->mn.tmpz++]=c; @@ -1022,17 +1068,37 @@ static int puttmp(int c) return(er); } +static int puttmpw(int c) +{ + int er=E_NOMEM; + + //printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz); + + if(afile->mn.tmpzmn.tmp[afile->mn.tmpz++]= c & 0xff; + afile->mn.tmp[afile->mn.tmpz++]= (c >> 8) & 0xff; + er=E_OK; + } + return(er); +} + static int puttmps(signed char *s, int l) { int i=0,er=E_NOMEM; - + + // printf("puttmps %d bytes from %p to %p:", l, s, afile->mn.tmp+afile->mn.tmpz); + if(afile->mn.tmpz+lmn.tmp[afile->mn.tmpz++]=s[i++]; + while(imn.tmp[afile->mn.tmpz++]=s[i++]; + } er=E_OK; } + // printf("\n"); return(er); } @@ -1062,25 +1128,19 @@ static int xa_getline(char *s) if(ec==E_NEWLINE) { - puttmp(0); + puttmpw(0); puttmp(T_LINE); - puttmp((filep->fline)&255); - puttmp(((filep->fline)>>8)&255); - ec=E_OK; + puttmpw(filep->fline); + ec=E_OK; } else if(ec==E_NEWFILE) { - puttmp(0); + puttmpw(0); puttmp(T_FILE); - puttmp((filep->fline)&255); - puttmp(((filep->fline)>>8)&255); + puttmpw(filep->fline); puttmps((signed char*)&(filep->fname), sizeof(filep->fname)); -/* - puttmps((signed char*)filep->fname, - 1+(int)strlen(filep->fname)); -*/ ec=E_OK; } } while(!ec && l[i]=='\0'); @@ -1089,6 +1149,7 @@ static int xa_getline(char *s) gl=0; if(!ec || ec==E_EOF) { + int startofline = 1; do { c=s[j]=l[i++]; @@ -1096,21 +1157,42 @@ static int xa_getline(char *s) hkfl^=1; if (!comcom && !(hkfl&1) && c=='\'') hkfl^=2; - if (c==';' && !hkfl) + if (c==';' && !hkfl) { comcom = 1; - if (c=='\0') - break; /* hkfl = comcom = 0 */ - if (c==':' && !hkfl && (!comcom || !masm)) { - gl=1; - break; - } + } + if (c=='\0') { + // end of line + break; /* hkfl = comcom = 0 */ + } + if (c==':' && !hkfl) { + /* if the next char is a "=" - so that we have a ":=" - and we + we have ca65 compatibility, we ignore the colon */ + // also check for ":+" and ":-" + + if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) { + /* but otherwise we check if it is in a comment and we have + MASM or CA65 compatibility, then we ignore the colon as well */ + if(!comcom || !(masm || ca65)) { + /* we found a colon, so we keep the current line in memory + but return the part before the colon, and next time the part + after the colon, so we can parse C64 BASIC text assembler... */ + gl=1; + break; + } + } + } + if (!isspace(c)) { + startofline = 0; + } j++; } while (c!='\0' && j-1) { - if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) { + if (er<=-ANZERR || er>-1) { + if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) { sprintf(out,"%s:line %d: %04x: Warning - %s\n", filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]); } else { @@ -1167,3 +1249,37 @@ void logout(char *s) fprintf(fperr,"%s",s); } +/*****************************************************************/ + +typedef struct { + char *name; + int *flag; +} compat_set; + +static compat_set compat_sets[] = { + { "MASM", &masm }, + { "CA65", &ca65 }, + { "C", &ctypes }, + { "XA23", &xa23 }, + { NULL, NULL } +}; + +int set_compat(char *compat_name) { + int i = 0; + while (compat_sets[i].name != NULL) { + if (strcmp(compat_sets[i].name, compat_name) == 0) { + /* set appropriate compatibility flag */ + (*compat_sets[i].flag) = 1; + + /* warn on old versions of xa */ + if (xa23) fprintf(stderr, + "Warning: -XXA23 is explicitly deprecated\n"); + + return 0; + } + i++; + } + return -1; +} + + diff --git a/xa/src/xa.h b/xa/src/xa.h index b00cbed..52ac51e 100644 --- a/xa/src/xa.h +++ b/xa/src/xa.h @@ -21,12 +21,18 @@ #include "xah.h" /* For SEG_MAX */ +#define progmajor "2" +#define progminor "4" +#define progpatch "0" +#define progversion progmajor "." progminor "." progpatch + extern int ncmos, cmosfl, w65816, n65816; -extern int masm, nolink, ppinstr; +extern int masm, ca65, xa23, nolink, undefok; extern int noglob; extern int showblk; extern int relmode; extern int crossref; +extern int ctypes; extern char altppchar; extern int tlen, tbase; diff --git a/xa/src/xaa.c b/xa/src/xaa.c index 40885f7..85577f9 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -32,7 +32,7 @@ static int pr[]= { P_START,P_ADD,P_ADD,P_MULT,P_MULT,P_SHIFT,P_SHIFT,P_CMP, P_CMP,P_EQU,P_CMP,P_CMP,P_EQU,P_AND,P_XOR,P_OR, - P_LAND,P_LOR }; + P_LAND,P_LOR,P_EQU,P_START }; static int pp,pcc; static int fundef; @@ -77,7 +77,8 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f) if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255); *v=(*v>>8)&255; } - else { + else + if(s[pp]!=T_END) { er=ag_term(s,P_START,v,&afl, label); bfl = afl & (A_MASK>>8); if(bfl && (bfl != (A_ADR>>8)) ) { @@ -85,10 +86,12 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f) errout(W_ADDRACC); } if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK); + } else { + er = E_SYNTAX; } *l=pp; -/* printf("a_term: afl->%04x *pfl=%04x, (pc=%04x)\n",afl,*pfl, xpc); */ +//fprintf(stderr, "a_term: nolink=%d, noundef=%d ->er=%d; l=%d, pp=%d, afl->%04x *pfl=%04x, (pc=%04x)\n",nolink, noundef ,er, *l, pp, afl,*pfl, xpc); return(er); } @@ -98,15 +101,28 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) afl = 0; -/* -printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]); -*/ +//fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]); + while(s[pp]=='-') { pp++; mf=-mf; } +#if(0) /* NYI: this is hacked into .assert for now */ + if(s[pp]==18) /* logical not */ + { + pp++; + if(!(er=ag_term(s,P_START,v,&afl,label))) + { + if(s[pp]!=')') + er=E_SYNTAX; + else + pp++; + } + *v = !(*v); + } else +#endif if(s[pp]=='(') { pp++; @@ -121,25 +137,31 @@ printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]); if(s[pp]==T_LABEL) { er=l_get(cval(s+pp+1),v, &afl); + /* printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n", er, segment, afl, nolink, fundef); */ if(er==E_NODEF && segment != SEG_ABS && fundef ) { - if( nolink || (afl==SEG_UNDEF)) { + if( nolink || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) { er = E_OK; *v = 0; - afl = SEG_UNDEF; + if(afl!=SEG_UNDEFZP) { + afl = SEG_UNDEF; + } *label = cval(s+pp+1); } } pp+=3; } else - if(s[pp]==T_VALUE) + if(s[pp]==T_VALUE || s[pp] == T_CAST) { + while (s[pp] == T_CAST) { + pp+=2; + } *v=lval(s+pp+1); - pp+=4; + pp+=5; /* printf("value: v=%04x\n",*v); */ @@ -149,7 +171,7 @@ printf("value: v=%04x\n",*v); { afl = s[pp+1]; *v=cval(s+pp+2); - pp+=4; + pp+=6; /* printf("pointer: v=%04x, afl=%04x\n",*v,afl); */ @@ -160,15 +182,16 @@ printf("pointer: v=%04x, afl=%04x\n",*v,afl); *v=pcc; pp++; afl = segment; - } + } else { er=E_SYNTAX; } *v *= mf; - while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END) + while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END && s[pp]!=T_COMMENT) { +//fprintf(stderr, "ag_term while: s[pp=%d]=%02x\n", pp, s[pp]); er=get_op(s,&o); if(!er && pr[o]>p) @@ -177,18 +200,24 @@ printf("pointer: v=%04x, afl=%04x\n",*v,afl); if(!(er=ag_term(s,pr[o],&w, nafl, label))) { if(afl || *nafl) { /* check pointer arithmetic */ - if((afl == *nafl) && (afl!=SEG_UNDEF) && o==2) { - afl = 0; /* substract two pointers */ + if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) { + afl = 0; /* subtract two pointers */ } else if(((afl && !*nafl) || (*nafl && !afl)) && o==1) { afl=(afl | *nafl); /* add constant to pointer */ } else if((afl && !*nafl) && o==2) { - afl=(afl | *nafl); /* substract constant from pointer */ + afl=(afl | *nafl); /* subtract constant from pointer */ } else { - /* allow math in the same segment */ + if((!afl && *nafl) && o==2) { + /* subtract pointer from constant */ + errout(W_SUBTRACT); + } + /* allow math in the same segment */ if(segment!=SEG_ABS && segment != afl) { if(!dsb_len) { + /*printf("ILLPOINTER=dsb_len=%d,segment=%d\n",dsb_len, segment);*/ + /* e.g. adding two pointers, adding two undefined values */ er=E_ILLSEGMENT; } } @@ -211,10 +240,18 @@ static int get_op(signed char *s, int *o) *o=s[pp]; - if(*o<1 || *o>17) + if(*o<1 || *o>17) { +/* + printf("*o=%d, pp=%d, s=%s\n", *o, pp, s); + for (int i=0; i< 10; i++) { + printf(" %02x", s[i]); + } + printf("\n"); +*/ er=E_SYNTAX; - else + } else { er=E_OK; + } return(er); } diff --git a/xa/src/xad.h b/xa/src/xad.h index 79528fc..2c2a64c 100644 --- a/xa/src/xad.h +++ b/xa/src/xad.h @@ -31,11 +31,12 @@ #define cval(s) 256 * ((s)[1] & 255) + ((s)[0]&255) #define lval(s) 65536 * ((s)[2] & 255) + 256 * ((s)[1] & 255) + ((s)[0] & 255) -#define wval(i, v) do { \ +#define wval(i, v, f) do { \ t[i++] = T_VALUE; \ t[i++] = v & 255; \ t[i++] = (v >> 8) & 255; \ t[i++] = (v >> 16) & 255; \ + t[i++] = f & 255; \ } while (0) #endif /* __XA65_XAD_H__ */ diff --git a/xa/src/xah.h b/xa/src/xah.h index 26133b2..a126ed2 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -20,15 +20,29 @@ #ifndef __XA65_XAH_H__ #define __XA65_XAH_H__ -#define ANZLAB 5000 /* mal 14 -> Byte */ +/* + * Note: the computations to get the number of bytes necessary to allocate are + * a historic remnant of the Atari ST (the original platform) not being able to efficiently allocate small chunks + * of memory so I had to allocate a large chunk myself and manage the tables myself. + * This has changed and some parts of xa65 are modified to just do a malloc() now. + * These fixed numbers should actually go away. AF 20110623 + */ +#define ANZLAB 5000 /* multiplied by sizeof(Labtab) -> Byte */ #define LABMEM 40000L #define MAXLAB 32 #define MAXBLK 16 #define MAXFILE 7 #define MAXLINE 2048 #define MAXPP 40000L -#define ANZDEF 2340 /* mal 14 -> Byte, ANZDEF * 14 < 32768 */ -#define TMPMEM 200000L /* Zwischenspeicher von Pass1 nach Pass 2 */ +#define ANZDEF 2340 /* multiplied by sizeof(List) -> Byte, ANZDEF * 20 < 32768 */ +#define TMPMEM 2000000L /* temporary memory buffer from Pass1 to Pass 2 (includes all source, thus enlarged) */ + +typedef enum { + STD = 0, + CHEAP = 1, + UNNAMED = 2, + UNNAMED_DEF = 3 +} xalabel_t; typedef struct LabOcc { struct LabOcc *next; @@ -36,17 +50,29 @@ typedef struct LabOcc { char *fname; } LabOcc; +/** + * struct that defines a label, after it has been parsed + */ typedef struct { int blk; + int origblk; // only for fl=3 int val; int len; int fl; /* 0 = label value not valid/known, * 1 = label value known + * 2 = label value not known, external global label (imported on link) + * 3 = label value not known, temporarily on external global label list (for -U) */ int afl; /* 0 = no address (no relocation), 1 = address label */ int nextindex; + xalabel_t is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */ char *n; struct LabOcc *occlist; + // within a block, make a linked list for the unnamed label counting + // use indexes, as the label table can be re-alloced (so pointers change) + // -1 is the "undef'd" end of list + int blknext; + int blkprev; } Labtab; typedef struct { @@ -71,20 +97,20 @@ typedef struct { #define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */ -#define E_OK 0 /* Fehlernummern */ -#define E_SYNTAX -1 /* Syntax Fehler */ -#define E_LABDEF -2 /* Label definiert */ -#define E_NODEF -3 /* Label nicht definiert */ -#define E_LABFULL -4 /* Labeltabelle voll */ -#define E_LABEXP -5 /* Label erwartet */ -#define E_NOMEM -6 /* kein Speicher mehr */ -#define E_ILLCODE -7 /* Illegaler Opcode */ -#define E_ADRESS -8 /* Illegale Adressierung */ +#define E_OK 0 /* No error */ +#define E_SYNTAX -1 /* Syntax error */ +#define E_LABDEF -2 /* Label already defined (duplicate label definition) */ +#define E_NODEF -3 /* Label not defined */ +#define E_LABFULL -4 /* Label table full */ +#define E_LABEXP -5 /* Label expected but not found */ +#define E_NOMEM -6 /* out of memory */ +#define E_ILLCODE -7 /* Illegal Opcode */ +#define E_ADRESS -8 /* Illegal Addressing mode */ #define E_RANGE -9 /* Branch out of range */ -#define E_OVERFLOW -10 /* Ueberlauf */ -#define E_DIV -11 /* Division durch Null */ -#define E_PSOEXP -12 /* Pseudo-Opcode erwartet */ -#define E_BLKOVR -13 /* Block-Stack Uebergelaufen */ +#define E_OVERFLOW -10 /* overflow */ +#define E_DIV -11 /* Division by zero */ +#define E_PSOEXP -12 /* Pseudo-Opcode expected but not found */ +#define E_BLKOVR -13 /* Block-Stack overflow */ #define E_FNF -14 /* File not found (pp) */ #define E_EOF -15 /* End of File */ #define E_BLOCK -16 /* Block inkonsistent */ @@ -112,6 +138,9 @@ typedef struct { #define E_OUTOFDATA -34 /* out of data */ #define E_ILLQUANT -35 /* generic illegal quantity error */ #define E_BIN -36 /* okdef */ +#define E_UERROR -37 /* #error */ +#define E_AERROR -38 /* .assert failed */ +#define E_NEGDSBLEN -39 /* .dsb has negative length */ /* errors thru 64 are placeholders available for use */ #define W_ADRRELOC -65 /* word relocation in byte value */ @@ -124,21 +153,28 @@ typedef struct { #define W_OPENPP -72 /* warning about open preprocessor directive */ #define W_OVER64K -73 /* included binary over 64K in 6502 mode */ #define W_OVER16M -74 /* included binary over 16M in 65816 mode */ -#define W_OLDMVNS -75 /* use of old mv? $xxxx syntax */ -/* warnings 76-77 are placeholders available for use */ +#define W_SUBTRACT -75 /* subtract a segment pointer from a constant - not supported in -R mode */ +/* warnings 75-77 are placeholders available for use */ -#define T_VALUE -1 -#define T_LABEL -2 -#define T_OP -3 -#define T_END -4 -#define T_LINE -5 -#define T_FILE -6 -#define T_POINTER -7 +/* Meta-values for the token list. Note must not overlap with the + * K* definitions in xat.c, which have outgrown the positive numbers + * and are now growing up from -128 ... */ +#define T_VALUE -1 /* following is a 24 bit value in the token list */ +#define T_LABEL -2 /* referring to a label, following the token is the 16bit label number */ +#define T_OP -3 /* label oriented operation; following is the label number (16bit), plus the operation char (e.g. '+') */ +#define T_END -4 /* end of line marker */ +#define T_LINE -5 /* new line indicator; following is the 16 bit line number */ +#define T_FILE -6 /* new file indicator; following is the 16 bit line number, then the file name (zero-term) */ +#define T_POINTER -7 /* ??? */ +#define T_COMMENT -8 /* unused */ +#define T_DEFINE -9 /* define a label; inserted at conversion and discarded in pass1, only used in listing output */ +#define T_LISTING -10 /* meta token, inserted after conversion before pass1, used after pass2 to create listing */ +#define T_CAST -11 /* token inserted for a cast */ -#define P_START 0 /* Prioritaeten fuer Arithmetik */ -#define P_LOR 1 /* Von zwei Operationen wird immer */ -#define P_LAND 2 /* die mit der hoeheren Prioritaet */ -#define P_OR 3 /* zuerst ausgefuehrt */ +#define P_START 0 /* arithmetic operation priorities */ +#define P_LOR 1 /* of any two operations, the one with */ +#define P_LAND 2 /* the higher priority will be done first */ +#define P_OR 3 #define P_XOR 4 #define P_AND 5 #define P_EQU 6 @@ -169,6 +205,8 @@ typedef struct { #define SEG_ZERO 5 #define SEG_MAX 6 +#define SEG_UNDEFZP 7 /* is being mapped to UNDEF */ + typedef struct Fopt { signed char *text; /* text after pass1 */ int len; @@ -189,8 +227,11 @@ typedef struct File { int base[SEG_MAX]; int len[SEG_MAX]; struct { + // temporary memory between pass1 and pass2 signed char *tmp; + // write pointer unsigned long tmpz; + // read pointer unsigned long tmpe; } mn; struct { diff --git a/xa/src/xal.c b/xa/src/xal.c index 5598c75..1781112 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -48,46 +48,24 @@ static int b_fget(int*,int); static int b_ltest(int,int); static int b_get(int*); static int b_test(int); -static int ll_def(char *s, int *n, int b); +static int ll_def(char *s, int *n, int b, xalabel_t ltype); +static int b_link(int); -/* local variables */ +static int b_new(void); -/* -static int hashindex[256]; -static Labtab *lt = NULL; -static int lti = 0; -static int ltm = 0; -*/ +static void cll_init(); +static int cll_get(); +static void cll_clear(); +static int cll_getcur(); -/* -static char *ln; -static unsigned long lni; -static long sl; -*/ static Labtab *ltp; int l_init(void) { + cll_init(); + //unn_init(); return 0; -#if 0 - int er; - - for(er=0;er<256;er++) - hashindex[er]=0; - - /*sl=(long)sizeof(Labtab);*/ - -/* if(!(er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)<))) - er=m_alloc((long)LABMEM,&ln);*/ - - er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)<); - - lti=0; -/* lni=0L;*/ - - return(er); -#endif } int ga_lab(void) @@ -139,86 +117,221 @@ FILE *fp; } } +/********************************************************************************** + * cheap local labels + */ + +static int cll_current = 0; /* the current cheap local labels block */ + +/** + * init the cheap local labels + */ +void cll_init() { + cll_current = 0; +} + +/** + * get the block number for a new cheap local label block + */ +int cll_get() { + if (cll_current == 0) { + cll_current = b_new(); + } + return cll_current; +} + +/** + * clear the local labels + */ +void cll_clear() { + cll_current = 0; +} + +int cll_getcur() { + return cll_current; +} + +/**********************************************************************************/ + +/** + * define a global label (from the "-L" command line parameter) + */ int lg_set(char *s ) { int n, er; - er = ll_search(s,&n); + er = ll_search(s,&n, STD); if(er==E_OK) { fprintf(stderr,"Warning: global label doubly defined!\n"); } else { - if(!(er=ll_def(s,&n,0))) { - ltp=afile->la.lt+n; - ltp->fl=2; - ltp->afl=SEG_UNDEF; - } + if(!(er=ll_def(s,&n,0, STD))) { + return lg_import(n); + } } return er; } +/** + * define a global label (from the .import pseudo opcode)) + * "s" is a pointer to the first label character, end is at \0 + * or at non-alphanumeric/_ char + */ +int lg_import(int n) { + int er=E_OK; + + ltp=afile->la.lt+n; + ltp->fl=2; + ltp->afl=SEG_UNDEF; + + return er; +} + +/* + * re-define a previously undef'd label as globally undefined + * (for -U option) + */ +int lg_toglobal(char *s ) { + int n, er; + +//printf("lg_toglobal(%s)\n", s); + er = ll_search(s,&n, STD); + + if(er==E_OK && ltp->fl != 3) { + // fonnd, but not yet set as global undef'd label + ltp=afile->la.lt+n; + ltp->fl=3; + ltp->afl=SEG_UNDEF; + ltp->origblk=ltp->blk; + ltp->blk=0; + } + return er; +} + + +/** + * define a global zeropage label (from the .importzp pseudo opcode)) + * "s" is a pointer to the first label character, end is at \0 + * or at non-alphanumeric/_ char + */ +int lg_importzp(int n) { + int er=E_OK; + + ltp=afile->la.lt+n; + ltp->fl=2; + ltp->afl=SEG_UNDEFZP; + + return er; +} + +/**********************************************************************************/ int l_def(char *s, int *l, int *x, int *f) { int n,er,b,i=0; + xalabel_t cll_fl; - *f=0; - b=0; - n=0; + *f=0; /* flag (given as param) that the label is to be re-defined and the + "label defined error" is to be skipped */ + b=0; /* block level on block stack, resp. block number */ + n=0; /* flag, when set, b is absolute block number and not being translated */ + cll_fl=STD; /* when 0, clear the cheap local label block */ + if(s[0]==':') { + // ca65 unnamed label + i++; + //n++; /* block number b is absolute */ + //b=unn_get(); /* current (possibly newly allocated) unnamed label block */ + cll_fl = UNNAMED; // keep the cheap local label block + } else if(s[0]=='-') { - *f+=1; + *f+=1; /* label is being redefined */ i++; } else + if(s[0]=='@') + { + i++; + n++; /* block number b is absolute */ + b=cll_get(); /* current (possibly newly allocated) cheap label block */ + cll_fl=CHEAP; /* do not clear the cll block again... */ + } else if(s[0]=='+') { i++; - n++; - b=0; + n++; /* block number b is absolute */ + b=0; /* global block number */ } while(s[i]=='&') { - n=0; + if (n) b=0; /* reset block number */ + n=0; /* block number is relative */ i++; - b++; + b++; /* one (more) level up the block stack */ } - if(!n) + if(!n) { + /* translate from block stack level to absolute block number */ b_fget(&b,b); + } + if(cll_fl == STD) { + /* clear cheap local labels */ + cll_clear(); + } - if(!isalpha(s[i]) && s[i]!='_') + if((!isalpha(s[i])) && (s[i]!='_') && !(ca65 && ((cll_fl == UNNAMED) || isdigit(s[i])) ) ) { + //printf("SYNTAX cll_fl=%d, i=%d, s[i]=%02x (%c)\n", cll_fl, i, s[i], s[i]); er=E_SYNTAX; - else + } else { - er=ll_search(s+i,&n); + er = E_NODEF; + if (cll_fl != UNNAMED) { + er=ll_search(s+i,&n, cll_fl); + } if(er==E_OK) { + //printf("l_def OK: cll_fl=%d, i=%d, s=%s\n", cll_fl, i, s); + /* we actually found an existing label in the same scope */ ltp=afile->la.lt+n; if(*f) { + /* redefinition of label */ *l=ltp->len+i; } else - if(ltp->fl==0) + if(ltp->fl == 0) { + /* label has not been defined yet, (e.g. pass1 forward ref), so we try to set it. */ *l=ltp->len+i; if(b_ltest(ltp->blk,b)) er=E_LABDEF; else ltp->blk=b; + } else + if(ltp->fl == 3) + { + /* label has been defined as -U undef'd label so far - we need to check */ + *l=ltp->len+i; + if(b_ltest(ltp->origblk,b)) + er=E_LABDEF; + else + ltp->blk=b; + } else er=E_LABDEF; } else if(er==E_NODEF) { - if(!(er=ll_def(s+i,&n,b))) /* ll_def(...,*f) */ + + if(!(er=ll_def(s+i,&n,b, cll_fl) )) /* store the label in the table of labels */ { ltp=afile->la.lt+n; *l=ltp->len+i; ltp->fl=0; + ltp->is_cll=cll_fl; } + //printf("l_def NODEF: n=%d, s=%s\n", n, ltp->n); } *x=n; @@ -229,15 +342,31 @@ int l_def(char *s, int *l, int *x, int *f) int l_search(char *s, int *l, int *x, int *v, int *afl) { int n,er,b; + xalabel_t cll_fl; *afl=0; - er=ll_search(s,&n); -/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/ + /* check cheap local label */ + cll_fl=STD; + if (s[0]=='@') { + cll_fl=CHEAP; + s++; + } else + if (s[0]==':') { + cll_fl = UNNAMED_DEF; + s++; + } + + er = E_NODEF; + if (cll_fl != UNNAMED_DEF) { + er=ll_search(s,&n, cll_fl); + } + +//printf("l_search: lab=%s(afl=%d, er=%d, cll_fl=%d, cll_cur=%d)\n",s,*afl,er, cll_fl, cll_getcur()); if(er==E_OK) { ltp=afile->la.lt+n; - *l=ltp->len; + *l=ltp->len + ((cll_fl == STD) ? 0 : 1); if(ltp->fl == 1) { l_get(n,v,afl);/* *v=lt[n].val;*/ @@ -251,12 +380,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl) } else { - b_get(&b); - er=ll_def(s,x,b); /* ll_def(...,*v); */ + if(cll_fl == CHEAP) { + b=cll_get(); + } else + if(cll_fl == UNNAMED_DEF) { + b_get(&b); // b=unn_get(); + } else { + b_get(&b); + } + + er=ll_def(s,x,b, cll_fl); /* ll_def(...,*v); */ ltp=afile->la.lt+(*x); - - *l=ltp->len; + ltp->is_cll = cll_fl; + + *l=ltp->len + ((cll_fl == STD) ? 0 : 1); + //*l=ltp->len + cll_fl; if(!er) { @@ -303,11 +442,87 @@ void l_addocc(int n, int *v, int *afl) { } } +/* for the list functionality */ +char *l_get_name(int n, xalabel_t *is_cll) { + if (n > afile->la.ltm) { + fprintf(stderr, "Corrupted structures! n=%d, but max=%d\n", n, afile->la.ltm); + exit(1); + } + ltp=afile->la.lt+n; + *is_cll = ltp->is_cll; + return ltp->n; +} + +// works on the static(!) ltp "label table pointer" +// also returns the actual index in the table of the current ltp +static int resolve_unnamed() { + // need to count up/down in the linkd label list for the block + char *namep = ltp->n; + int nextp = -1; + //printf("::: unnamed_def: %s, n=%d\n", namep, n); + while ((*namep == '+') || (*namep == '-')) { + char c = *namep; + nextp = -1; + if (c == '+') { + nextp = ltp->blknext; + } else + if (c == '-') { + nextp = ltp->blkprev; + } + //printf("::: nextp=%d\n", nextp); + if (nextp == -1) { + return -1; // E_NODEF + } + ltp = afile->la.lt+nextp; + //printf("::: leads to: %s, nextp=%d\n", ltp->n, nextp); + if (ltp->is_cll == UNNAMED) { + namep++; + } + } + return nextp; +} + +/* for the listing, esp. html links; returns a pointer to a static buffer, available till next call */ +char *l_get_unique_name(int n) { + static char buf[MAXLINE]; + ltp=afile->la.lt+n; + + if (ltp->is_cll == CHEAP || ltp->is_cll == STD) { + sprintf(buf, "%d%c%s", ltp->blk, + (ltp->is_cll == CHEAP) ? 'C' : '_', + ltp->n); + } else + if (ltp->is_cll == UNNAMED) { + // definition of unnamed label - name is NULL + // so use the actual index + sprintf(buf, "%dU%d", ltp->blk, n); + } else + if (ltp->is_cll == UNNAMED_DEF) { + // we actually need to find the correct label from the "+" and "-" + // in the name + int tmp = resolve_unnamed(); + if (tmp >= 0) { + sprintf(buf, "%dU%d", ltp->blk, tmp); + } else { + sprintf(buf, "__%d", tmp); + } + } else { + buf[0] = 0; // no value + } + return buf; +} + int l_get(int n, int *v, int *afl) { if(crossref) l_addocc(n,v,afl); - ltp=afile->la.lt+n; + ltp = afile->la.lt+n; + + if (ltp->is_cll == UNNAMED_DEF) { + int tmp = resolve_unnamed(); + if (tmp == -1) return E_NODEF; + // now ltp is set to the actual label + } (*v)=ltp->val; lz=ltp->n; *afl = ltp->afl; @@ -321,7 +536,8 @@ void l_set(int n, int v, int afl) ltp->val = v; ltp->fl = 1; ltp->afl = afl; -/*printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);*/ + +//printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl); } static void ll_exblk(int a, int b) @@ -335,19 +551,23 @@ static void ll_exblk(int a, int b) } } -static int ll_def(char *s, int *n, int b) /* definiert naechstes Label nr->n */ +/* defines next label, returns new label number in out param n */ +static int ll_def(char *s, int *n, int b, xalabel_t ltype) { int j=0,er=E_NOMEM,hash; - char *s2; + char *s2 = NULL; -/*printf("ll_def: s=%s\n",s); */ +//printf("ll_def: s=%s, ltype=%d, no_name=%d\n",s, ltype, no_name); + // label table for the file ... if(!afile->la.lt) { + // ... does not exist yet, so malloc it afile->la.lti = 0; afile->la.ltm = 1000; afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab)); } if(afile->la.lti>=afile->la.ltm) { + // ... or is at its capacity limit, so realloc it afile->la.ltm *= 1.5; afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab)); } @@ -355,54 +575,66 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label fprintf(stderr, "Oops: no memory!\n"); exit(1); } -#if 0 - if((ltila.lt+afile->la.lti; -/* - s2=ltp->n=ln+lni; - while((jla.lt + afile->la.lti; + + if (ltype != UNNAMED) { + // alloc space and copy over name + if (ltype == UNNAMED_DEF) { + // unnamed lables are like ":--" or ":+" with variable length + while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++; + } else { + // standard (and cheap) labels are normal text + while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++; + } + s2 = malloc(j+1); + if(!s2) { fprintf(stderr,"Oops: no memory!\n"); exit(1); + } + strncpy(s2,s,j); + s2[j]=0; } - strncpy(s2,s,j); - s2[j]=0; -/* - if(jlen=j; - ltp->n = s2; - ltp->blk=b; + ltp->len=j; // length of label + ltp->n = s2; // name of label (char*) + ltp->blk=b; // block number ltp->fl=0; ltp->afl=0; - ltp->occlist=NULL; - hash=hashcode(s,j); - ltp->nextindex=afile->la.hashindex[hash]; - afile->la.hashindex[hash]=afile->la.lti; - *n=afile->la.lti; - afile->la.lti++; -/* lni+=j+1;*/ -/* } - } -*/ -/*printf("ll_def return: %d\n",er);*/ + ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label + ltp->occlist=NULL; + hash=hashcode(s,j); // compute hashcode + ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode + afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode + + // TODO: does not work across files! + ltp->blknext = -1; // no next block + ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block + + if (ltp->blkprev != -1) { + ltp = afile->la.lt + ltp->blkprev; + ltp->blknext = afile->la.lti; + } + + *n=afile->la.lti; // return the list index for that file in the out parameter n + afile->la.lti++; // increase last index in lable table + return(er); } - -int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ +/** + * search a label name in the label table. Return the label number + * in "n". Finds only labels that are in a block that is in the current + * set of blocks (in the block stack) + * + * If cll_fl is set, the label is also searched in the local cheap label scope + * + * Do not define the label (as is done in l_search()!) + */ +int ll_search(char *s, int *n, xalabel_t cll_fl) /* search Label in Tabelle ,nr->n */ { int i,j=0,k,er=E_NODEF,hash; @@ -411,7 +643,6 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ hash=hashcode(s,j); i=afile->la.hashindex[hash]; -/*printf("search?\n");*/ if(i>=afile->la.ltm) return E_NODEF; do @@ -422,11 +653,25 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ { for (k=0;(kn[k]==s[k]);k++); - if((j==k)&&(!b_test(ltp->blk))) - { - er=E_OK; - break; - } + if (cll_fl == CHEAP) { + if (ltp->blk == cll_getcur()) { + er=E_OK; + break; + } + } else + if (cll_fl == UNNAMED) { + // TODO + } else { +//printf("ll_search:match labels %s with %p (%s) from block %d, block check is %d\n", s, ltp, ltp->n, ltp->blk, b_test(ltp->blk)); + /* check if the found label is in any of the blocks in the + current block stack */ + if((j==k)&&(!b_test(ltp->blk))) + { + /* ok, label found and it is reachable (its block nr is in the current block stack */ + er=E_OK; + break; + } + } } if(!i) @@ -444,6 +689,8 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ getchar(); } #endif +//printf("l_search(%s) returns er=%d, n=%d\n", s, er, *n); + return(er); } @@ -451,7 +698,7 @@ int ll_pdef(char *t) { int n; - if(ll_search(t,&n)==E_OK) + if(ll_search(t,&n, STD)==E_OK) { ltp=afile->la.lt+n; if(ltp->fl) @@ -460,6 +707,9 @@ int ll_pdef(char *t) return(E_NODEF); } +/* + * Write out the list of global labels in an o65 file + */ int l_write(FILE *fp) { int i, afl, n=0; @@ -469,25 +719,39 @@ int l_write(FILE *fp) fputc(0, fp); return 0; } + // calculate number of global labels for (i=0;ila.lti;i++) { ltp=afile->la.lt+i; if((!ltp->blk) && (ltp->fl==1)) { n++; } } + // write number of globals to file fputc(n&255, fp); fputc((n>>8)&255, fp); + // iterate over labels and write out label for (i=0;ila.lti;i++) { ltp=afile->la.lt+i; if((!ltp->blk) && (ltp->fl==1)) { + // write global name fprintf(fp, "%s",ltp->n); fputc(0,fp); + + // segment byte afl = ltp->afl; - /* hack to switch undef and abs flag from internal to file format */ -/*printf("label %s, afl=%04x, A_FMASK>>8=%04x\n", ltp->n, afl, A_FMASK>>8);*/ - if( (afl & (A_FMASK>>8)) < SEG_TEXT) afl^=1; + // hack to switch undef and abs flag from internal to file format + // if asolute of undefined (< SEG_TEXT, i.e. 0 or 1) + // then invert bit 0 (0 = absolute) + if( (afl & (A_FMASK>>8)) < SEG_TEXT) { + afl^=1; + } + // remove residue flags, only write out real segment number + // according to o65 file format definition + afl = afl & (A_FMASK >> 8); fputc(afl,fp); + + // value fputc(ltp->val&255, fp); fputc((ltp->val>>8)&255, fp); } @@ -496,19 +760,39 @@ int l_write(FILE *fp) return 0; } -static int bt[MAXBLK]; -static int blk; -static int bi; +/******************************************************************************************* + * block management code. Here the ".(" and ".)" blocks are maintained. + * + * Blocks are numbered uniquely, every time a new block is opened, the "blk" variable + * is increased and its number used as block number. + * + * The currently open blocks are maintained in a stack (bt[]). The lowest entry is the outermost + * block number, adding block numbers as blocks are opened. When a block is closed, + * the block stack is shortened again (bi has the length of the block stack) + * + * Methods exist to open new blocks, close a block, and do some checks, e.g. whether + * a specific block number is contained in the current block stack. + */ +static int bt[MAXBLK]; /* block stack */ +static int labind; /* last allocated label, -1 none yet alloc'd - used for linking to find unnamed labels */ +static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */ +static int blk; /* current block number for allocation */ int b_init(void) { blk =0; bi =0; bt[bi]=blk; + labind=-1; return(E_OK); } +int b_new(void) +{ + return ++blk; +} + int b_depth(void) { return bi; @@ -519,19 +803,26 @@ int ga_blk(void) return(blk); } +/** + * open a new block scope + */ int b_open(void) { int er=E_BLKOVR; if(bi=0) @@ -562,6 +860,10 @@ static int b_fget(int *n, int i) return(E_OK); } +/** + * tests whether the given block number n is in the current stack of + * current block numbers bt[] + */ static int b_test(int n) { int i=bi; @@ -572,6 +874,9 @@ static int b_test(int n) return( i+1 ? E_OK : E_NOBLK ); } +/** + * tests whether the given block number "a" is in the + */ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(a)] */ { int i=0,er=E_OK; @@ -593,3 +898,10 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1( return(er); } +int b_link(int newlab) { + int tmp = labind; + //printf("b_link: old was %d, set to %d\n", tmp, newlab); + labind = newlab; + return tmp; +} + diff --git a/xa/src/xal.h b/xa/src/xal.h index 98a1d75..7522210 100644 --- a/xa/src/xal.h +++ b/xa/src/xal.h @@ -21,8 +21,13 @@ #include /* for FILE */ +/* nasty stuff - "lz" is exported from xal.c so xa.c can print the name + * of the label that was last searched for in the error message that the + * label was not found... + */ extern char *lz; + int l_init(void); int ga_lab(void); int gm_lab(void); @@ -30,6 +35,10 @@ long gm_labm(void); long ga_labm(void); int lg_set(char *); +int lg_import(int); +int lg_importzp(int); +// used to re-define undef'd labels as global for -U option +int lg_toglobal(char *); int b_init(void); int b_depth(void); @@ -40,9 +49,11 @@ int ga_blk(void); int l_def(char *s, int* l, int *x, int *f); int l_search(char *s, int *l, int *x, int *v, int *afl); void l_set(int n, int v, int afl); +char* l_get_name(int n, xalabel_t *is_cll); +char* l_get_unique_name(int n); int l_get(int n, int *v, int *afl); int l_vget(int n, int *v, char **s); -int ll_search(char *s, int *n); +int ll_search(char *s, int *n, xalabel_t labeltype); int ll_pdef(char *t); int b_open(void); diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c new file mode 100644 index 0000000..92b6d55 --- /dev/null +++ b/xa/src/xalisting.c @@ -0,0 +1,750 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * maintained by Cameron Kaiser + * + * Assembler listing + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* enable this to turn on (copious) optimization output */ +/* #define DEBUG_AM */ +#undef LISTING_DEBUG + +#include +#include + +#include "xah.h" +#include "xal.h" +#include "xat.h" + + +/*********************************************************************************************/ +/* this is the listing code + * + * Unfortunately this code has to go here (for now), as this file is the only one + * where we have access to the tables that allow to convert the tokens back to + * a listing + */ + +static FILE *listfp = NULL; +static int list_lineno = 1; /* current line number */ +static int list_last_lineno = 0; /* current line number */ +static char *list_filenamep = NULL; /* current file name pointer */ + +static int list_numbytes = 8; + +static int list_string(char *buf, char *string); +static int list_tokens(char *buf, signed char *input, int len); +static int list_value(char *buf, int val, signed char format); +static int list_nchar(char *buf, signed char c, int n); +static int list_char(char *buf, signed char c); +static int list_sp(char *buf); +static int list_word(char *buf, int outword); +static int list_word_f(char *buf, int outword, signed char format); +static int list_byte(char *buf, int outbyte); +static int list_byte_f(char *buf, int outbyte, signed char format); +static int list_nibble_f(char *buf, int outnib, signed char format); + +/*********************************************************************************************/ + +// formatter +typedef struct { + void (*start_listing)(char *name); + void (*start_line)(); + int (*set_anchor)(char *buf, char *name); // returns number of bytes added to buf + int (*start_label)(char *buf, char *name); // returns number of bytes added to buf + int (*end_label)(char *buf); + void (*end_line)(); + void (*end_listing)(); + char* (*escape)(char *toescape); // returns pointer to static buffer, valid until next call + char* (*escape_char)(char toescape); // returns pointer to static buffer, valid until next call +} formatter_t; + +static char *def_escape(char *toescape) { + return toescape; +} + +static char *def_escape_char(char toescape) { + static char buf[2]; + buf[0] = toescape; + buf[1] = 0; + return buf; +} + +static formatter_t def_format = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + def_escape, def_escape_char +}; + +static void html_start_listing(char *name) { + // really short version for now + fprintf(listfp, "%s
\n", 
+		(name == NULL) ? "(null)" : name);
+}
+
+static int html_set_anchor(char *buf, char *name) {
+	sprintf(buf, " ", name);
+	return strlen(buf);
+}
+
+static int html_start_label(char *buf, char *name) {
+	sprintf(buf, "", name);
+	return strlen(buf);
+}
+
+static int html_end_label(char *buf) {
+	sprintf(buf, "");
+	return strlen(buf);
+}
+
+static void html_end_listing() {
+	fprintf(listfp, "
\n"); +} + +static char *html_escape(char *toescape) { + static char buf[MAXLINE]; + + char *p = toescape; + char *q = buf; + + while (*p != 0) { + if (*p == '<') { + strcpy(q, "<"); + q+=4; + p++; + } else + if (*p == '&') { + strcpy(q, "&"); + q+=5; + p++; + } else + if (*p == '>') { + strcpy(q, ">"); + q+=4; + p++; + } else { + *q = *p; + q++; + p++; + } + } + *q = 0; // string terminator + return buf; +} + +static char *html_escape_char(char toescape) { + static char buf[2]; + + buf[0] = toescape; + buf[1] = 0; + + return html_escape(buf); +} + +static formatter_t html_format = { + html_start_listing, + NULL, + html_set_anchor, + html_start_label, + html_end_label, + NULL, + html_end_listing, + html_escape, html_escape_char +}; + +static formatter_t *formatp = &def_format; + +/*********************************************************************************************/ + +void list_flush() { + if (listfp != NULL) { + fflush(listfp); + } +} + +void list_start(const char *formatname) { + formatp = &def_format; + + if (formatname != NULL && strcmp("html", formatname) == 0) { + formatp = &html_format; + } + + if (listfp != NULL) { + if (formatp->start_listing != NULL) formatp->start_listing(list_filenamep); + } +} + +void list_end() { + if (listfp != NULL) { + if (formatp->end_listing != NULL) formatp->end_listing(); + } +} + +// set number of bytes per line displayed as hex +void list_setbytes(int number_of_bytes_per_line) { + list_numbytes = number_of_bytes_per_line; +} + +/* set line number for the coming listing output */ +void list_line(int l) { + list_lineno = l; +} + +/* set file name for the coming listing output */ +void list_filename(char *fname) { + if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { + list_filenamep = fname; + list_lineno = 1; + list_last_lineno = 0; + + /* Hack */ + if (listfp != NULL) { + fprintf(listfp, "\n%s\n\n", fname); + } + } +} + +/** + * set the output file descriptor where to write the listing + */ +void list_setfile(FILE *fp) { + listfp = fp; +} + +char *list_preamble(char *buf, int lineno, int seg, int pc) { + int i; + char c; + + /* line number in file */ + snprintf(buf, 10, "% 5d", lineno); + i = strlen(buf); + buf += i; + buf += list_char(buf, ' '); + + c = '?'; + /* preamble ':'
' ' */ + switch(seg) { + case SEG_ABS: c='A'; break; + case SEG_TEXT: c='T'; break; + case SEG_BSS: c='B'; break; + case SEG_DATA: c='D'; break; + case SEG_UNDEF: c='U'; break; + case SEG_ZERO: c='Z'; break; + } + buf = buf + list_char(buf, c); + buf = buf + list_char(buf, ':'); + buf = buf + list_word(buf, pc); + buf = buf + list_nchar(buf, ' ', 2); + + return buf; +} + + +/** + * listing/listing_len give the buffer address and length respectively that contains + * the token as they are produced by the tokenizer. + * bincode/bincode_len give the buffer address and length that contain the binary code + * that is produced from the token listing + * + * Note that both lengths may be zero + */ +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { + int i, n_hexb, num_last_line, tmp, overflow; + + char outline[MAXLINE]; + char *buf = outline; + + int lst_seg = listing[0]; + int lst_pc = (listing[2]<<8) | (listing[1] & 255); + + /* no output file (not even stdout) */ + if (listfp == NULL) return; + + + /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ + + if (bincode_len < 0) bincode_len = -bincode_len; + + /* do we need a separation line? */ + if (list_lineno > list_last_lineno+1) { + /* yes */ + /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ + fprintf(listfp, "\n"); + } + list_last_lineno = list_lineno; + + // could be extended to include the preamble... + if (formatp->start_line != NULL) formatp->start_line(); + + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + + // check if we have labels, so we can adjust the max printable number of + // bytes in the last line + num_last_line = 11; + tmp = listing[3] & 255; + if (tmp == (T_DEFINE & 255)) { + // we have label definition + num_last_line = 8; + } + overflow = 0; + + /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ + n_hexb = bincode_len; + if (list_numbytes != 0 && n_hexb >= list_numbytes) { + n_hexb = list_numbytes-1; + overflow = 1; + } + for (i = 0; i < n_hexb; i++) { + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + if ( (i%16) == 15) { + // make a break + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + if (formatp->end_line != NULL) formatp->end_line(); + if (formatp->start_line != NULL) formatp->start_line(); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); + } + } + if (overflow) { + // are we at the last byte? + if (n_hexb + 1 == bincode_len) { + // just print the last byte + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + } else { + // display "..." + buf = buf + list_nchar(buf, '.', 3); + } + n_hexb++; + } + i = n_hexb % 16; + if (i > num_last_line) { + // make a break (Note: with original PC, as now the assembler text follows + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + if (formatp->end_line != NULL) formatp->end_line(); + if (formatp->start_line != NULL) formatp->start_line(); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + i = 0; + } + i = num_last_line - i; + buf = buf + list_nchar(buf, ' ', i * 3); + + buf = buf + list_sp(buf); + + buf += list_tokens(buf, listing + 3, listing_len - 3); + +#ifdef LISTING_DEBUG + /* for now only do a hex dump so we see what actually happens */ + { + char valbuf[32]; + i = buf - outline; + if (i<80) buf += list_nchar(buf, ' ', 80-i); + + buf += list_string(buf, " >>"); + sprintf(valbuf, "%p", listing+3); + buf += list_string(buf, valbuf); + buf += list_sp(buf); + for (i = 3; i < listing_len; i++) { + buf = buf + list_byte(buf, listing[i]); + buf = buf + list_sp(buf); + } + } +#endif + buf[0] = 0; + + fprintf(listfp, "%s\n", outline); + + if (formatp->end_line != NULL) formatp->end_line(); +} + +int list_tokens(char *buf, signed char *input, int len) { + int outp = 0; + int inp = 0; + int tmp; + char *name; + signed char c; + xalabel_t is_cll; + int tabval, operator; + signed char format; + + if (inp >= len) return 0; + + tmp = input[inp] & 255; + + tabval = 0; + if (tmp == (T_DEFINE & 255)) { + while (inp < len && tmp == (T_DEFINE & 255)) { + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); +/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ + name=l_get_name(tmp, &is_cll); + + // duplicate anchor names? + if (formatp->set_anchor != NULL) { + outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp)); + } + + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + tmp = list_string(buf+outp, name); + tabval += tmp + 1 + is_cll; + outp += tmp; + } + outp += list_char(buf+outp, ' '); + inp += 3; + tmp = input[inp] & 255; + } + if (tabval < 10) { + outp += list_nchar(buf+outp, ' ', 10-tabval); + } + } else { + if (tmp >= 0 && tmp < number_of_valid_tokens) { + outp += list_string(buf+outp, " "); + } + } + + if (tmp >= 0 && tmp < number_of_valid_tokens) { + /* assembler keyword */ + /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ + if (kt[tmp] != NULL) { + outp += list_string(buf+outp, kt[tmp]); + } + outp += list_sp(buf + outp); + inp += 1; +#if 0 + if (tmp == Kinclude) { + /* just another exception from the rule... */ + /* next char is terminator (", ') then the length and then the file name */ + char term = input[inp]; + int len = input[inp+1] & 255; + outp += list_char(buf+outp, term); + for (tmp = 2; tmp < len+2; tmp++) { + outp += list_char(buf+outp, input[inp+tmp]); + } + outp += list_char(buf+outp, term); + inp += len + 2; + } +#endif + } + + operator = 0; + while (inp < len) { + + switch(input[inp]) { + case T_CAST: + outp += list_string(buf+outp, formatp->escape_char(input[inp+1])); + inp+=2; + break; + case T_VALUE: + /*outp += list_char(buf+outp, 'V');*/ + /* 24 bit value */ + tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); + format = input[inp+4]; + outp += list_value(buf+outp, tmp, format); + inp += 5; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_LABEL: + /*outp += list_char(buf+outp, 'L');*/ + /* 16 bit label number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + + // duplicate label name + if (formatp->start_label != NULL) { + outp += formatp->start_label(buf+outp, l_get_unique_name(tmp)); + } + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + outp += list_string(buf+outp, name == NULL ? "" : name); + } + + if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp); + + inp += 3; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_OP: + /* label arithmetic operation; inp[3] is operation like '=' or '+' */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (input[inp+3] == '=') { + // label definition + if (formatp->set_anchor != NULL) { + outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp)); + } + } + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + outp += list_char(buf+outp, input[inp+3]); + inp += 4; + + break; + case T_END: + /* end of operation */ + /*outp += list_string(buf+outp, ";");*/ + inp += 1; + goto end; + break; + case T_COMMENT: + if (inp > 0 && inp < 20) { + outp += list_nchar(buf+outp, ' ', 20-inp); + } + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_char(buf+outp, ';'); + outp += list_string(buf+outp, (char*)input+inp+3); + inp += tmp + 3; + break; + case T_LINE: + case T_FILE: + /* those two are meta-tokens, evaluated outside the t_p2 call, + * they result in calls to list_line(), list_filename() */ + break; + case T_POINTER: + /* what is this? It's actually resolved during token conversion */ + tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); + name=l_get_name(tmp, &is_cll); + if (formatp->start_label != NULL) { + outp += formatp->start_label(buf+outp, l_get_unique_name(tmp)); + } + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + + if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp); + /* + outp += list_byte(buf+outp, input[inp+1]); + outp += list_char(buf+outp, '#'); + tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); + outp += list_value(buf+outp, tmp); + */ + inp += 6; + operator = 1; /* check if arithmetic operator follows */ + break; + case '"': { + int i, len; + + // string display + inp++; + outp += list_char(buf+outp, '"'); + len = input[inp] & 0xff; + for (i = 0; i < len; i++) { + inp++; + outp += list_char(buf+outp, input[inp]); + } + inp++; + outp += list_char(buf+outp, '"'); + break; + } + case '*': { + // If '*' appears as operand, it is the PC. We need to switch to operator then + inp++; + outp += list_char(buf+outp, '*'); + operator = 1; + break; + } + default: + c = input[inp]; + if (c > 31) { + outp += list_string(buf+outp, formatp->escape_char(input[inp])); + } else { + outp += list_char(buf+outp, '\''); + outp += list_byte(buf+outp, input[inp]); + } + inp += 1; + break; + } + + if (operator && inp < len) { + signed char op = input[inp]; + if (op > 0 && op <= 20) { // sizeof(arith_ops) + outp += list_string(buf+outp, formatp->escape(arith_ops[op])); + inp += 1; + operator = 0; + } + // note: falls through for closing brackets which are where an operator would normally be. + // closing bracket is then printed in upper (operand) part in default case before + // another operator is expected after the bracket + } + } +end: + return outp; +} + +int list_string(char *buf, char *string) { + int p = 0; + + if (buf == NULL || string == NULL) { + fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string); + fflush(stderr); + //exit(1); + return 0; + } + while (string[p] != 0) { + buf[p] = string[p]; + p++; + } + return p; +} + +int list_value(char *buf, int val, signed char format) { + int p = 0; + char valbuf[32]; + + switch (format) { + case '$': + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + case '%': + p += list_char(buf + p, '%'); + if (val & (255<<16)) { + p += list_byte_f(buf+p, val>>16,'%'); + p += list_word_f(buf+p, val,'%'); + } else + if (val & (255<<8)) { + p += list_word_f(buf+p, val,'%'); + } else { + p += list_byte_f(buf+p, val,'%'); + } + break; + case '&': + snprintf(valbuf, 32, "%o",val); + p+= list_char(buf+p, '&'); + p+= list_string(buf+p, valbuf); + break; + case 'd': + snprintf(valbuf, 32, "%d",val); + p+= list_string(buf+p, valbuf); + break; + case '\'': + case '"': + p+= list_char(buf+p, format); + p+= list_char(buf+p, val); + p+= list_char(buf+p, format); + break; + default: + /* hex format as fallback */ + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + } + return p; +} + +int list_nchar(char *buf, signed char c, int n) { + int i; + for (i = 0; i < n; i++) { + buf[i]=c; + } + return n; +} + +int list_char(char *buf, signed char c) { + buf[0] = c; + return 1; +} + +int list_sp(char *buf) { + buf[0] = ' '; + return 1; +} + +int list_word(char *buf, int outword) { + return list_word_f(buf, outword, '$'); +} + +int list_word_f(char *buf, int outword, signed char format) { + int p = 0; + p+= list_byte_f(buf+p, outword >> 8, format); + p+= list_byte_f(buf+p, outword, format); + return p; +} + +int list_byte(char *buf, int outbyte) { + return list_byte_f(buf, outbyte, '$'); +} + +int list_byte_f(char *buf, int outbyte, signed char format) { + int p = 0; + p+= list_nibble_f(buf+p, (outbyte >> 4), format); + p+= list_nibble_f(buf+p, outbyte, format); + return p; +} + +int list_nibble_f(char *buf, int outnib, signed char format) { + int p = 0; + outnib = outnib & 0xf; + switch(format) { + case '$': + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + case '%': + buf[p++] = (outnib&8)?'1':'0'; + buf[p++] = (outnib&4)?'1':'0'; + buf[p++] = (outnib&2)?'1':'0'; + buf[p++] = (outnib&1)?'1':'0'; + break; + default: + /* hex as default */ + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + } + return p; +} + + + diff --git a/xa/src/xalisting.h b/xa/src/xalisting.h new file mode 100644 index 0000000..8505047 --- /dev/null +++ b/xa/src/xalisting.h @@ -0,0 +1,34 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __XA65_XALISTING_H__ +#define __XA65_XALISTING_H__ + +void list_start(char *formatname); //either NULL or "html" +void list_end(); + +void list_flush(); // debug helper + +void list_setfile(FILE *fp); +void list_line(int l); /* set line number for the coming listing output */ +void list_filename(char *fname);/* set file name for the coming listing output */ + +// list a single line/token set +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); + +#endif /* __XA65_XALISTING_H__ */ diff --git a/xa/src/xam.c b/xa/src/xam.c index 5e4b8ef..968c8bb 100644 --- a/xa/src/xam.c +++ b/xa/src/xam.c @@ -53,10 +53,13 @@ FILE *xfopen(const char *fn,const char *mode) return NULL; } + // copy to xname by replacing windows backslashes with the proper DIRCHAR for(i=0;ifo.olist[i].len; t=afile->fo.olist[i].text; /* do not optimize */ - t_p2(t, &l, 1, &afl); + t_p2_l(t, &l, &afl); if(l>254) { errout(E_OPTLEN); diff --git a/xa/src/xap.c b/xa/src/xap.c index bdde75e..9cce78e 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -40,7 +40,8 @@ #include "xap.h" /* define this for recursive evaluation output */ -/* #define DEBUG_RECMAC */ +#undef DEBUG_RECMAC +#undef DEBUG_REPLACE char s[MAXLINE]; Datei *filep; @@ -50,24 +51,27 @@ static int pp_replace(char*,char*,int,int); static int searchdef(char*); static int fgetline(char*,int len, int *rlen, FILE*); -static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*); +/*static int icl_open(char*);*/ +static int pp_ifdef(char*),pp_ifndef(char*); static int pp_else(char*),pp_endif(char*); static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*); static int pp_ifldef(char*),pp_iflused(char*); static int pp_undef(char*); +static int pp_error(char*); -#define ANZBEF 13 -#define VALBEF 6 +#define ANZBEF 14 +#define VALBEF 7 static int quotebs = 0; static int inquote = 0; -static char *cmd[]={ "echo","include","define","undef","printdef","print", +static char *cmd[]={ +"echo","include","define","undef","printdef","print","error", /* VALBEF */ "ifdef","ifndef","else","endif", - "ifldef","iflused","if" }; + "ifldef","iflused","if" }; /* ANZBEF */ static int (*func[])(char*) = { pp_echo,icl_open,pp_define,pp_undef, - pp_prdef,pp_print, pp_ifdef,pp_ifndef, + pp_prdef,pp_print,pp_error,pp_ifdef,pp_ifndef, pp_else,pp_endif, pp_ifldef,pp_iflused,pp_if }; @@ -131,7 +135,7 @@ int pp_ifldef(char *t) int pp_iflused(char *t) { int n; - loopfl=(loopfl<<1)+( ll_search(t,&n) ? 1 : 0 ); + loopfl=(loopfl<<1)+( ll_search(t,&n,STD) ? 1 : 0 ); return(0); } @@ -177,21 +181,29 @@ int pp_print(char *t) return(0); } +int pp_error(char *t) +{ + /* the offending line is printed for us */ + return E_UERROR; +} + int pp_if(char *t) { int a,f,l,er; - if((er=pp_replace(s,t,-1,rlist))) +/* XXX: #if XYZ, if XYZ is not defined, XYZ gets treated as a label. */ + + if((er=pp_replace(s,t,-1,rlist))) { errout(er); - else + } else { dsb_len = 1; f=b_term(s,&a,&l,pc[segment]); dsb_len = 0; - if((!loopfl) && f) + if((!loopfl) && f) { errout(f); - else + } else loopfl=(loopfl<<1)+( a ? 0 : 1 ); } return(0); @@ -362,7 +374,10 @@ int pp_define(char *k) { i++; liste[rl].p_anz++; - for(j=0; t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++); + // skip whitespace before parameter name + while(isspace(t[i])) i++; + // find length + for(j=0; (!isspace(t[i+j])) && t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++); if(ji=%d, len=%d\n", n, liste[n].search,i, liste[n].s_len); +#endif + return i == liste[n].s_len; +} + +/** + * this is a break out of the original pp_replace code, as this code + * was basically duplicated for initial and recursive calls. + * + * to -> original output buffer for overflow check (only!) + * t -> where to write the output + * n -> replace macro n in liste[] + * sl -> length of liste[n].search (= liste[n].s_len) + * recursive -> + * l -> + * blist -> + * + */ +static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int *l, int blist) { - char *t=to,c,*x,*y,*mx,*rs; - int i,l,n,sl,d,ld,er=E_OK,hkfl,klfl; - char fti[MAXLINE],fto[MAXLINE]; -/* - int flag=!strncmp(ti,"TOUT",4); - if(flag) printf("flag=%d\n",flag); -*/ - (void)strcpy(t,ti); + int er = E_OK; + int i, d; + char c; - if(rlist) - { - while(t[0]!='\0') - { - /* find start of a potential token to be replaced */ - while(!isalpha(t[0]) && t[0]!='_') { - - /* escape strings quoted with " */ - if (!ppinstr && t[0] == '\"') { - do { - t++; - ti++; - } while (t[0] && t[0]!='\"'); - } + // save mem, to restore it when we don't need the pseudo replacements anymore + // Note: in a real version, that should probably be a parameter, and not fiddling + // with global variables... + char *saved_mem = mem; - /* escape strings quoted with ' */ - if (!ppinstr && t[0] == '\'') { - do { - t++; - ti++; - } while (t[0] && t[0]!='\''); - } +#ifdef DEBUG_RECMAC + printf("replace part: n=%d, sl=%d, rec=%d, %s\n", n, sl, recursive, t); +#endif - if(t[0]=='\0') - break; /*return(E_OK);*/ - else - { - t++; - ti++; - } - } - - for(l=0;isalnum(t[l])||t[l]=='_';l++); - ld=l; -/* - if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t); -*/ - if(a<0) - { - n=hashindex[hashcode(t,l)]; - - do - { - sl=liste[n].s_len; - - if(sl && (sl==l)) - { - i=0; - x=liste[n].search; - while(t[i]==*x++ && t[i]) - i++; + // yes, mark replacement string + char *rs=liste[n].replace; + + // does it have parameters? - if(i==sl) - { - rs=liste[n].replace; if(liste[n].p_anz) { + // yes, we have parameters, so we need to pp_replace them + // as well. + char fti[MAXLINE],fto[MAXLINE]; + + // copy replacement into temp buffer (void)strcpy(fti,liste[n].replace); - if(rlist+liste[n].p_anz>=ANZDEF || memfre=ANZDEF || memfre10) + if (++j>10) { + // we ran into 10 recursions deep - that does not look sound, bail out errout(E_ORECMAC); + } } +#endif + // catch an error situation if (liste[rlist+i].replace == NULL) { errout(E_ANZPAR); return E_ANZPAR; } - (void)strcpy(liste[rlist+i].replace, nfto); + + // copy over the replacement string into free memory (using mx as pointer) + (void)strcpy(mx, nfto); + // replace the pointer to the (now obsolete) old replacement with the one we just created + // Note that due to the nature of the (more or less static) memory allocation, this is not + // being freed. Oh well... + liste[blist+i].replace = mx; + mx += strlen(mx)+1; + #ifdef DEBUG_RECMAC printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); #endif } - if(!er) - er=pp_replace(fto,fti,rlist,rlist+i); + + if(!er) { + // safe-guard our memory allocations + mem = mx; + // only change (of two) from recursive: rlist is 0 there +#ifdef DEBUG_RECMAC + printf("replace macro: recursive=%d, blist=%d, -> b=%d\n", recursive, blist, blist+liste[n].p_anz); + printf(" from: %s\n", fti); +#endif + er=pp_replace(fto,fti,recursive ? 0 : blist,blist+liste[n].p_anz); +#ifdef DEBUG_RECMAC + printf(" to: %s\n", fto); +#endif + } /* if(flag) printf("sl=%d,",sl);*/ sl=(int)((long)y+1L-(long)t); /* if(flag) printf("sl=%d\n",sl);*/ rs=fto; -/* printf("->%s\n",fto);*/ +#ifdef DEBUG_RECMAC + printf("->%s\n",fto); +#endif } } - if(er) + if(er) { + mem = saved_mem; return(er); - } + } + } // end if(liste[n].p_anz), i.e. if it has parameters d=(int)strlen(rs)-sl; - if(strlen(to)+d>=MAXLINE) + if(strlen(to)+d>=MAXLINE) { + mem = saved_mem; return(E_NOMEM); + } /* if(d<0) @@ -628,129 +721,155 @@ int pp_replace(char *to, char *ti, int a,int b) t[ll+d]=t[ll]; } */ - if(d) - (void)strcpy(t+sl+d,ti+sl); + if(d) { + // d can be positive or negative, so strcpy cannot be used, use memmove instead + (void)memmove(t+sl+d,t+sl, strlen(t) - sl + 1); + } i=0; - while((c=rs[i])) + while((c=rs[i])) { t[i++]=c; - l=sl+d;/*=0;*/ - break; - } + } + // other change from recursive. there sl is missing from add + //*l=(recursive ? 0 : sl) + d;/*=0;*/ + *l=sl + d;/*=0;*/ + + mem = saved_mem; + + return (er); +} + +/** + * copy the input string pointed to by ti into + * an output string buffer pointed to by to, replacing all + * preprocessor definitions in the process. + * + * Note: this method is called recursively, with "a" being -1 + * when called from the "outside" respectively in a new context + * (like macro parameters) + * + * The "b" parameter denotes the index in the list from which on + * pseudo replacement entries are being created for replacement + * parameters + * + */ +int pp_replace(char *to, char *ti, int a,int b) +{ + char *t=to; + int l,n,sl,er=E_OK; + int ld; // length of name/token to analyse +/* + int flag=!strncmp(ti,"TOUT",4); + if(flag) printf("flag=%d\n",flag); +*/ + // t points to to, so copy input to output 1:1 + // then below work on the copy in-place + (void)strcpy(t,ti); + + // if there are replacements in the list of replacements + if(rlist) + { + // loop over the whole input + while(t[0]!='\0' && t[0] != ';') + { + // skip over the whitespace + // comment handling is NASTY NASTY NASTY + // but I currently don't see another way, as comments and colons + // can (and do) appear in preprocessor replacements + char quotefl = 0; + char commentfl = 0; + while((t[0] != 0) && (quotefl || commentfl || ((!isalpha(t[0]) && t[0]!='_')))) { + if (t[0]=='\0') { + break; /*return(E_OK);*/ + } else + { + if (t[0] == ';' && !quotefl) { + commentfl = 1; + } + if (t[0] == ':' && !quotefl && !ca65 && !masm) { + // note that both ca65 and masm allow colons in comments + // so in these cases we cannot reset the comment handling here + commentfl = 0; + } + if (quotefl) { + // ignore other quotes within a quote + if (t[0] == quotefl) { + quotefl = 0; + } + } else + if (t[0] == '"' || t[0] == '\'') { + quotefl = t[0]; + } + t++; + ti++; + } + } + + // determine the length of the name + for(l=0;isalnum(t[l])||t[l]=='_';l++); + // store in ld + ld=l; +#ifdef DEBUG_RECMAC + printf("l=%d,a=%d,b=%d, t=%s\n",l,a, b ,t); +#endif + + // the following if() is executed when being called from an + // 'external' context, i.e. not from a recursion + if(a<0) + { + // when called from an external context, not by recursion + + // compute hashcode for the name for the search index entry (liste[n]) + n=hashindex[hashcode(t,l)]; + + // loop over all entries in linked list for hash code (think: hash collisions) + do // while(1); + { + // length of name of pp definition + sl=liste[n].s_len; + +#ifdef DEBUG_RECMAC + printf("macro entry: name=%s, sl=%d, p_anz=%d\n", liste[n].search, sl, liste[n].p_anz); +#endif + // does pp definition match what we have found? + if(sl && (sl==l) && check_name(t, n)) + { + er = pp_replace_part(to, t, n, sl, 0, &l, b); + if (er != E_OK) { + return er; + } + break; } if(!n) break; - + + // next index in linked list for given hash code n=liste[n].nextindex; } while(1); } else { + // called when in recursive call + // loop over all the replacement entries from the given b down to 0 + // that allows to replace the parameters first (as they were added at + // the end of the list) for(n=b-1;n>=a;n--) { sl=liste[n].s_len; - if(sl && (sl==l)) + if(sl && (sl==l) && check_name(t, n)) { - i=0; - x=liste[n].search; - while(t[i]==*x++ && t[i]) - i++; - - if(i==sl) - { - rs=liste[n].replace; - if(liste[n].p_anz) - { - (void)strcpy(fti,liste[n].replace); - if(rlist+liste[n].p_anz>=ANZDEF || memfre=MAXLINE) - return(E_NOMEM); -/* - if(d<0) - { - y=t+sl+d; - x=t+sl; - while(*y++=*x++); - } - if(d>0) - { - for(ll=strlen(t);ll>=sl;ll--) - t[ll+d]=t[ll]; - } -*/ - if(d) - (void)strcpy(t+sl+d,ti+sl); - - i=0; - while((c=rs[i])) - t[i++]=c; - l+=d;/*0;*/ - break; - } + er = pp_replace_part(to, t, n, sl, 1, &l, b); + break; } } } + // advance input by length of name ti+=ld; + // advance output by l t+=l; - } - } + } /* end while(t[0] != 0) */ + } /* end if(rlist) */ return(E_OK); } @@ -774,6 +893,11 @@ int pp_init(void) if(!er) { liste=malloc((long)ANZDEF*sizeof(List)); if(!liste) er=E_NOMEM; + if(!er && !xa23) { + er = pp_define("XA_MAJOR " progmajor); + if (!er) er = pp_define("XA_MINOR " progminor); + if (!er) er = pp_define("XA_PATCH " progpatch); + } } return(er); } @@ -781,17 +905,20 @@ int pp_init(void) int pp_open(char *name) { FILE *fp; + int l; fp=xfopen(name,"r"); + l = strlen(name); + /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ - flist[0].fname = malloc(strlen(name)+1); + flist[0].fname = malloc(l+1); if(!flist[0].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } - (void)strcpy(flist[0].fname,name); + (void)strncpy(flist[0].fname,name,l+1); flist[0].fline=0; flist[0].bdepth=b_depth(); flist[0].filep=fp; @@ -835,7 +962,8 @@ int icl_close(int *c) int icl_open(char *tt) { FILE *fp2; - int j,i=0; + char *namep; + int len,j,i=0; pp_replace(s,tt,-1,rlist); @@ -858,14 +986,17 @@ int icl_open(char *tt) fsp++; + namep = s+i; + len = strlen(namep); + /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ - flist[fsp].fname = malloc(strlen(s+i)+1); + flist[fsp].fname = malloc(len+1); if(!flist[fsp].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } - strcpy(flist[fsp].fname,s+i); + strncpy(flist[fsp].fname,namep, len+1); flist[fsp].fline=0; flist[fsp].bdepth=b_depth(); flist[fsp].flinep=NULL; @@ -875,6 +1006,7 @@ int icl_open(char *tt) return(0); } + int pgetline(char *t) { int c,er=E_OK; @@ -887,32 +1019,43 @@ int pgetline(char *t) filep =flist+fsp; do { - c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep); - /* continuation lines */ - tlen = rlen; - while(c=='\n' && tlen && in_line[tlen-1]=='\\') { - c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep); - tlen += rlen-1; + int is_continuation = 0; + tlen = 0; // start of current line in in_line[] + do { + c=fgetline(in_line + tlen, MAXLINE - tlen, &rlen, flist[fsp].filep); + //fprintf(stderr, "fgetline -> c=%02x, rlen->%d, t->%s\n", c, rlen, in_line+tlen); + + /* check for continuation lines */ + is_continuation = ((c == '\n') && (rlen > 0) && (in_line[tlen + rlen - 1]=='\\')); + if (is_continuation) { + // cut off the continuation character + rlen--; + in_line[tlen + rlen] = 0; } - if(in_line[0]=='#' || in_line[0] == altppchar) - { + + tlen += rlen; + } while (is_continuation); + + if(in_line[0]=='#' || in_line[0] == altppchar) + { if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't handle this right */ er=pp_cpp(in_line+1); } else { - if((er=pp_comand(in_line+1))) - { - if(er!=1) - { - logout(in_line); - logout("\n"); - } - } + if((er=pp_comand(in_line+1))) + { + if(er!=1) + { + logout(in_line); + logout("\n"); + } + } } - } else + } else { er=1; + } - if(c==EOF) { + if(c==EOF) { if (loopfl && fsp) { char bletch[MAXLINE]; sprintf(bletch, @@ -936,8 +1079,15 @@ int pgetline(char *t) er= (er==1) ? E_OK : er ; - if(!er) + if(!er) { +#ifdef DEBUG_REPLACE +// printf("<<<: %s\n", in_line); +#endif er=pp_replace(t,in_line,-1,rlist); +#ifdef DEBUG_REPLACE + printf(">>>: %s\n", t); +#endif + } if(!er && nff) er=E_NEWFILE; @@ -947,7 +1097,8 @@ int pgetline(char *t) filep=flist+fsp; filep->flinep=in_line; - + + //fprintf(stderr, "pgetline -> er=%d, t=%s\n", er, t); return(er); } @@ -988,8 +1139,9 @@ int rgetc(FILE *fp) nlf=1; } - /* check for start of comment anyway, to allow for nestesd comments */ - if(!inquote && c=='/') + /* check for start of comment anyway, to allow for nested comments */ + /* only allow this with 2.3 compatibility */ + if(!inquote && c=='/' && (xa23 || !incomment)) { d = getc(fp); @@ -998,6 +1150,10 @@ int rgetc(FILE *fp) do { c = getc(fp); } while (c != '\n' && c != EOF); + if (c == '\n') { + flist[fsp].fline++; + nlf=1; + } } else if (d == '*') { /* start block comment */ @@ -1037,19 +1193,15 @@ int rgetc(FILE *fp) inquote ^= 1; } -#if(0) -/* implement backslashed quotes for 2.4 */ - if(c=='\\') quotebs=1; else quotebs=0; -#endif - - + /* implement backslashed quotes for 2.4 */ + if(!xa23 && c=='\\') quotebs=1; else quotebs=0; } else { /* in comment */ /* check for end of comment */ - /* note: incomment only set true if not quoted, and quote not changed in comment */ - if((!inquote) && (c=='*')) + /* note: for xa2.3, incomment only set true if not quoted, and quote not changed in comment */ + if((!inquote || !xa23) && (c=='*')) { if((d=getc(fp))!='/') { d_isvalid = 1; @@ -1075,6 +1227,11 @@ int rgetc(FILE *fp) return(c-'\t'?c:' '); } +/** + * Note that the line returned is always zero-terminated, + * the rlen out parameter is just convenience, so that + * a further strlen() can be saved + */ int fgetline(char *t, int len, int *rlen, FILE *fp) { static int c,i; diff --git a/xa/src/xap.h b/xa/src/xap.h index 5d87778..79da7a4 100644 --- a/xa/src/xap.h +++ b/xa/src/xap.h @@ -30,6 +30,9 @@ void pp_end(void); int pgetline(char *t); Datei *pp_getidat(void); +/* needed for .include pseudo opcode */ +int icl_open(char*); + int ga_pp(void); int gm_pp(void); long gm_ppm(void); diff --git a/xa/src/xar.c b/xa/src/xar.c index 25d9aae..3ebc2d5 100644 --- a/xa/src/xar.c +++ b/xa/src/xar.c @@ -30,22 +30,30 @@ #include "xao.h" #include "xau.h" +#undef DEBUG_RELOC + File *afile = NULL; int rmode = RMODE_RELOC; +/* int r_set(int pc, int afl, int l) { -/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d\n",pc, l, afl,segment);*/ if(segment==SEG_TEXT) return rt_set(pc,afl,l,0); if(segment==SEG_DATA) return rd_set(pc,afl,l,0); return 0; } +*/ int u_set(int pc, int afl, int label, int l) { -/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n", - pc, l, afl,segment, label);*/ - if((afl & A_FMASK) == (SEG_UNDEF<<8)) +#ifdef DEBUG_RELOC +printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n", + pc, l, afl,segment, label); +#endif + if(((afl & A_FMASK) == (SEG_UNDEF<<8)) + || ((afl & A_FMASK) == (SEG_UNDEFZP<<8)) + ) { label = u_label(label); /* set label as undefined */ + } if(segment==SEG_TEXT) return rt_set(pc,afl,l,label); if(segment==SEG_DATA) return rd_set(pc,afl,l,label); return 0; @@ -77,7 +85,9 @@ int rt_set(int pc, int afl, int l, int lab) { /*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/ } if(l==1 && ((afl&A_MASK)==A_ADR)) { - if((afl & A_FMASK) != (SEG_ZERO<<8)) { + if(((afl & A_FMASK) != (SEG_ZERO<<8)) + && ((afl & A_FMASK) != (SEG_UNDEFZP<<8)) + ) { /*printf("afl=%04x\n",afl);*/ errout(W_ADRRELOC); } @@ -147,10 +157,16 @@ int rt_write(FILE *fp, int pc) { } fputc(pc2-pc, fp); pc=pc2; - fputc((afl>>8)&255, fp); - if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { + if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) { + fputc( (((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp); + fputc(afile->rt.rlist[p].lab & 255, fp); + fputc((afile->rt.rlist[p].lab>>8) & 255, fp); + } else { + fputc( (afl>>8)&255, fp); + if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { fputc(afile->rt.rlist[p].lab & 255, fp); fputc((afile->rt.rlist[p].lab>>8) & 255, fp); + } } if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); } diff --git a/xa/src/xar.h b/xa/src/xar.h index 01aa887..947c618 100644 --- a/xa/src/xar.h +++ b/xa/src/xar.h @@ -25,7 +25,7 @@ extern File *alloc_file(void); /* jumps to r[td]_set, depending on segment */ -int r_set(int pc, int reloc, int len); +/*int r_set(int pc, int reloc, int len);*/ int u_set(int pc, int reloc, int label, int len); int rt_set(int pc, int reloc, int len, int label); diff --git a/xa/src/xar2.c b/xa/src/xar2.c index fcf87b1..5075917 100644 --- a/xa/src/xar2.c +++ b/xa/src/xar2.c @@ -111,11 +111,17 @@ int rd_write(FILE *fp, int pc) { } fputc(pc2-pc, fp); pc=pc2; - fputc((afl>>8)&255, fp); - if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { + if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) { + fputc((((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp); + fputc(afile->rd.rlist[p].lab & 255, fp); + fputc((afile->rd.rlist[p].lab>>8) & 255, fp); + } else { + fputc((afl>>8)&255, fp); + if(((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8))) { fputc(afile->rd.rlist[p].lab & 255, fp); fputc((afile->rd.rlist[p].lab>>8) & 255, fp); - } + } + } if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); } p=afile->rd.rlist[p].next; diff --git a/xa/src/xat.c b/xa/src/xat.c index 88d5342..4a71e11 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -21,12 +21,16 @@ */ /* enable this to turn on (copious) optimization output */ -/* -#define DEBUG_AM -*/ + +#undef LISTING_DEBUG +#undef DEBUG_CONV +#undef DEBUG_CAST +#undef DEBUG_RELOC +#undef DEBUG_AM #include #include +#include #include "xad.h" #include "xah.h" @@ -40,6 +44,7 @@ #include "xao.h" #include "xap.h" #include "xacharset.h" +#include "xalisting.h" int dsb_len = 0; @@ -50,10 +55,24 @@ static void tg_dez(signed char*,int*,int*); static void tg_hex(signed char*,int*,int*); static void tg_oct(signed char*,int*,int*); static void tg_bin(signed char*,int*,int*); +static int t_p2(signed char *t, int *ll, int fl, int *al); +//static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); + +void list_setbytes(int number_of_bytes_per_line); /* assembly mnemonics and pseudo-op tokens */ /* ina and dea don't work yet */ -static char *kt[] ={ +/* Note AF 20110624: added some ca65 compatibility pseudo opcodes, + * many are still missing (and will most likely never by supported in this + * code base). Potential candidates are .hibytes, .lobytes, .asciiz, + * .addr, .charmap, .dbyt, .faraddr, .bankbytes, .segment (at least for the known ones) + * .incbin is similar to our .bin, but with parameters reversed (argh...) + * I like the .popseg/.pushseg pair; + * .global/.globalzp is equivalent to forward-defining a label in the global block + * .export/.exportzp could be implemented with a commandline switch to NOT export + * global labels, where .exported labels would still be exported in an o65 file. + */ +char *kt[] ={ /* 1 2 3 4 5 6 7 8 9 10 */ "adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi", "bne","bpl","bra","brk","bvc","bvs","brl","clc","cld","cli", @@ -77,11 +96,26 @@ static char *kt[] ={ ".byt",".word",".asc",".dsb", ".(", ".)", "*=", ".text",".data",".bss", ".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw", - ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc" + ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code", + ".include", ".import", ".importzp", ".proc", ".endproc", + ".zeropage", ".org", ".reloc", ".listbytes", + ".scope", ".endscope", ".assert" }; -static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; +/* arithmetic operators (purely for listing, parsing is done programmatically */ +char *arith_ops[] = { + "", "+", "-", // 0,1,2 + "*", "/", // 3,4 + ">>", "<<", // 5,6 + "<", ">", "=", // 7,8,9 + "<=", ">=", "<>", // 10,11,12 + "&", "^", "|", // 13,14,15 + "&&", "||", "==", "!=", "!" // 16,17,18 (9),19 (12),20 (NYI) +}; + +/* length of arithmetic operators indexed by operator number */ +static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2,2,2,1 }; /* mvn and mvp are handled specially, they have a weird syntax */ #define Kmvp 38 @@ -90,8 +124,6 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; /* index into token array for pseudo-ops */ /* last valid mnemonic */ #define Lastbef 93 -/* last valid token+1 */ -#define Anzkey 123 #define Kbyt Lastbef+1 #define Kword Lastbef+2 @@ -125,8 +157,33 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #define Kbin Lastbef+28 #define Kaasc Lastbef+29 -#define Kreloc Anzkey /* *= (relocation mode) */ -#define Ksegment Anzkey+1 +#define Kcode Lastbef+30 /* gets remapped to Ktext */ + +/* 93 + 30 -> 123 */ + +#define Kinclude Lastbef+31 +#define Kimport Lastbef+32 +#define Kimportzp Lastbef+33 +#define Kproc Lastbef+34 /* mapped to Kopen */ +/* 93 + 35 -> 128 */ +#define Kendproc Lastbef+35 /* mapped to Kclose */ +#define Kzeropage Lastbef+36 /* mapped to Kzero */ +#define Korg Lastbef+37 /* mapped to Kpcdef - with parameter equivalent to "*=$abcd" */ +#define Krelocx Lastbef+38 /* mapped to Kpcdef - without parameter equivalent to "*=" */ +#define Klistbytes (Lastbef+39-256) +#define Kscope (Lastbef+40) /* mapped to Kopen */ +#define Kendscope (Lastbef+41) /* mapped to Kclose */ + +#define Kassert (Lastbef+42-256) + +/* last valid token+1 */ +#define Anzkey Lastbef+43 /* define last valid token number; last define above plus one */ + + +#define Kreloc (Anzkey-256) /* *= (relocation mode) */ +#define Ksegment (Anzkey+1-256) /* this actually now is above 127, which might be a problem as char is signed ... */ + +int number_of_valid_tokens = Anzkey; /* array used for hashing tokens (26 entries, a-z) */ @@ -325,16 +382,21 @@ static int le[] ={ 1,2,2,2,2,2,2,2,3,3,3,2,3,3,3,2, static int opt[] ={ -1,-1,-1,-1,-1,-1,-1,-1,1,2,3,-1,4,5,-1,-1, /*new*/ -1,8,9,-1,-1,-1,-1,-1 }; /* abs -> zp */ +/*********************************************************************************************/ /* pass 1 */ int t_p1(signed char *s, signed char *t, int *ll, int *al) { static int er,l,n,v,nk,na1,na2,bl,am,sy,i,label,byte; /*,j,v2 ;*/ int afl = 0; + int tlen; /* token listing length, to adjust length that is returned */ + int inp; /* input pointer in t[] */ + unsigned char cast; /* notes and typical conventions ... er = error code am = addressing mode in use */ + cast='\0'; bl=0; *al = 0; @@ -344,22 +406,71 @@ int t_p1(signed char *s, signed char *t, int *ll, int *al) #ifdef DEBUG_AM fprintf(stderr, "- p1 %d starting -\n", pc[segment]); #endif - er=t_conv(s,t,&l,pc[segment],&nk,&na1,&na2,0,&byte); - /* leaving our token sequence in t */ + + /* As the t_p1 code below always works through the tokens + * from t_conv in such a way that it always produces a shorter + * result, the conversion below takes place "in place". + * This, however, means that the original token sequence, which + * would be useful for some assembler listing, is overwritten. + * While the original assumption was ok for a constrained + * environment like the Atari ST, this is no longer true. + * Converting the code below to have separate input and output + * areas would be error-prone, so we do some copy-magic here + * instead...*/ + /* we keep three bytes buffer for "T_LISTING" and the length of the + * token list + */ + t[0]=T_LISTING; + er=t_conv(s,t+6,&l,pc[segment],&nk,&na1,&na2,0,&byte); + tlen = l+6; + t[1]=tlen&255; + t[2]=(tlen>>8)&255; + t[3]=segment; + t[4]=pc[segment]&255; + t[5]=(pc[segment]>>8)&255; + /* now we have to duplicate the token sequence from the T_LISTING buffer + * to the end of "t", so we can then in-place convert it + * below. Non-overlapping, size is known in advance, so + * using memcpy is fine here + */ + inp = 0; + /* discard label definitions before copying the buffer, so we don't get + * label defined errors */ + while (inp1) && (t[0]1) && (t[inp]base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length(); romable=1; } - if(!er) { @@ -368,33 +479,71 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); * pseudo-op dispatch (except .byt, .asc) * */ - n=t[0]; + // fix sign + n=t[0]; // & 0xff; + /* TODO: make that a big switch statement... */ /* maybe later. Cameron */ if(n==Kend || n==Klist || n==Kxlist) { *ll = 0; /* ignore */ } else + if(n==Kinclude) { + *ll = 0; /* no output length */ + i=1; + if(t[i]=='\"') { + int k,j=0; + char binfname[255]; + i++; + k=t[i]+i+1; + i++; + while(i 255) + er = E_NOMEM; /* buffer overflow */ + } + binfname[j] = '\0'; + er=icl_open(binfname); + } else { + er=E_SYNTAX; + } + } else if(n==Kfopt) { if(romable==1) er=E_ROMOPT; t[0] = Kbyt; set_fopt(l,t,nk+1-na1+na2); *ll = 0; } else + if(n==Klistbytes) { + int p = 0; + if(!(er=a_term(t+1,&p,&l,pc[segment],&afl,&label,0))) { + er=E_OKDEF; + } + *ll = 3; + t[0] = Klistbytes; + t[1] = p & 0xff; + t[2] = (p >> 8) & 0xff; + //printf("Klistbytes p1: er=%d, l=%d\n", er, l); + } else if(n==Kpcdef) { int tmp; - if(!(er=a_term(t+1,&tmp /*&pc[SEG_ABS]*/,&l,pc[segment],&afl,&label,0))) + // get parameter for *= + er=a_term(t+1,&tmp,&l,pc[segment],&afl,&label,0); + // found? + if(!er) { i=1; - wval(i,tmp /*pc[SEG_ABS]*/); + wval(i,tmp, 0); /* writes T_VALUE, 3 bytes value, plus one byte */ t[i++]=T_END; - *ll=6; + *ll=7; er=E_OKDEF; -/*printf("set pc=%04x, oldsegment=%d, pc[segm]=%04x, ", +#ifdef DEBUG_RELOC +printf("set pc=%04x, oldsegment=%d, pc[segm]=%04x, ", pc[SEG_ABS], segment, pc[segment]); -printf(" wrote %02x %02x %02x %02x %02x %02x\n", - t[0],t[1],t[2],t[3],t[4],t[5]);*/ +printf(" wrote %02x %02x %02x %02x %02x %02x, %02x, %02x\n", + t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7]); +#endif if(segment==SEG_TEXT) { pc[SEG_ABS] = tmp; r_mode(RMODE_ABS); @@ -406,15 +555,19 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", } } /*printf("newsegment=%d, pc[ABS]=%04x\n", segment, pc[SEG_ABS]);*/ - } else { /* TODO: different error code */ + } else { + // no param found, only "*=". + // if we ABS, we switch back to reloc +#ifdef DEBUG_RELOC +printf("reloc: er=%d, l=%d, segment=%d, pc[%d]=%04x, pc[abs(%d)]=%04x, pc[text(%d)]=%04x\n", + er, l, segment, segment, pc[segment], SEG_ABS, pc[SEG_ABS],SEG_TEXT, pc[SEG_TEXT]); +#endif if((segment==SEG_ABS) && (er==E_SYNTAX && l==0)) { -/*printf("reloc: oldseg=%d, pc[oldseg]=%04x, pc[abs]=%04x, pc[text]=%04x\n", - segment, pc[segment], pc[SEG_ABS], pc[SEG_TEXT]);*/ t[0]=Kreloc; i=1; - wval(i,pc[SEG_TEXT]); + wval(i,pc[SEG_TEXT], 0); t[i++]=T_END; - *ll=6; + *ll=7; er=E_OKDEF; r_mode(RMODE_RELOC); /*printf(" : newseg=%d, pc[newseg]=%04x, pc[abs]=%04x, pc[text]=%04x\n", @@ -479,6 +632,7 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", dsb_len = 0; } else if(n==Ktext) { + r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode segment = relmode ? SEG_TEXT : SEG_ABS; t[0]=Ksegment; t[1]=segment; @@ -487,6 +641,7 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", } else if(n==Kdata) { if(relmode) { + r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode segment = SEG_DATA; t[0]=Ksegment; t[1]=SEG_DATA; @@ -498,6 +653,7 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", } else if(n==Kbss) { if(relmode) { + r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode segment = SEG_BSS; t[0]=Ksegment; t[1]=SEG_BSS; @@ -509,6 +665,7 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", } else if(n==Kzero) { if(relmode) { + r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode segment = SEG_ZERO; t[0]=Ksegment; t[1]=SEG_ZERO; @@ -518,6 +675,48 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", er=E_ILLSEGMENT; } } else + if (n==Kassert) { /* ignore this in first pass, just check syntax */ + int x; + i = 1; + + /* XXX: sadly, can't implement unary logical not yet */ + if(!(er=a_term(t+i,&x,&l,pc[segment],&afl,&label,1))) { + i += l; + } + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + /* get filename. + the tokenizer can either see it as a multichar string ... */ + if (!er) { + int k; + + if(t[i]=='\"') { + i++; + k=t[i]+i+1; + i++; + while(i er=%d\n", er); +#endif } } else if(er==E_NODEF) { -/* - * no label was found from t_conv! - * try to figure out most likely length - * - */ + /* + * no label was found from t_conv! + * try to figure out most likely length + * + */ #ifdef DEBUG_AM fprintf(stderr, "E_NODEF pass1 xat.c\n"); @@ -686,19 +889,37 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); if(n>=0 && n<=Lastbef && n != Kmvn && n != Kmvp) /* not for mvn/p */ { - if(t[1]==T_END) + int inp = 1; /* input pointer */ + + if(t[inp]==T_END || t[inp]==T_COMMENT) { sy=0; /* implied */ + inp++; } else - if(t[1]=='#') + if(t[inp]=='#') { sy=1+nk; /* immediate */ + inp++; } else - if(t[1]=='(') + if(t[inp]=='(') { sy=7+nk; /* computed */ - } else + inp++; + } else { sy=4+nk; /* absolute or zero page */ + } + + /* this actually finds the cast for all addressing modes, + but t_conv() only puts it there for immediate (#) or absolute/ + absolute indexed addressing modes */ + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; +#ifdef DEBUG_CAST + printf("Found cast to: %c\n", cast); +#endif + } /* length counter set to maximum length + 1 */ if (w65816 || (t[l-1]=='@' || t[l-1] == '!')) { @@ -744,20 +965,21 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); /* optimize operand length for 24-bit quantities */ /* look at cast byte from t_conv */ - if (t[l-1]!='@' && t[l-1] != '!') + + if (cast!='@' && cast!= '!') { if(bl && !er && opt[am]>=0 && am>16) /* <<< NOTE! */ if(ct[n][opt[am]]>=0) am=opt[am]; } /* if ` is declared, force further optimization */ - if (t[l-1]=='`') { + if (cast=='`') { if (opt[am]<0 || ct[n][opt[am]]<0) errout(E_ADRESS); am=opt[am]; } /* if ! is declared, force to 16-bit quantity */ - if (t[l-1]=='!' && am>16 && opt[am]>=0 && bl) { + if (cast=='!' && am>16 && opt[am]>=0 && bl) { am=opt[am]; } @@ -781,6 +1003,48 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); /* .byt, .asc, .word, .dsb, .fopt pseudo-op dispatch */ } else + if(n==Kimportzp) { + int i; + *ll=0; /* no output */ + bl = 0; /* no output length */ + /* import labels; next follow a comma-separated list of labels that are + imported. Tokenizer has already created label entries, we only need to + set the flags appropriately */ + i=1; +/*printf("Kimport: t[i]=%d\n",t[i]);*/ + while(t[i]==T_LABEL) { + int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */ +/*printf("lg_import: %d\n",n);*/ + lg_importzp(n); + i+=3; + while (t[i]==' ') i++; + if (t[i]!=',') break; + i++; + while (t[i]==' ') i++; + } + er=E_NOLINE; + } else + if(n==Kimport) { + int i; + *ll=0; /* no output */ + bl = 0; /* no output length */ + /* import labels; next follow a comma-separated list of labels that are + imported. Tokenizer has already created label entries, we only need to + set the flags appropriately */ + i=1; +/*printf("Kimport: t[i]=%d\n",t[i]);*/ + while(t[i]==T_LABEL) { + int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */ +/*printf("lg_import: %d\n",n);*/ + lg_import(n); + i+=3; + while (t[i]==' ') i++; + if (t[i]!=',') break; + i++; + while (t[i]==' ') i++; + } + er=E_NOLINE; + } else if(n==Kmvn || n==Kmvp) { bl=3; @@ -829,29 +1093,129 @@ fprintf(stderr, "guessing instruction length is %d\n", bl); if(segment==SEG_TEXT) pc[SEG_ABS]+=bl; if(segment==SEG_ABS) pc[SEG_TEXT]+=bl; + /* adjust length by token listing buffer length */ +#ifdef DEBUG_CONV + printf("converted: (er=%d, t=%p, ll=%d, tlen=%d):",er, t, *ll, tlen); + for(i=0;i<*ll;i++) + printf("%02x,",t[i] & 0xff); + printf("\n"); + printf("adjusted len=%d\n", *ll+tlen); +#endif + + *ll = *ll + tlen; return(er); } -/*t_pass 2*/ +/*********************************************************************************************/ +/* t_pass 2 + * + * *t is the token list as given from pass1 + * *ll is the returned length of bytes (doubles as + * input for whether OK or OKDEF status from pass1) + * fl defines if we allow zeropage optimization + * + * Conversion takes place "in place" in the *t array. + */ + +/** + * function called from the main loop, where "only" the + * undefined labels have to be resolved and the affected + * opcodes are assembled, the rest is passed through from + * pass1 (pass-through is done in t_p2, when *ll<0) + * As this is not called from p1, assume that we do not + * do length optimization + * + * *t is the input token list + * *ll is the input length of the token list, + * and the output of how many bytes of the buffer are to be taken + * into the file; note that for .dsb and .bin, this does NOT match + * the length in the internal data structures! + */ +int t_p2_l(signed char *t, int *ll, int *al) +{ + int er = E_OK; + int l = *ll; + + if (l < 0) l = -l; + +#if 0 + { + printf("t_p2_l (ll=%d, t=%p):", *ll, t); + for(int i=0;i l) + { + int i; + + // that is corrupt data and should not happen + list_flush(); + printf("corrupt: t_p2_l (l=%d, tlen=%d, ll=%d, t=%p):", l, tlen, *ll, t); + for(i=0;i0 bei E_OKDEF */ + if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF */ { *ll=-*ll; bl=*ll; er=E_OK; + } else { n=t[0]; @@ -867,7 +1231,8 @@ int t_p2(signed char *t, int *ll, int fl, int *al) v2=v; } else { if( (!(er=l_get(n,&v2, &afl))) - && ((afl & A_FMASK)!=(SEG_UNDEF<<8)) ) + && ((afl & A_FMASK)!=(SEG_UNDEF<<8)) + && ((afl & A_FMASK)!=(SEG_UNDEFZP<<8)) ) { if(t[3]=='+') { @@ -922,7 +1287,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) { i=1; j=0; - while(!er && t[i]!=T_END) + while(!er && t[i]!=T_END && t[i] != T_COMMENT) { if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) { @@ -933,7 +1298,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) t[j++]=(v>>8)&255; i+=l; - if(t[i]!=T_END && t[i]!=',') + if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',') er=E_SYNTAX; else if(t[i]==',') @@ -944,6 +1309,57 @@ int t_p2(signed char *t, int *ll, int fl, int *al) *ll=j; bl=j; } else + if (n == Kassert) + { + int result = 0; + int c; + i = 1; + + /* this time, actually check something */ + if(!(er=a_term(t+i,&result,&l,pc[segment],&afl,&label,1))) { + i += l; + } + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + /* get filename. + the tokenizer can either see it as a multichar string ... */ + if (!er) { + int k; + + if (!result) + fprintf(stderr, "Assertion failed: "); + if(t[i]=='\"') { + i++; + k=t[i]+i+1; + i++; + while(i> 8); - t[j++] = (v & 0x00ff); - } else { - t[j++] = v; - } + if (v & 0xff00) + er=E_ILLQUANT; + else + t[j++]=v; } if (j > 3) er=E_SYNTAX; - if(t[i]!=T_END && t[i]!=',') + if(t[i]!=T_END && t[i]!=T_COMMENT && t[i]!=',') er=E_SYNTAX; else if(t[i]==',') @@ -1121,7 +1530,7 @@ fprintf(stderr, "mvn mvp: %i %i %i %i %i\n", t[0], t[i], wide, i, j); } else if(n==Kasc || n==Kbyt || n==Kaasc) { i=1; j=0; - while(!er && t[i]!=T_END) + while(!er && t[i]!=T_END && t[i] != T_COMMENT) { if(t[i]=='\"') { @@ -1145,7 +1554,7 @@ fprintf(stderr, "mvn mvp: %i %i %i %i %i\n", t[0], t[i], wide, i, j); } } } - if(t[i]!=T_END && t[i]!=',') + if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',') er=E_SYNTAX; else if(t[i]==',') @@ -1195,6 +1604,14 @@ fprintf(stderr, "mvn mvp: %i %i %i %i %i\n", t[0], t[i], wide, i, j); pc[segment] = npc; /*printf("Kreloc: newsegment=%d, pc[seg]=%04x\n", segment, pc[segment]);*/ } else + if(n==Klistbytes) { + int nbytes = (t[1] & 0xff) + (t[2] << 8); + //printf("Klistbytes --> er=%d, nbytes=%d\n", er, nbytes); + list_setbytes(nbytes); + l = 2; + *ll=0; + bl =0; + } else if(n==Ksegment) { segment = t[1]; *ll=0; @@ -1206,7 +1623,7 @@ fprintf(stderr, "mvn mvp: %i %i %i %i %i\n", t[0], t[i], wide, i, j); if(!(er=a_term(t+1,&j,&i,pc[segment],&afl,&label,0))) { if (j<0) - er=E_SYNTAX; + er=E_NEGDSBLEN; else /* if(t[i+1]!=',') @@ -1244,47 +1661,59 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } dsb_len = 0; } else - if(n<=Lastbef) + if(n>=0 && n<=Lastbef) { -/* instruction */ - if((c=t[1])=='#') + int inp = 1; /* input pointer */ + signed char cast = '\0'; /* cast value */ + + c = t[inp]; + + if(c=='#') { - i=2; + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; +#ifdef DEBUG_CAST + printf("Found cast to (2): %c\n", cast); +#endif + } sy=1; - if(!(er=a_term(t+i,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { /* if(1) printf("a_term returns afl=%04x\n",afl); */ rlt[0] = afl; lab[0] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp] != T_COMMENT) { - if(t[i]!=',') + if(t[inp]!=',') er=E_SYNTAX; else { - i++; + inp++; sy++; - if(!(er=a_term(t+i,vv+1,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv+1,&l,pc[segment],&afl,&label,1))) { rlt[1] = afl; lab[1] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp] != T_COMMENT) { - if(t[i]!=',') + if(t[inp]!=',') er=E_SYNTAX; else { - i++; + inp++; sy++; - if(!(er=a_term(t+i,vv+2,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv+2,&l,pc[segment],&afl,&label,1))) { rlt[2] = afl; lab[2] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } @@ -1294,38 +1723,51 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } } } else - if(c==T_END) + if(c==T_END || c==T_COMMENT) { sy=0; } else if(c=='(') { + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; +#ifdef DEBUG_CAST + printf("Found cast to (3): %c\n", cast); +#endif + } sy=7; - if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[2+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[2+l]==',') + if(t[inp]==',') { - if (tolower(t[3+l])=='x') + inp++; + if (tolower(t[inp])=='x') sy=8; else sy=13; } else - if(t[2+l]==')') + if(t[inp]==')') { - if(t[3+l]==',') + inp++; + if(t[inp]==',') { - if(tolower(t[4+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=9; else er=E_SYNTAX; } else - if(t[3+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } else @@ -1334,24 +1776,36 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } else if(c=='[') { + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; +#ifdef DEBUG_CAST + printf("Found cast to (4): %c\n", cast); +#endif + } sy=10; - if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[2+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[2+l]==']') + if(t[inp]==']') { - if(t[3+l]==',') + inp++; + if(t[inp]==',') { - if(tolower(t[4+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=11; else er=E_SYNTAX; } else - if(t[3+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } else @@ -1359,19 +1813,29 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } } else { + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; +#ifdef DEBUG_CAST + printf("Found cast to (5): %c\n", cast); +#endif + } sy=4; - if(!(er=a_term(t+1,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[1+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[1+l]==',') + if(t[inp]==',') { - if(tolower(t[2+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=6; else - if(tolower(t[2+l])=='s') + if(tolower(t[inp])=='s') sy=12; else sy=5; @@ -1382,7 +1846,7 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } /* set bl to maximum overall length +1 as while() below starts with decrementing it */ - if (w65816 || (t[*ll-1]=='@' || t[*ll-1] == '!')) { + if (w65816 || cast=='@' || cast== '!') { /* for 65816 allow addressing modes up to 4 byte overall length */ bl=Maxbyt+1; } else { @@ -1426,7 +1890,7 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); /* only do optimization if we're being called in pass 1 -- never pass 2 */ /* look at cast byte */ - if (t[*ll-1]!='@') + if (cast!='@') { #ifdef DEBUG_AM fprintf(stderr, @@ -1437,9 +1901,12 @@ fprintf(stderr, /* terrible KLUDGE!!!! OH NOES!!!1! due to the way this is constructed, you must absolutely always specify @ to get an absolute long or it will absolutely always be optimized down */ - - if(bl && am>16 && - !er && !(vv[0]&0xff0000) && opt[am]>=0) +/* now also checks for negative overflow, resp. not-overflow */ + if(bl + && am>16 + && !er + && (((vv[0]&0xff8000)==0xff8000) || !(vv[0]&0xff0000)) + && opt[am]>=0) if(ct[n][opt[am]]>=0) am=opt[am]; #ifdef DEBUG_AM @@ -1447,10 +1914,10 @@ fprintf(stderr, "aftaa1: pc= %d, am = %d and vv[0] = %d, optimize = %d, bitmask = %d, bl = %d\n", pc[segment], am, vv[0], fl, (vv[0]&0xffff00), bl); #endif - if(t[*ll-1]!='!') { + if(cast!='!') { if(bl && !er && !(vv[0]&0xffff00) && opt[am]>=0) { if(ct[n][opt[am]]>=0) { - if (!fl || t[*ll-1]=='`') { + if (!fl || cast=='`') { am=opt[am]; } else { errout(W_FORLAB); @@ -1497,8 +1964,10 @@ fprintf(stderr, "byte length is now %d, am=%d, er=%d\n", bl, am, er); er=E_CMOS; } else { n65816++; - if(!w65816) + if(!w65816) { +fprintf(stderr,"n=%d, am=%d\n", n, am); er=E_65816; + } } } if(am!=0) @@ -1590,10 +2059,11 @@ fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]); er=E_SYNTAX; } } - + } else er=E_SYNTAX; } + #ifdef DEBUG_AM fprintf(stderr, "-- endof P2\n"); #endif @@ -1604,6 +2074,11 @@ fprintf(stderr, "-- endof P2\n"); return(er); } +/*********************************************************************************************/ +/* helper function for the preprocessor, to compute an arithmetic value + * (e.g. for #if or #print). + * First tokenizes it, then calculates the value + */ int b_term(char *s, int *v, int *l, int pc) { static signed char t[MAXLINE]; @@ -1617,17 +2092,37 @@ int b_term(char *s, int *v, int *l, int pc) return(er); } -/* translate a string into a first-pass sequence of tokens */ +/*********************************************************************************************/ +/* translate a string into a first-pass sequence of tokens; + * Take the text from *s (stopping at \0 or ';'), tokenize it + * and write the result to *t, returning the length of the + * token sequence in *l + * + * Input params: + * s source input line + * t output token sequence buffer + * l return length of output token sequence here + * pc the current PC to set address labels to that value + * nk return number of comma in the parameters + * na1 asc text count returned + * na2 total byte count in asc texts returned + * af arithmetic flag: 0=do label definitions, parse opcodes and params; + * 1=only tokenize parameters, for b_term() call from the preprocessor + * for arithmetic conditions + * bytep ??? + */ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, - int *na1, int *na2, int af, int *bytep) /* Pass1 von s nach t */ -/* tr. pass1, from s to t */ + int *na1, int *na2, int af, int *bytep) { static int v,f; static int operand,o; int fl,afl; - int p,q,ud,n,ll,mk,er; - int m, uz, byte; - static unsigned char cast; + int p,q,ll,mk,er; + int ud; /* counts undefined labels */ + int n; /* label number to be passed between l_def (definition) and l_set (set the value) */ + int byte; + int uz; /* unused at the moment */ + /*static unsigned char cast;*/ /* ich verstehe deutsch, aber verstehen andere leute nicht; so, werde ich diese bemerkungen uebersetzen ... cameron */ @@ -1647,16 +2142,38 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, fl=0; /* 1 = pass text thru */ afl=0; /* pointer flag for label */ - while(s[p]==' ') p++; + // skip leading whitespace + while(isspace(s[p])) p++; n=T_END; - cast='\0'; + /*cast='\0';*/ if(!af) { while(s[p]!='\0' && s[p]!=';') { + //printf("CONV: %s\n", s); + if (s[p] == ':') { + // this is a ca65 unnamed label + if ((er = l_def((char*)s+p, &ll, &n, &f))) + break; + l_set(n,pc,segment); /* set as address value */ + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; + n=0; + + p+=ll; + + while(isspace(s[p])) p++; + + // end of line + if (s[p] == 0 || s[p] == ';') { + break; + } + } + /* is keyword? */ if(!(er=t_keyword(s+p,&ll,&n))) break; @@ -1665,16 +2182,18 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, if(er && er!=E_NOKEY) break; - /* if so, try to understand as label */ + // if so, try to understand as label + // it returns the label number in n if((er=l_def((char*)s+p,&ll,&n,&f))) break; p+=ll; - while(s[p]==' ') p++; + while(isspace(s[p])) p++; if(s[p]=='=') { + /*printf("Found = @%s\n",s+p);*/ t[q++]=T_OP; t[q++]=n&255; t[q++]=(n>>8)&255; @@ -1683,6 +2202,17 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, ll=n=0; break; } else + if(s[p]==':' && s[p+1]=='=') /* support := label assignments (ca65 compatibility) */ + { + /*printf("Found := @%s\n", s+p);*/ + t[q++]=T_OP; + t[q++]=n&255; + t[q++]=(n>>8)&255; + t[q++]='='; + p+=2; + ll=n=0; + break; + } else if(f && s[p]!='\0' && s[p+1]=='=') { t[q++]=T_OP; @@ -1698,16 +2228,24 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, p++; while(s[p]==' ') p++; l_set(n,pc,segment); /* set as address value */ + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; n=0; + } else { /* label ... syntax */ l_set(n,pc,segment); /* set as address value */ - n=0; + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; + n=0; } } - if(n != Kmvn && n != Kmvp && ((n & 0xff) <=Lastbef)) - mk=1; /* 1= nur 1 Komma erlaubt *//* = only 1 comma ok */ + if(n != Kmvn && n != Kmvp && ((n & 0xff) <=Lastbef)) { + mk=1; /* = only 1 comma ok for normal opcodes */ + } } if(s[p]=='\0' || s[p]==';') @@ -1730,13 +2268,20 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, operand=1; - while(s[p]==' ') p++; + // skip whitespace + while(isspace(s[p])) { + p++; + } if(s[p]=='#') { mk=0; t[q++]=s[p++]; - while(s[p]==' ') p++; + + // skip following whitespace + while(isspace(s[p])) { + p++; + } } /* @@ -1757,16 +2302,24 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, { if(fl) { + // pass through text (e.g. for ",y") t[q++]=s[p++]; + } else { if(operand) { /* are we forcing the operand into a particular - addressing mode? !, @, ` operators */ - if(s[p]=='!' || s[p]=='@' || s[p]=='`') + addressing mode? !, @, ` operators + Note these are not available in ca65, but we only + switch off "@" which are used for cheap local labels*/ + if(s[p]=='!' || (s[p]=='@' && !ca65) || s[p]=='`') { - cast=s[p]; +#ifdef DEBUG_CAST + printf("Setting cast to: %c\n", s[p]); +#endif + t[q++]=T_CAST; + t[q++]=s[p]; operand= -operand+1; p++; } else @@ -1780,22 +2333,34 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, { t[q++]=s[p++]; } else - /* maybe it's a label */ - if(isalpha(s[p]) || s[p]=='_') + /* maybe it's a label + Note that for ca65 cheap local labels, we check for "@" */ + if(isalpha(s[p]) || s[p]=='_' || ((s[p]==':' || s[p]=='@') && ca65)) { - m=n; + + int p2 = 0; + if (n == (Klistbytes & 0xff)) { + // check for "unlimited" + // Note: this could be done by a more general "constants" handling, + // where in appropriate places (like the one here), constants are + // replaced by a pointer to a predefined constants info, e.g. using + // a T_CONSTANT. Which would also fix the listing of this constant + // (which is currently listed as "0") + static char *unlimited = "unlimited"; + while (s[p+p2] != 0 && unlimited[p2] != 0 && s[p+p2] == unlimited[p2]) p2++; + } + if (p2 == 9) { // length of "unlimited" + er = E_OK; + // found constant + wval(q, 0, 'd'); + p += p2; + } else { + //m=n; er=l_search((char*)s+p,&ll,&n,&v,&afl); -/* - if(m==Kglobl || m==Kextzero) { - if(er==E_NODEF) { - er=E_OK; - } - t[q++]=T_LABEL; - t[q++]=n & 255; - t[q++]=(n>>8) & 255; - } else -*/ + if (er == E_NODEF && undefok) { + lg_toglobal(s+p); + } if(!er) { @@ -1804,8 +2369,13 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, t[q++]=afl & 255; t[q++]=v & 255; t[q++]=(v>>8) & 255; + t[q++]=n & 255; /* cheap fix for listing */ + t[q++]=(n>>8) & 255; /* why is the label already resolved in t_conv? */ } else { - wval(q,v); + t[q++]=T_LABEL; + t[q++]=n & 255; + t[q++]=(n>>8) & 255; + /*wval(q,v, 0);*/ } } else if(er==E_NODEF) @@ -1819,36 +2389,57 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); /* if(afl==SEG_ZEROUNDEF) uz++; */ - ud++; + ud++; // number of undefined labels er=E_OK; } p+=ll; + } } else - if(s[p]<='9' && s[p]>='0') + if(s[p]<='9' && (s[p]>'0' || (s[p] == '0' && !ctypes))) { tg_dez(s+p,&ll,&v); p+=ll; - wval(q,v); + wval(q,v, 'd'); } else - - /* handle encodings: hex, binary, octal, quoted strings */ + /* handle encodings: hex, binary, octal, quoted strings */ switch(s[p]) { + case '0': + // only gets here when "ctypes" is set, and starts with 0 + // we here check for the C stype "0xHEX" and "0OCTAL" encodings + if ('x' == tolower(s[p+1])) { + // c-style hex + tg_hex(s+p+2, &ll, &v); + p+=2+ll; + wval(q, v, '$'); + } else + if (isdigit(s[p+1])) { + // c-style octal if digit follows + tg_oct(s+p+1,&ll,&v); + p+=1+ll; + wval(q,v, '&'); + } else { + // else use decimal (0) + tg_dez(s+p,&ll,&v); + p+=ll; + wval(q,v, 'd'); + } + break; case '$': tg_hex(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '$'); break; case '%': tg_bin(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '%'); break; case '&': tg_oct(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '&'); break; case '\'': case '\"': @@ -1885,8 +2476,10 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); if(s[p]==',') { t[q++]=s[p++]; - if(mk) + if(mk) { + // if only one comma, pass through all following text - esp. ",y" or ",x" etc fl++; + } *nk+=1; } else switch(s[p]) { @@ -1902,6 +2495,9 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); case '/': o=4; break; + case '!': + if (s[p+1] == '=') o=12; + break; case '<': switch (s[p+1]) { case '<': @@ -1942,6 +2538,9 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); case '>': o=11; break; + case '=': + o=9; p++; /* hack */ + break; default: o=9; break; @@ -1970,9 +2569,6 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); { t[q++]=o; p+=lp[o]; -#if(0) - uz++; /* disable 8-bit detection */ -#endif } operand= -operand+1; } @@ -1981,6 +2577,7 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } } } +//printf("er=%d, ud=%d\n", er, ud); if(!er) { /* @@ -1994,33 +2591,62 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } */ byte = 0; - t[q++]=T_END; if(ud > 0) { er=E_NODEF; byte = 1; } } + + if (s[p] == ';') { + /* handle comments */ + /* first find out how long */ + int i; + for (i = p+1; s[i] != '\0'; i++); + i = i - p; /* actual length of the comment, including zero-byte terminator */ + /*if (i >= 1) {*/ + /* there actually is a comment */ + t[q++] = T_COMMENT; + t[q++] = i&255; + t[q++] = (i>>8)&255; + memcpy(t+q, s+p+1, i); /* also copy zero terminator, used in listing */ + q += i; + /*}*/ + } + t[q++]=T_END; /* FIXME: this is an unholy union of two "!" implementations :-( */ - t[q++]='\0'; - t[q++]=cast; + /* FIXME FIXME FIXME ... + if (operand==1) { + t[q++]='\0'; + t[q++]=cast; + } + */ *l=q; if(bytep) *bytep=byte; return(er); } +/********************************************************************************************* + * identifies a keyword in s, if it is found, starting with s[0] + * A keyword is either a mnemonic, or a pseudo-opcode + */ static int t_keyword(signed char *s, int *l, int *n) { - int i = 0, j = 0, hash; + int i = 0; // index into keywords + int j = 0; + int hash; + // keywords either start with a character, a "." or "*" if(!isalpha(s[0]) && s[0]!='.' && s[0]!='*' ) return(E_NOKEY); + // if first char is a character, use it as hash... if(isalpha(s[0])) hash=tolower(s[0])-'a'; else hash=26; + // check for "*=" if(s[0]=='*') { j=1; while(s[j] && isspace(s[j])) j++; @@ -2029,9 +2655,14 @@ static int t_keyword(signed char *s, int *l, int *n) j++; } } + + // no keyword yet found? if(!i) { + // get sub-table from hash code, and compare with table content + // (temporarily) redefine i as start index in opcode table, and hash as end index i=ktp[hash]; hash=ktp[hash+1]; + // check all entries in opcode table from start to end for that hash code while(iud.ulist) { afile->ud.ulist = malloc(200*sizeof(int)); if(afile->ud.ulist) afile->ud.um=200; diff --git a/xa/tests/README b/xa/tests/README index fad09fc..ad2405d 100644 --- a/xa/tests/README +++ b/xa/tests/README @@ -1,13 +1,19 @@ This is a directory of test suites for complex or pathological cases that have been repaired (?) in the current version. It is primarily for internal -testing, but is here for your interest. +testing, but is here for your interest. It requires a reasonably compatible +`make` and Perl. -Starting with 2.3.6, you should not normally need to run these directly -unless 'make test' fails. If you do, use harness: +You can run specific tests from the main source directory with + +make test TESTS=test,test,test,... + +or, if `make test` doesn't work right on your system, you can run the Perl +harness directly: ./harness -cc=... -cflags=... -make=... -tests=testdir,testdir,testdir,... If -tests is omitted, all tests are run. + Don't run the makefiles directly, if they exist; they may not work properly. If a Makefile is not present, then the test harness assembles "test.s" and compares it with "ok". @@ -33,9 +39,12 @@ ppstrings/ Don't substitute inside strings (unless -S) neg_offset/ Test negative offsets/values with/without relocation chppch/ Changing preprocessor characters (-p) charset/ Tests of when charsets should be honoured and when not +ca65/ Compatibility tests for ca65 compatibility +relmode/ tests concerning switches between segments and absolute mode mvnmvp/ Test MVN MVP unusual addressing mode ('816) dos51/ Regression test, label scoping, "real world code" cpktest/ Regression test, label listing, "real world code" +listing/ Test of listing feature op816/ Regression test for '816 opcodes (thanks Alessandro Gatti) branch/ Branch range test masmcom/ Another test for -M that generates totally valid code @@ -46,6 +55,9 @@ math/ Math tests (currently divide by zero, thanks Frederic Cambus) alxl/ Various '816 width tests (includes Samuel Falvo's test) pparity/ Tests of preprocessor macro arity (with Emil Johansson's test) recucom/ Recursive comments test +aserror/ Tests of .assert and #error syntax/function +reset_segment/ Verifies conditions under which a segment is reset +expando/ Test of preprocessor expansion (thanks Tom Hargreaves) Cameron Kaiser, André Fachat diff --git a/xa/tests/aserr/Makefile b/xa/tests/aserr/Makefile new file mode 100644 index 0000000..35f7ec5 --- /dev/null +++ b/xa/tests/aserr/Makefile @@ -0,0 +1,16 @@ + +default: test.s + @echo expected to fail.... + ../../xa -DBAD0 test.s || exit 0 && exit 1 + ../../xa -DBAD1 test.s || exit 0 && exit 1 + ../../xa -DBAD2 test.s || exit 0 && exit 1 + ../../xa -DBAD3 test.s || exit 0 && exit 1 + ../../xa -DBAD4 test.s || exit 0 && exit 1 + ../../xa -DBAD5 test.s || exit 0 && exit 1 + @echo no more failures! + ../../xa test.s + ../hextool -cmp=ok < a.o65 + +clean: + rm -f a.o65 + diff --git a/xa/tests/aserr/ok b/xa/tests/aserr/ok new file mode 100644 index 0000000..7cd3c66 --- /dev/null +++ b/xa/tests/aserr/ok @@ -0,0 +1 @@ +© \ No newline at end of file diff --git a/xa/tests/aserr/test.s b/xa/tests/aserr/test.s new file mode 100644 index 0000000..a3a9178 --- /dev/null +++ b/xa/tests/aserr/test.s @@ -0,0 +1,41 @@ +#if XA_MAJOR != 2 +#error make sure this is up to date for future tests +#endif +#if XA_MINOR != 4 +#error make sure this is up to date for future tests +#endif + + * = $1000 + +#ifdef BAD0 +.assert w=w, "what the" +#endif + +w + +#ifdef BAD1 +#error bad1 +#endif + +#ifdef BAD2 +.assert *<>$1000, "everything is bad" +#endif + + lda #1 + +.assert *-2=w, "everything is really bad" +.assert w==w, "everything sucks" +.assert ((w & $ff00)>>8)=16, "everything is hideous" +#ifdef BAD3 +.assert *==$1003, "everything is terrible" +#endif +#ifdef BAD4 +.assert w!=w, "everything sucks and is terrible and hideous and bad" +#endif + +#ifdef BAD5 +#if XA_MAJOR != 1 +#error I want a really old version +#endif +#endif + diff --git a/xa/tests/ca65/Makefile b/xa/tests/ca65/Makefile new file mode 100644 index 0000000..bbe4fa6 --- /dev/null +++ b/xa/tests/ca65/Makefile @@ -0,0 +1,39 @@ +# +# Makefile for tests +# + +XA=../../xa + +CA65=ca65 +LD65=ld65 +OBJS=unnamed1 unnamed2 escape2 + +# escape1 test only relevant if xa23 mode is on +#tests: unnamed1 unnamed2 escape1 escape2 clean +tests: $(OBJS) + +# BSD make won't populate $< in these and GNU make doesn't like $> + +unnamed1: unnamed1.a65 + #${CA65} unnamed1.a65; ${LD65} -t none -o unnamed1.ca65 unnamed1.o; rm unnamed1.o + ${XA} -XCA65 unnamed1.a65 -o $@ + ../hextool -cmp=unnamed1.ca65 < $@ + +unnamed2: unnamed2.a65 + #${CA65} unnamed2.a65; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o + ${XA} -XCA65 unnamed2.a65 -o $@ 2>a.err || true + ../hextool -cmp=unnamed2.ca65 < $@ + +# add -XXA23 to actually test this +escape1: escape1.a65 + ${XA} escape1.a65 -o $@ + ../hextool -cmp=escape1.out < $@ + +escape2: escape2.a65 + #${CA65} escape2.a65; ${LD65} -t none -o escape2.ca65 escape2.o; rm escape2.o + ${XA} -XCA65 escape2.a65 -o $@ 2>a.err || true + ../hextool -cmp=escape2.ca65 < $@ + +clean: + rm -f *.err a.o65 $(OBJS) + diff --git a/xa/tests/ca65/escape1.a65 b/xa/tests/ca65/escape1.a65 new file mode 100644 index 0000000..74e8c09 --- /dev/null +++ b/xa/tests/ca65/escape1.a65 @@ -0,0 +1,6 @@ + + *=$1000 + + lda #"^^" + + diff --git a/xa/tests/ca65/escape1.out b/xa/tests/ca65/escape1.out new file mode 100644 index 0000000..8943227 --- /dev/null +++ b/xa/tests/ca65/escape1.out @@ -0,0 +1 @@ +©^ \ No newline at end of file diff --git a/xa/tests/ca65/escape2.a65 b/xa/tests/ca65/escape2.a65 new file mode 100644 index 0000000..fce5372 --- /dev/null +++ b/xa/tests/ca65/escape2.a65 @@ -0,0 +1,6 @@ + + .org $1000 + + lda #'^' + + diff --git a/xa/tests/ca65/escape2.ca65 b/xa/tests/ca65/escape2.ca65 new file mode 100644 index 0000000..8943227 --- /dev/null +++ b/xa/tests/ca65/escape2.ca65 @@ -0,0 +1 @@ +©^ \ No newline at end of file diff --git a/xa/tests/ca65/unnamed1.a65 b/xa/tests/ca65/unnamed1.a65 new file mode 100644 index 0000000..37f8379 --- /dev/null +++ b/xa/tests/ca65/unnamed1.a65 @@ -0,0 +1,15 @@ + +; test of unnamed labels + +start: .org $4000 + + lda #$00 +: iny ; first + bne :- ; go to first + beq :++ ; go to third +: ; second + jmp :- ; go to second + jmp :++ +: ldy #1 ; third +: nop + diff --git a/xa/tests/ca65/unnamed1.ca65 b/xa/tests/ca65/unnamed1.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..54ddb553d91e19fa13604066ba2208597a8a581f GIT binary patch literal 16 YcmZ34{Sc{4nF)23m9Jk06_}|?f?J) literal 0 HcmV?d00001 diff --git a/xa/tests/ca65/unnamed2.a65 b/xa/tests/ca65/unnamed2.a65 new file mode 100644 index 0000000..4851f06 --- /dev/null +++ b/xa/tests/ca65/unnamed2.a65 @@ -0,0 +1,17 @@ + +; test of unnamed labels + +start: .org $4000 + + lda #$00 +: iny ; first + bne :- ; go to first + beq :++ ; go to third + .scope +: ; second + jmp :- ; go to second + jmp :++ +: ldy #1 ; third + .endscope +: nop + diff --git a/xa/tests/ca65/unnamed2.ca65 b/xa/tests/ca65/unnamed2.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..54ddb553d91e19fa13604066ba2208597a8a581f GIT binary patch literal 16 YcmZ34{Sc{4nF)23m9Jk06_}|?f?J) literal 0 HcmV?d00001 diff --git a/xa/tests/chardelimiter/ok b/xa/tests/chardelimiter/ok index 2c00b0b..e71fe5f 100644 --- a/xa/tests/chardelimiter/ok +++ b/xa/tests/chardelimiter/ok @@ -1 +1 @@ -©A©A1234512345"''" \ No newline at end of file +©A©A1234512345"''"n \ No newline at end of file diff --git a/xa/tests/chardelimiter/test.s b/xa/tests/chardelimiter/test.s index f219d34..6127ac1 100644 --- a/xa/tests/chardelimiter/test.s +++ b/xa/tests/chardelimiter/test.s @@ -7,10 +7,10 @@ .asc "12345" .asc '12345' - .asc "^"" ; ^ is escape character - .asc '^'' + .asc "\"" ; \ is escape character + .asc '\'' .asc "'" .asc '"' - .asc "^n" + .asc "\n" diff --git a/xa/tests/cpktest/Makefile b/xa/tests/cpktest/Makefile index e442ee9..8e0533c 100644 --- a/xa/tests/cpktest/Makefile +++ b/xa/tests/cpktest/Makefile @@ -1,10 +1,10 @@ default: ../../xa -l test.l -o test.o pack_eng.a65 - cmp test.l english.l || exit 1 + ../hextool -cmp=test.l < english.l || exit 1 ../hextool -cmp=eng.ok < test.o ../../xa -l test.l -o test.o pack_ger.a65 - cmp test.l deutsch.l || exit 1 + ../hextool -cmp=test.l < deutsch.l || exit 1 ../hextool -cmp=de.ok < test.o clean: rm -f *.o test.l diff --git a/xa/tests/csapiec/testseg.ok b/xa/tests/csapiec/testseg.ok index 254ccb13ae20170b77d91c7b474881f83c3a95b9..6a377b340e264f204409f9b260754dd221183f03 100644 GIT binary patch delta 11 Scmcb^c!zO9H6zo+ngjqFHv~2S delta 11 Scmcb^c!zO9HDlAnngjqHHw3l- diff --git a/xa/tests/expando/ok b/xa/tests/expando/ok new file mode 100644 index 0000000..e4eb9c0 --- /dev/null +++ b/xa/tests/expando/ok @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/xa/tests/expando/test.s b/xa/tests/expando/test.s new file mode 100644 index 0000000..2cc1a1a --- /dev/null +++ b/xa/tests/expando/test.s @@ -0,0 +1,23 @@ +PBI=6 + +#define NIB(x) PBI+((x&1)>>0), \ + PBI+((x&2)>>1), \ + PBI+((x&4)>>2), \ + PBI+((x&8)>>3) +tab0 + .byt NIB(10),NIB(12),NIB(0), NIB(0) + .byt NIB(10),NIB(12),NIB(15),NIB(0) + .byt NIB(10),NIB(12),NIB(0), NIB(15) + .byt NIB(10),NIB(12),NIB(15),NIB(15) + +; oh well. +tab1 + .byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1 + .byt PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0 + .byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1 + .byt PBI+1,PBI+1,PBI+1,PBI+1,PBI+0,PBI+0,PBI+0,PBI+0 + .byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1 + .byt PBI+0,PBI+0,PBI+0,PBI+0,PBI+1,PBI+1,PBI+1,PBI+1 + .byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1 + .byt PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1 + diff --git a/xa/tests/harness b/xa/tests/harness index 8662f1b..f770e55 100755 --- a/xa/tests/harness +++ b/xa/tests/harness @@ -1,11 +1,21 @@ #!/usr/bin/perl -s -$make ||= "make"; $cc ||= "cc"; +$make ||= "make"; $cflags ||= ''; -$ENV{'MAKE'} = $make; +$makeflags ||= ''; + +# defeat multiple jobs, this doesn't do parallel right now +#$make =~ s/-j\d*(\s|$)//; +#$make =~ s/--jobserver-[^\s]+//; +#$makeflags =~ s/-j\d*(\s|$)//; +#$makeflags =~ s/--jobserver-[^\s]+//; + $ENV{'CC'} = $cc; +$ENV{'MAKE'} = $make; $ENV{'CFLAGS'} = $cflags; +$ENV{'MFLAGS'} = $makeflags; +$ENV{'MAKEFLAGS'} = $makeflags; $|++; $ntests = 0; @@ -16,8 +26,7 @@ print <<"EOF"; CC = $cc CFLAGS = $cflags MAKE = $make -tests to run: $dtests - +MAKEFLAGS = $makeflags EOF # Get a list of all directories. If there is a Makefile there, do it. @@ -25,9 +34,26 @@ EOF # Otherwise, do nothing (acknowledge and ignore directories we don't grok). opendir(D, ".") || die("test harness failed: $!\n"); -W: while($x = readdir(D)) { - next W if ($x =~ /^\./); - next W if (length($tests) && ($tests !~ /$x/)); +while($x = readdir(D)) { + next if ($x =~ /^\./ || $x =~ /\s/); + next if (length($tests) && ($tests !~ /$x/)); + next if (! -d $x); + if (-r "$x/Makefile") { + push(@mtests, $x); + } else { + push(@stests, $x); + } +} +closedir(D); + +@tests = (); +push(@tests, sort @mtests) if (scalar(@mtests)); +push(@tests, sort @stests) if (scalar(@stests)); +print "matching tests: "; +print join(",", @tests); +print "\n\n"; + +W: foreach $x (@tests) { next W if (!chdir($x)); $x = substr($x . " " . ("." x 79), 0, 50); print STDOUT "$x > "; @@ -58,7 +84,6 @@ W: while($x = readdir(D)) { } chdir(".."); } -closedir(D); print STDOUT "=" x 79, "\n"; if ($ntests) { # ntestacy is a terrible thing print STDOUT "\n## ALL SELECTED TESTS PASS ($dtests, n=$ntests) ##\n"; diff --git a/xa/tests/ldoreloc/10.s b/xa/tests/ldoreloc/10.s new file mode 100644 index 0000000..75b0e4d --- /dev/null +++ b/xa/tests/ldoreloc/10.s @@ -0,0 +1,3 @@ + jsr bla +loop: jmp loop + lda l1 diff --git a/xa/tests/ldoreloc/20.s b/xa/tests/ldoreloc/20.s new file mode 100644 index 0000000..344f516 --- /dev/null +++ b/xa/tests/ldoreloc/20.s @@ -0,0 +1,6 @@ + jsr bla +loop: jmp loop + lda #loop + lda #l1 diff --git a/xa/tests/ldoreloc/30.s b/xa/tests/ldoreloc/30.s new file mode 100644 index 0000000..9f47553 --- /dev/null +++ b/xa/tests/ldoreloc/30.s @@ -0,0 +1,2 @@ + jsr bla +loop: jmp loop diff --git a/xa/tests/ldoreloc/31.s b/xa/tests/ldoreloc/31.s new file mode 100644 index 0000000..5802af3 --- /dev/null +++ b/xa/tests/ldoreloc/31.s @@ -0,0 +1,2 @@ + jsr loop +bla: jmp bla diff --git a/xa/tests/ldoreloc/40.s b/xa/tests/ldoreloc/40.s new file mode 100644 index 0000000..b108d3a --- /dev/null +++ b/xa/tests/ldoreloc/40.s @@ -0,0 +1,4 @@ +foo =$1234 + + jsr bla +loop: jmp loop diff --git a/xa/tests/ldoreloc/41.s b/xa/tests/ldoreloc/41.s new file mode 100644 index 0000000..961a4ea --- /dev/null +++ b/xa/tests/ldoreloc/41.s @@ -0,0 +1,7 @@ + jsr loop +bla: jmp bla + lda foo + lda #foo + + diff --git a/xa/tests/ldoreloc/50.s b/xa/tests/ldoreloc/50.s new file mode 100644 index 0000000..0c7faa6 --- /dev/null +++ b/xa/tests/ldoreloc/50.s @@ -0,0 +1,8 @@ +foo =$1234 + + jsr bla +loop: jmp loop + + .data +bar .word bla + diff --git a/xa/tests/ldoreloc/51.s b/xa/tests/ldoreloc/51.s new file mode 100644 index 0000000..470dddf --- /dev/null +++ b/xa/tests/ldoreloc/51.s @@ -0,0 +1,11 @@ + jsr loop +bla: lda bar + + .data + + .word foo + .word bar + .byte foo + + diff --git a/xa/tests/ldoreloc/60.s b/xa/tests/ldoreloc/60.s new file mode 100644 index 0000000..a4cf5bb --- /dev/null +++ b/xa/tests/ldoreloc/60.s @@ -0,0 +1,13 @@ + + .zero +ptr .word 0 + .text + +foo =$1234 + + lda ptr2 +loop: jmp loop + + .data +bar .word bla + diff --git a/xa/tests/ldoreloc/61.s b/xa/tests/ldoreloc/61.s new file mode 100644 index 0000000..00b716f --- /dev/null +++ b/xa/tests/ldoreloc/61.s @@ -0,0 +1,15 @@ + jsr loop +bla: lda ptr + lda #ptr + + .zero +ptr2 .byt 0 + + .data + + .word foo + .word bar + .byte foo + + diff --git a/xa/tests/ldoreloc/Makefile b/xa/tests/ldoreloc/Makefile index cf70ac2..2189c46 100644 --- a/xa/tests/ldoreloc/Makefile +++ b/xa/tests/ldoreloc/Makefile @@ -1,24 +1,130 @@ default: all -all: t +all: t1 t2 t10 t11 t20 t21 t30 t31 t40 t41 t50 t51 t60 t61 t62 -1.o65: 1.s - ../../xa -R -c -o 1.o65 1.s - ../hextool 1.o65 > 1.o65.hex +# BSD only has suffix rules -2.o65: 2.s - ../../xa -R -c -o 2.o65 2.s - ../hextool 2.o65 > 2.o65.hex +.SUFFIXES: .o65 .hex + +#%.o65: %.s +.s.o65: + ../../xa -R -c -o $@ $< + +#%.hex: %.o65 +.o65.hex: + ../hextool $< > $@ linked.o65: 1.o65 2.o65 - ../../ldo65 -o linked.o65 1.o65 2.o65 - ../hextool linked.o65 > linked.o65.hex + ../../ldo65 -o $@ 1.o65 2.o65 -t: linked.o65 - ../../reloc65 -bt 32768 -xt -o t linked.o65 - ../hextool t > t.hex - ../hextool -cmp=t < t.ok +linked2.o65: 1.o65 2.o65 + ../../ldo65 -o $@ 2.o65 1.o65 + +linked10.o65: 10.o65 2.o65 + ../../ldo65 -U -o $@ 10.o65 2.o65 + +linked11.o65: 10.o65 2.o65 + ../../ldo65 -U -o $@ 2.o65 10.o65 + +linked20.o65: 20.o65 2.o65 + ../../ldo65 -Ll1 -o $@ 2.o65 20.o65 + +linked21.o65: 20.o65 2.o65 + ../../ldo65 -L l1 -o $@ 20.o65 2.o65 + +linked22.o65: 20.o65 2.o65 + ../../ldo65 -o $@ 20.o65 2.o65 && exit 1 || exit 0 + +linked30.o65: 30.o65 31.o65 + ../../ldo65 -o $@ 30.o65 31.o65 + +linked31.o65: 30.o65 31.o65 + ../../ldo65 -o $@ 31.o65 30.o65 + +linked40.o65: 40.o65 41.o65 + ../../ldo65 -o $@ 40.o65 41.o65 + +linked41.o65: 40.o65 41.o65 + ../../ldo65 -o $@ 41.o65 40.o65 + +linked50.o65: 50.o65 51.o65 + ../../ldo65 -o $@ 50.o65 51.o65 + +linked51.o65: 50.o65 51.o65 + ../../ldo65 -o $@ 51.o65 50.o65 + +linked60.o65: 60.o65 61.o65 + ../../ldo65 -o $@ 60.o65 61.o65 + +linked61.o65: 60.o65 61.o65 + ../../ldo65 -o $@ 61.o65 60.o65 + +linked62.o65: 60.o65 61.o65 + ../../ldo65 -bd 65529 -bt 65523 -bz 255 -o $@ 61.o65 60.o65 && exit 1 || exit 0 + +# BSD make doesn't populate $< in these rules and GNU make doesn't like $> + +t1: linked.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked.o65 + ../hextool -cmp=$@ < t1.ok + +t2: linked2.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked2.o65 + ../hextool -cmp=$@ < t2.ok + +t10: linked10.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked10.o65 + ../hextool -cmp=$@ < t10.ok + +t11: linked11.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked11.o65 + ../hextool -cmp=$@ < t11.ok + +t20: linked20.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked20.o65 + ../hextool -cmp=$@ < t20.ok + +t21: linked21.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked21.o65 + ../hextool -cmp=$@ < t21.ok + +t22: linked22.o65 + # should fail, so no action + +t30: linked30.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked30.o65 + ../hextool -cmp=$@ < t30.ok + +t31: linked31.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked31.o65 + ../hextool -cmp=$@ < t31.ok + +t40: linked40.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked40.o65 + ../hextool -cmp=$@ < t40.ok + +t41: linked41.o65 + ../../reloc65 -bt 32768 -xt -o $@ linked41.o65 + ../hextool -cmp=$@ < t41.ok + +t50: linked50.o65 + ../../reloc65 -bt 32768 -bd 40960 -o $@ linked50.o65 + ../hextool -cmp=$@ < t50.ok + +t51: linked51.o65 + ../../reloc65 -bt 32768 -bd 40960 -o $@ linked51.o65 + ../hextool -cmp=$@ < t51.ok + +t60: linked60.o65 + ../../reloc65 -bt 32768 -bd 40960 -o $@ linked60.o65 + ../hextool -cmp=$@ < t60.ok + +t61: linked61.o65 + ../../reloc65 -bt 32768 -bd 40960 -o $@ linked61.o65 + ../hextool -cmp=$@ < t61.ok + +t62: linked62.o65 clean: - rm -f *.o65 *.hex t + rm -f *.o65 *.hex t1 t2 t10 t11 t20 t21 t30 t31 t40 t41 t50 t51 t60 t61 diff --git a/xa/tests/ldoreloc/t1.ok b/xa/tests/ldoreloc/t1.ok new file mode 100644 index 0000000..683812c --- /dev/null +++ b/xa/tests/ldoreloc/t1.ok @@ -0,0 +1 @@ + €L€` \ No newline at end of file diff --git a/xa/tests/ldoreloc/t10.ok b/xa/tests/ldoreloc/t10.ok new file mode 100644 index 0000000000000000000000000000000000000000..7e1420e18ee0226b33b73eee9e57e7df7a0777bb GIT binary patch literal 10 RcmY%3Z17=jSj)hW000eD0)_wp literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t11.ok b/xa/tests/ldoreloc/t11.ok new file mode 100644 index 0000000000000000000000000000000000000000..0ce503be6e7fcfb1b46ced8af8c578b9b1722e75 GIT binary patch literal 10 RcmYdLU}*4RX;{m^000h60)7Ah literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t2.ok b/xa/tests/ldoreloc/t2.ok new file mode 100644 index 0000000000000000000000000000000000000000..ac427af7750e15690f99801358576835256cdbfe GIT binary patch literal 7 OcmYdLU}*4RX#fBQ(*e-{ literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t20.ok b/xa/tests/ldoreloc/t20.ok new file mode 100644 index 0000000000000000000000000000000000000000..5d4e930abd9526ef7c345ce529b8607597798060 GIT binary patch literal 15 WcmYdLU}*4RX;{g!vSB5|N(KNWD+Kuf literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t21.ok b/xa/tests/ldoreloc/t21.ok new file mode 100644 index 0000000000000000000000000000000000000000..814a45e648f44a9540f4df839ea424546750bce8 GIT binary patch literal 15 WcmY%3Yw%%iSjoJyVI{*#h6Dg5GzA3! literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t30.ok b/xa/tests/ldoreloc/t30.ok new file mode 100644 index 0000000..462da61 --- /dev/null +++ b/xa/tests/ldoreloc/t30.ok @@ -0,0 +1 @@ + €L€ €L € \ No newline at end of file diff --git a/xa/tests/ldoreloc/t31.ok b/xa/tests/ldoreloc/t31.ok new file mode 100644 index 0000000..462da61 --- /dev/null +++ b/xa/tests/ldoreloc/t31.ok @@ -0,0 +1 @@ + €L€ €L € \ No newline at end of file diff --git a/xa/tests/ldoreloc/t40.ok b/xa/tests/ldoreloc/t40.ok new file mode 100644 index 0000000..d90649d --- /dev/null +++ b/xa/tests/ldoreloc/t40.ok @@ -0,0 +1 @@ + €L€ €L €­4©4© \ No newline at end of file diff --git a/xa/tests/ldoreloc/t41.ok b/xa/tests/ldoreloc/t41.ok new file mode 100644 index 0000000..740cfe4 --- /dev/null +++ b/xa/tests/ldoreloc/t41.ok @@ -0,0 +1 @@ + €L€­4©4© €L€ \ No newline at end of file diff --git a/xa/tests/ldoreloc/t50.ok b/xa/tests/ldoreloc/t50.ok new file mode 100644 index 0000000000000000000000000000000000000000..9f8c44274f6c27b1dec76f9b2df4f9036ecfb699 GIT binary patch literal 94 zcmWlMu?>JA5C9L}LJ}({U8y- k7R6p#ur$+p_(y&#?infrhbk`3r|N|lEBQuf<;?hCAJ&Bt?EnA( literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t51.ok b/xa/tests/ldoreloc/t51.ok new file mode 100644 index 0000000000000000000000000000000000000000..353d6ff53b4adbb211a57175d26e1d5a03f64bcc GIT binary patch literal 94 zcmWm3u?c`M5J1syPJ#ieOyCgF+5ucb3oGHo365luEZ~mD-#vbZE;B6~p$@Qu`wdgD p*VjpG3znjSz5JTU;`$VKk!2~o}AOh+PkR_l(opz=?=Gew%_FbFt;-$#%kqo{-<5 z)bIpB|K!ZP)LZpa_{!D0h7v&z-NT38NqhcqVcAwH;cZ6hn%QhY)TeQcqcY7Sv5wAz GD)R#+?-e8f literal 0 HcmV?d00001 diff --git a/xa/tests/ldoreloc/t61.ok b/xa/tests/ldoreloc/t61.ok new file mode 100644 index 0000000000000000000000000000000000000000..33d02fca0de21c032e93f7ca9c476e7bd615333a GIT binary patch literal 113 zcmWlOu?@m76a_E;kqF5Wg(sk40c5BdfF+WGDw3m!0lti~hg*v5h`HvZyN-On(eM-0 zBRs&+znp{b;;Y?w22XLQDazX}+H|o^1$_>MfoUEw`SM<`^hPtic;!r&;+*q>1)s(h G4fO{eo)tU* literal 0 HcmV?d00001 diff --git a/xa/tests/line/ok b/xa/tests/line/ok new file mode 100644 index 0000000000000000000000000000000000000000..136a737d31838a3672b8bff6821b10b599f585d9 GIT binary patch literal 74 PcmZQzKmZm5lMEIB0YU%; literal 0 HcmV?d00001 diff --git a/xa/tests/line/test.s b/xa/tests/line/test.s new file mode 100644 index 0000000..4b8b416 --- /dev/null +++ b/xa/tests/line/test.s @@ -0,0 +1,20 @@ + +/* + * tests the internal line presentation getting over 128 + */ + +#define MAX_ENDPOINTS 4 + + *=$c000 + +txmax .dsb MAX_ENDPOINTS, 0 ; max transfer length per endpoint +txpos .dsb MAX_ENDPOINTS, 0 ; endpoint buffer position per endpoint, calculated at usbd_start +txlen .dsb MAX_ENDPOINTS, 0 ; endpoint buffer length, set per transaction + +/* + * tests the internal line presentation getting over 256 + */ + + +txpos2 .byt MAX_ENDPOINTS, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; endpoint buffer position per endpoint, calculated at usbd_start and even more comments, but the many values alone use 5 byte per value internally... + diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile new file mode 100644 index 0000000..5da7f63 --- /dev/null +++ b/xa/tests/listing/Makefile @@ -0,0 +1,51 @@ +# +# Makefile for tests +# + +XA=../../xa + +CA65=ca65 +LD65=ld65 + +tests: operatorsx.out assertx.out assertx.html linebreakx.out include1x.out listblocksx.html listca65x.html listca65_2x.html + +operatorsx.out: operators.a65 + ${XA} -P- -o operatorsx.o65 operators.a65 > $@ + ../hextool -cmp=operators.out < $@ + +assertx.out: assert.a65 + ${XA} -P- -o assertx.o65 assert.a65 > $@ + ../hextool -cmp=assert.out < $@ + ../hextool -cmp=assert.o65 < assertx.o65 + +assertx.html: assert.a65 + ${XA} -P- -Fhtml -o assertx.o65 assert.a65 > $@ + ../hextool -cmp=assert.html < $@ + +include1x.out: include1.a65 + ${XA} -P- include1.a65 > $@ + ../hextool -cmp=include1.out < $@ + +linebreakx.out: linebreak.a65 + ${XA} -P- linebreak.a65 > $@ + ../hextool -cmp=linebreak.out < $@ + +listblocksx.html: listblocks.a65 + ${XA} -P- -Fhtml listblocks.a65 > $@ + ../hextool -cmp=listblocks.html < $@ + +listca65x.html: listca65.a65 + ${XA} -XCA65 -P- -Fhtml -o listca65x.o65 listca65.a65 > $@ + #${CA65} $>; ${LD65} -t none -o listca65.ca65 listca65.o; rm listca65.o + ../hextool -cmp=listca65.html < $@ + ../hextool -cmp=listca65.ca65 < listca65x.o65 + +listca65_2x.html: listca65_2.a65 + ${XA} -XCA65 -P- -Fhtml -o listca65_2x.o65 listca65_2.a65 > $@ + #${CA65} $>; ${LD65} -t none -o listca65_2.ca65 listca65_2.o; rm listca65_2.o + ../hextool -cmp=listca65_2.html < $@ + ../hextool -cmp=listca65_2.ca65 < listca65_2x.o65 + +clean: + rm -f *.err *x.out *x.html *x.o65 + diff --git a/xa/tests/listing/a.o65 b/xa/tests/listing/a.o65 new file mode 100644 index 0000000000000000000000000000000000000000..301d9c06f70cc9e202cc9dc77dc0edd985d8e7a0 GIT binary patch literal 16 WcmZ3<(8_e-&r%>h@!_uzg8%?X#0Y@^ literal 0 HcmV?d00001 diff --git a/xa/tests/listing/assert.a65 b/xa/tests/listing/assert.a65 new file mode 100644 index 0000000..e6eed67 --- /dev/null +++ b/xa/tests/listing/assert.a65 @@ -0,0 +1,8 @@ + *=$0400 + + .assert *<$17e6, "routine too long" + + lda #<$17e6 >> 2 + + lda *-2 + diff --git a/xa/tests/listing/assert.html b/xa/tests/listing/assert.html new file mode 100644 index 0000000..34f635c --- /dev/null +++ b/xa/tests/listing/assert.html @@ -0,0 +1,12 @@ +(null)
+
+assert.a65
+
+    1 A:1000                                     *= $0400
+
+    3 A:0400                                     .assert *<$17e6,"routine too long"
+
+    5 A:0400  a9 f9                              lda #<$17e6>>2
+
+    7 A:0402  ad 00 04                           lda *-2
+
diff --git a/xa/tests/listing/assert.o65 b/xa/tests/listing/assert.o65 new file mode 100644 index 0000000000000000000000000000000000000000..5700a95820f2971367681be7ba78c570a4f614d0 GIT binary patch literal 5 McmZ4ab1ef400}_?Q~&?~ literal 0 HcmV?d00001 diff --git a/xa/tests/listing/assert.out b/xa/tests/listing/assert.out new file mode 100644 index 0000000..7a8da2a --- /dev/null +++ b/xa/tests/listing/assert.out @@ -0,0 +1,10 @@ + +assert.a65 + + 1 A:1000 *= $0400 + + 3 A:0400 .assert *<$17e6,"routine too long" + + 5 A:0400 a9 f9 lda #<$17e6>>2 + + 7 A:0402 ad 00 04 lda *-2 diff --git a/xa/tests/listing/include1.a65 b/xa/tests/listing/include1.a65 new file mode 100644 index 0000000..070429e --- /dev/null +++ b/xa/tests/listing/include1.a65 @@ -0,0 +1,8 @@ + + .org $1000 + +#include "include1a.a65" + +.include "include1a.a65" + + diff --git a/xa/tests/listing/include1.out b/xa/tests/listing/include1.out new file mode 100644 index 0000000..4b6a923 --- /dev/null +++ b/xa/tests/listing/include1.out @@ -0,0 +1,23 @@ + +include1.a65 + + + 2 A:1000 *= $1000 + +include1a.a65 + + + 2 A:1000 a9 00 lda #$00 + +include1.a65 + + + 6 A:1002 .include "include1a.a65" + +include1a.a65 + + + 2 A:1002 a9 00 lda #$00 + +include1.a65 + diff --git a/xa/tests/listing/include1a.a65 b/xa/tests/listing/include1a.a65 new file mode 100644 index 0000000..554af8f --- /dev/null +++ b/xa/tests/listing/include1a.a65 @@ -0,0 +1,3 @@ + + lda #$00 + diff --git a/xa/tests/listing/linebreak.a65 b/xa/tests/listing/linebreak.a65 new file mode 100644 index 0000000..01d620a --- /dev/null +++ b/xa/tests/listing/linebreak.a65 @@ -0,0 +1,160 @@ + + *=$1000 + + // default listbytes is 8 + + lda #$0 + + // first without labels + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes +l9 .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, asc test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + // now set number of bytes per listing line to 10 + + .listbytes 10 + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes +l9 .byt 01,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 01,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 01,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, asc test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + // set number of listing bytes to unlimited + .listbytes unlimited + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine byte +l9 .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + diff --git a/xa/tests/listing/linebreak.out b/xa/tests/listing/linebreak.out new file mode 100644 index 0000000..723f4a4 --- /dev/null +++ b/xa/tests/listing/linebreak.out @@ -0,0 +1,162 @@ + +linebreak.a65 + + + 2 A:1000 *= $1000 + + 6 A:1000 a9 00 lda #$00 + + 10 A:1002 .( + + 12 A:1002 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 14 A:1008 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 16 A:100f 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 18 A:1017 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8; 9 + + 20 A:1020 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 22 A:102a 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 24 A:1035 30 31 32 33 34 35 36 ... .asc "012345678901234" ; 15, asc test as well + + 26 A:1044 30 31 32 33 34 35 36 ... .asc "0123456789012345" ; 16 + + 28 A:1054 30 31 32 33 34 35 36 ... .asc "01234567890123456"; 17 + + 30 A:1065 30 31 32 33 34 35 36 ... .asc "012345678901234567890123456789012"; 32 + + 35 A:1086 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 37 A:108c 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 39 A:1093 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 41 A:109b 00 01 02 03 04 05 06 ... l9 .byt 0,1,2,3,4,5,6,7,8; 9 + + 43 A:10a4 00 01 02 03 04 05 06 ... l10 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 45 A:10ae 00 01 02 03 04 05 06 ... l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 47 A:10b9 30 31 32 33 34 35 36 ... l15 .asc "012345678901234"; 15, asc test as well + + 49 A:10c8 30 31 32 33 34 35 36 ... l16 .asc "0123456789012345"; 16 + + 51 A:10d8 30 31 32 33 34 35 36 ... l17 .asc "01234567890123456"; 17 + + 53 A:10e9 30 31 32 33 34 35 36 ... l32 .asc "012345678901234567890123456789012"; 32 + + 55 A:110a .) + + 59 A:110a .listbytes 10 + + 61 A:110a .( + + 63 A:110a 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 65 A:1110 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 67 A:1117 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 69 A:111f 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9 + + 71 A:1128 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 73 A:1132 00 01 02 03 04 05 06 07 08 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 75 A:113d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234" ; 15, asc test as well + + 77 A:114c 30 31 32 33 34 35 36 37 38 ... .asc "0123456789012345" ; 16 + + 79 A:115c 30 31 32 33 34 35 36 37 38 ... .asc "01234567890123456"; 17 + + 81 A:116d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234567890123456789012"; 32 + + 87 A:118e 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 89 A:1194 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 91 A:119b 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 93 A:11a3 01 02 03 04 05 06 07 08 l9 .byt 1,2,3,4,5,6,7,8; 9 + + 95 A:11ab 01 02 03 04 05 06 07 08 09 + 95 A:11ab l10 .byt 1,2,3,4,5,6,7,8,9; 10 + + 97 A:11b4 01 02 03 04 05 06 07 08 09 0a + 97 A:11b4 l11 .byt 1,2,3,4,5,6,7,8,9,10; 11 + + 99 A:11be 30 31 32 33 34 35 36 37 38 ... + 99 A:11be l15 .asc "012345678901234"; 15, asc test as well + + 101 A:11cd 30 31 32 33 34 35 36 37 38 ... + 101 A:11cd l16 .asc "0123456789012345"; 16 + + 103 A:11dd 30 31 32 33 34 35 36 37 38 ... + 103 A:11dd l17 .asc "01234567890123456"; 17 + + 105 A:11ee 30 31 32 33 34 35 36 37 38 ... + 105 A:11ee l32 .asc "012345678901234567890123456789012"; 32 + + 107 A:120f .) + + 110 A:120f .listbytes 0 + + 112 A:120f .( + + 114 A:120f 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 116 A:1215 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 118 A:121c 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 120 A:1224 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9 + + 122 A:122d 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 124 A:1237 00 01 02 03 04 05 06 07 08 09 0a .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 126 A:1242 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 + 126 A:1242 .asc "012345678901234" ; 15, asc test as well + + 128 A:1251 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 128 A:1261 .asc "0123456789012345" ; 16 + + 130 A:1261 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 130 A:1271 36 .asc "01234567890123456"; 17 + + 132 A:1272 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 132 A:1282 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 + 132 A:1292 32 .asc "012345678901234567890123456789012"; 32 + + 138 A:1293 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 140 A:1299 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 142 A:12a0 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 144 A:12a8 00 01 02 03 04 05 06 07 08 + 144 A:12a8 l9 .byt 0,1,2,3,4,5,6,7,8; 9 + + 146 A:12b1 00 01 02 03 04 05 06 07 08 09 + 146 A:12b1 l10 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 148 A:12bb 00 01 02 03 04 05 06 07 08 09 0a + 148 A:12bb l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 150 A:12c6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 + 150 A:12c6 l15 .asc "012345678901234"; 15, test as well + + 152 A:12d5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 152 A:12e5 l16 .asc "0123456789012345"; 16 + + 154 A:12e5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 154 A:12f5 36 l17 .asc "01234567890123456"; 17 + + 156 A:12f6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 156 A:1306 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 + 156 A:1316 32 l32 .asc "012345678901234567890123456789012"; 32 + + 158 A:1317 .) diff --git a/xa/tests/listing/listblocks.a65 b/xa/tests/listing/listblocks.a65 new file mode 100644 index 0000000..0e615e9 --- /dev/null +++ b/xa/tests/listing/listblocks.a65 @@ -0,0 +1,23 @@ + +// tests the html listing feature with blocks that +// contain the same label names, but in different scopes + + *=$1000 + +label1 lda #$00 + + .( +label2 sta $02 + bne label2 + .) + + .( +label2 lda $02 ; again! + bne label2 + .) + +label2 iny + beq label2 + + jmp label1 + diff --git a/xa/tests/listing/listblocks.html b/xa/tests/listing/listblocks.html new file mode 100644 index 0000000..2feabc0 --- /dev/null +++ b/xa/tests/listing/listblocks.html @@ -0,0 +1,24 @@ +(null)
+
+listblocks.a65
+
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     label1    lda #$00
+
+    9 A:1002                                     .( 
+   10 A:1002  85 02                     label2    sta $02
+   11 A:1004  d0 fc                              bne label2
+   12 A:1006                                     .) 
+
+   14 A:1006                                     .( 
+   15 A:1006  a5 02                     label2    lda $02           ; again!
+   16 A:1008  d0 fc                              bne label2
+   17 A:100a                                     .) 
+
+   19 A:100a  c8                        label2    iny 
+   20 A:100b  f0 fd                              beq label2
+
+   22 A:100d  4c 00 10                           jmp label1
+
diff --git a/xa/tests/listing/listca65.a65 b/xa/tests/listing/listca65.a65 new file mode 100644 index 0000000..98ca0d6 --- /dev/null +++ b/xa/tests/listing/listca65.a65 @@ -0,0 +1,24 @@ + +; tests the html listing feature with blocks that +; contain the same label names, but in different scopes + + .org $1000 + +: lda #$00 + + .scope +: sta $02 +: bne :- + .endscope + + .scope +@label2: lda $02 ; again! + bne @label2 + .endscope + +label2: iny + beq label2 + + beq :--- + jmp :-- + diff --git a/xa/tests/listing/listca65.ca65 b/xa/tests/listing/listca65.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..e0c2101bcf1a03cb281315ebf6385cfd525ba5a8 GIT binary patch literal 18 acmZ3<(8_e--%_Rve@=Y(`{APxlK=o=pbBOH literal 0 HcmV?d00001 diff --git a/xa/tests/listing/listca65.html b/xa/tests/listing/listca65.html new file mode 100644 index 0000000..64bae00 --- /dev/null +++ b/xa/tests/listing/listca65.html @@ -0,0 +1,30 @@ +(null)
+
+listca65.a65
+
+
+    2 A:1000                                    ; tests the html listing feature with blocks that 
+    3 A:1000                                    ; contain the same label names, but in different scopes
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     :           lda #$00
+
+    9 A:1002                                     .( 
+   10 A:1002  85 02                     :           sta $02
+   11 A:1004  d0 fe                     :           bne :-
+   12 A:1006                                     .) 
+
+   14 A:1006                                     .( 
+   15 A:1006                            @label2   
+   15 A:1006  a5 02                              lda $02              ; again!
+   16 A:1008  d0 fc                              bne @label2
+   17 A:100a                                     .) 
+
+   19 A:100a                            label2    
+   19 A:100a  c8                                 iny 
+   20 A:100b  f0 fd                              beq label2
+
+   22 A:100d  f0 f1                              beq :---
+   23 A:100f  4c 02 10                           jmp :--
+
diff --git a/xa/tests/listing/listca65_2.a65 b/xa/tests/listing/listca65_2.a65 new file mode 100644 index 0000000..28fe1a4 --- /dev/null +++ b/xa/tests/listing/listca65_2.a65 @@ -0,0 +1,15 @@ + +; tests the html listing feature with blocks that +; contain the same label names, but in different scopes + + .org $1000 + +: lda #$00 + + .include "listca65_2b.a65" + +label2: iny + beq label2 + + jmp :- + diff --git a/xa/tests/listing/listca65_2.ca65 b/xa/tests/listing/listca65_2.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..be121928bcad5b8f9f089e44c30cfa0fb9748e3a GIT binary patch literal 11 TcmZ36CeKiFbMzvDh&ow literal 0 HcmV?d00001 diff --git a/xa/tests/listing/listca65_2.html b/xa/tests/listing/listca65_2.html new file mode 100644 index 0000000..50ba70d --- /dev/null +++ b/xa/tests/listing/listca65_2.html @@ -0,0 +1,32 @@ +(null)
+
+listca65_2.a65
+
+
+    2 A:1000                                    ; tests the html listing feature with blocks that 
+    3 A:1000                                    ; contain the same label names, but in different scopes
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     :           lda #$00
+
+    9 A:1002                                     .include "listca65_2b.a65"
+
+listca65_2b.a65
+
+
+    2 A:1002                                    ; to be included in listca65_2.a65
+    3 A:1002                                    ; to check HTML linkage of unnamed labels across files
+
+    5 A:1002  c8                        :           iny 
+    6 A:1003  d0 fd                              bne :-
+
+listca65_2.a65
+
+
+   11 A:1005                            label2    
+   11 A:1005  c8                                 iny 
+   12 A:1006  f0 fd                              beq label2
+
+   14 A:1008  4c 02 10                           jmp :-
+
diff --git a/xa/tests/listing/listca65_2b.a65 b/xa/tests/listing/listca65_2b.a65 new file mode 100644 index 0000000..109fcb7 --- /dev/null +++ b/xa/tests/listing/listca65_2b.a65 @@ -0,0 +1,7 @@ + + ; to be included in listca65_2.a65 + ; to check HTML linkage of unnamed labels across files + +: iny + bne :- + diff --git a/xa/tests/listing/operators.a65 b/xa/tests/listing/operators.a65 new file mode 100644 index 0000000..512a1e7 --- /dev/null +++ b/xa/tests/listing/operators.a65 @@ -0,0 +1,16 @@ + + +la9a5 =$a9a5 +lac15 =$ac15 +lad24 =$ad24 +lb3c0 =$b3c0 +laf28 =$af28 + +x1 =(la9a5^laf28)&$00ff +x2 =(lac15^laf28)&$00ff +x3 =(lad24^laf28)&$00ff +x4 =(lb3c0^laf28)&$00ff + +x5 =$ff&(la9a5|laf28) +x6 =$ff&(la9a5|laf28)&$00ff + diff --git a/xa/tests/listing/operators.out b/xa/tests/listing/operators.out new file mode 100644 index 0000000..5b142f5 --- /dev/null +++ b/xa/tests/listing/operators.out @@ -0,0 +1,17 @@ + +operators.a65 + + + 3 A:1000 la9a5=$a9a5 + 4 A:1000 lac15=$ac15 + 5 A:1000 lad24=$ad24 + 6 A:1000 lb3c0=$b3c0 + 7 A:1000 laf28=$af28 + + 9 A:1000 x1=(la9a5^laf28)&$ff + 10 A:1000 x2=(lac15^laf28)&$ff + 11 A:1000 x3=(lad24^laf28)&$ff + 12 A:1000 x4=(lb3c0^laf28)&$ff + + 14 A:1000 x5=$ff&(la9a5|laf28) + 15 A:1000 x6=$ff&(la9a5|laf28)&$ff diff --git a/xa/tests/mvnmvp/Makefile b/xa/tests/mvnmvp/Makefile index b48dbe9..5f5d84e 100644 --- a/xa/tests/mvnmvp/Makefile +++ b/xa/tests/mvnmvp/Makefile @@ -1,6 +1,7 @@ default: # xa should not allow this to happen. if it does, this test is no good. ../../xa test.s || exit 0 && exit 1 + ../../xa -w -DOLD_SYNTAX test.s || exit 0 && exit 1 # expected-to-fail tests did fail. should be no more errors now. ../../xa -w test.s -o test.o ../hextool -cmp=ok < test.o diff --git a/xa/tests/mvnmvp/test.s b/xa/tests/mvnmvp/test.s index c2d30d1..991c740 100644 --- a/xa/tests/mvnmvp/test.s +++ b/xa/tests/mvnmvp/test.s @@ -4,11 +4,27 @@ w = $01 lda $d020 lsr mvn w, $02 +#ifdef OLD_SYNTAX mvn $0201 mvn $0066 +#else +mvn $02,$01 +mvn $00,$66 +#endif mvp $03, w+3 +#ifdef OLD_SYNTAX mvp $0403 mvp $0088 +#else +mvp $04,$03 +mvp $00,$88 +#endif +#ifdef OLD_SYNTAX +mvp $0403,$03 +mvp $03,$0405 +mvn $0403,$03 +mvn $03,$0405 +#endif nop .byt $5a, $b6 .word $b65a diff --git a/xa/tests/pparity/Makefile b/xa/tests/pparity/Makefile new file mode 100644 index 0000000..832ecb7 --- /dev/null +++ b/xa/tests/pparity/Makefile @@ -0,0 +1,12 @@ +default: + # xa should not allow this to happen. if it does, this test is no good. + ../../xa bad.s || exit 0 && exit 1 + ../../xa bad2.s || exit 0 && exit 1 + ../../xa bad3.s || exit 0 && exit 1 + ../../xa bad4.s || exit 0 && exit 1 + # expected-to-fail tests did fail. should be no more errors now. + ../../xa good.s -o good.o + ../hextool -cmp=good.ok < good.o + +clean: + rm -f *.o diff --git a/xa/tests/pparity/bad.s b/xa/tests/pparity/bad.s new file mode 100644 index 0000000..8afee68 --- /dev/null +++ b/xa/tests/pparity/bad.s @@ -0,0 +1,3 @@ +#define FOO(a,b) +#define BAR(c) FOO(c) + diff --git a/xa/tests/pparity/bad2.s b/xa/tests/pparity/bad2.s new file mode 100644 index 0000000..2dbb41a --- /dev/null +++ b/xa/tests/pparity/bad2.s @@ -0,0 +1,3 @@ +#define FOO(a,b,c) +#define BAR(b,c) FOO(b,c) + diff --git a/xa/tests/pparity/bad3.s b/xa/tests/pparity/bad3.s new file mode 100644 index 0000000..7fe6013 --- /dev/null +++ b/xa/tests/pparity/bad3.s @@ -0,0 +1,10 @@ +#define FOO(a,b,c) +#define BAR(a,b,c) FOO(c,b,a) + +#define FOO(a,b,c) +#define BAR(b,c) FOO("x",b,c) + +#define FOO(a,b,c) .byt a,b,c +#define BAR(c) FOO("1", "2", c) + +FOO("3") diff --git a/xa/tests/pparity/bad4.s b/xa/tests/pparity/bad4.s new file mode 100644 index 0000000..7c42fb2 --- /dev/null +++ b/xa/tests/pparity/bad4.s @@ -0,0 +1,4 @@ +#define FOO(a) +#define BAR(c) FOO(c,a) + +BAR(1, 2) diff --git a/xa/tests/pparity/good.ok b/xa/tests/pparity/good.ok new file mode 100644 index 0000000..d800886 --- /dev/null +++ b/xa/tests/pparity/good.ok @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/xa/tests/pparity/good.s b/xa/tests/pparity/good.s new file mode 100644 index 0000000..fd67359 --- /dev/null +++ b/xa/tests/pparity/good.s @@ -0,0 +1,10 @@ +#define FOO(a,b,c) +#define BAR(a,b,c) FOO(c,b,a) + +#define FOO(a,b,c) +#define BAR(b,c) FOO("x",b,c) + +#define FOO(a,b,c) .byt a,b,c +#define BAR(c) FOO("1", "2", c) + +BAR("3") diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile new file mode 100644 index 0000000..701fa33 --- /dev/null +++ b/xa/tests/ppdefines/Makefile @@ -0,0 +1,21 @@ + +XA=../../xa +OBJS=test1.u test2.u test3.u test4.u test5.u test6.u test6a.u test6b.u test7.u + +all: $(OBJS) + +clean: + rm -f a.o65 $(OBJS) + +#%: %.a65 %.o65 +# ${XA} -XC $< -o $@ +# ../hextool -cmp=$@.o65 < $@ + +# BSD make only understands suffix rules + +.SUFFIXES: .u .a65 + +.a65.u: + ${XA} -XC $< -o $@ + ../hextool -cmp=$*.o65 < $@ + diff --git a/xa/tests/ppdefines/test1.a65 b/xa/tests/ppdefines/test1.a65 new file mode 100644 index 0000000..67395d0 --- /dev/null +++ b/xa/tests/ppdefines/test1.a65 @@ -0,0 +1,32 @@ + +#define macro1() \ + lda #0 + +#define macro2(a) \ + lda #(a) + +#define macro3(a,b) \ + lda #(a): \ + ldy #(b) + +#define const1 $40 + +#define func1(a) (a) | $20 + + *=$c000 + + macro1() + + macro2(2) + + macro3(2,3) + + lda #(2) | $20 + lda #func1(2) + + macro2(func1(3)) + + macro3(const1, func1(5)) + + macro3(func1(const1), func1(func1(const1))) + diff --git a/xa/tests/ppdefines/test1.o65 b/xa/tests/ppdefines/test1.o65 new file mode 100644 index 0000000000000000000000000000000000000000..449fc69408845bf78c9f68510040dec4cc3ef40e GIT binary patch literal 22 ccmZ3%7g_80AD)@yZ`_I literal 0 HcmV?d00001 diff --git a/xa/tests/ppdefines/test2.a65 b/xa/tests/ppdefines/test2.a65 new file mode 100644 index 0000000..f2b215c --- /dev/null +++ b/xa/tests/ppdefines/test2.a65 @@ -0,0 +1,33 @@ + + +/* + * tests the definition of macro parameters with spaces + * between the name and the brackers / comma + */ + +#define wreg(reg, val) \ + lda #(reg) | 0x02 :\ + lda #(val) + +#define wreg2( reg , val , val2 ) \ + lda #(reg) | 0x02 :\ + lda #(val) :\ + ldx #(val2) + +#define wreg3(reg, val, val2) \ + .byt reg, val, val2 + +#define P1 1 +#define P2 2 +#define P3 3 + + + *=$c000 + + wreg(P1, P2) + + wreg2(P1, P2, P3) + + wreg3( P1 , P2 , P3 ) + + diff --git a/xa/tests/ppdefines/test2.o65 b/xa/tests/ppdefines/test2.o65 new file mode 100644 index 0000000..202b9d6 --- /dev/null +++ b/xa/tests/ppdefines/test2.o65 @@ -0,0 +1 @@ +©©©©¢ \ No newline at end of file diff --git a/xa/tests/ppdefines/test3.a65 b/xa/tests/ppdefines/test3.a65 new file mode 100644 index 0000000..6046fc5 --- /dev/null +++ b/xa/tests/ppdefines/test3.a65 @@ -0,0 +1,11 @@ + +#define GD_DEVICE 0x01 // Get device descriptor for Device +#define GD_CONFIGURATION 0x02 // Get device descriptor for Configuration +#define GD_STRING 0x03 // Get device descriptor for String + + *=$c000 + + lda #GD_DEVICE ; test + + lda #GD_CONFIGURATION+$10 + diff --git a/xa/tests/ppdefines/test3.o65 b/xa/tests/ppdefines/test3.o65 new file mode 100644 index 0000000..d893461 --- /dev/null +++ b/xa/tests/ppdefines/test3.o65 @@ -0,0 +1 @@ +©© \ No newline at end of file diff --git a/xa/tests/ppdefines/test4.a65 b/xa/tests/ppdefines/test4.a65 new file mode 100644 index 0000000..0d1df86 --- /dev/null +++ b/xa/tests/ppdefines/test4.a65 @@ -0,0 +1,13 @@ + + ; same as test3, only there is a colon in the "//" comment + +#define GD_DEVICE 0x01 // Get device descriptor: Device +#define GD_CONFIGURATION 0x02 // Get device descriptor: Configuration +#define GD_STRING 0x03 // Get device descriptor: String + + *=$c000 + + lda #GD_DEVICE ; test + + lda #GD_CONFIGURATION+$10 + diff --git a/xa/tests/ppdefines/test4.o65 b/xa/tests/ppdefines/test4.o65 new file mode 100644 index 0000000..d893461 --- /dev/null +++ b/xa/tests/ppdefines/test4.o65 @@ -0,0 +1 @@ +©© \ No newline at end of file diff --git a/xa/tests/ppdefines/test5.a65 b/xa/tests/ppdefines/test5.a65 new file mode 100644 index 0000000..87428e1 --- /dev/null +++ b/xa/tests/ppdefines/test5.a65 @@ -0,0 +1,28 @@ + + ; this tests the double-slash quote in lines with various disturbances... + + lda #1 ; test1 + + lda #2/1 ; test2 with a constant division + + lda #3*2 ; test3 with multi + + lda #4<<1 ; test with shift left + lda #4>>1 ; test with shift right + + lda #"/" ; test with quotes + + lda #'/' ; test with single quotes + + .byt "/", "/", '/' ; test with multiple quotes + + ; test with comments in quotes + .byt "//" ; test with comment in quotes + + ; tests with escaped and quoted quotes + .byt '"' ; test xa65 specific escape code + .byt '"' ; test + + .byt "'" ; test xa65 specific escape code + .byt "'" ; test + diff --git a/xa/tests/ppdefines/test5.o65 b/xa/tests/ppdefines/test5.o65 new file mode 100644 index 0000000..883baaa --- /dev/null +++ b/xa/tests/ppdefines/test5.o65 @@ -0,0 +1 @@ +©©©©©©/©//////""'' \ No newline at end of file diff --git a/xa/tests/ppdefines/test6.a65 b/xa/tests/ppdefines/test6.a65 new file mode 100644 index 0000000..fbd3721 --- /dev/null +++ b/xa/tests/ppdefines/test6.a65 @@ -0,0 +1,45 @@ + +// testing some more complicated defines + +#define spi_enable(mask) \ + lda SPISSRB :\ + and #255-(mask) :\ + sta SPISSRB + +#define spi_disable(mask) \ + lda SPISSRB :\ + ora #(mask) :\ + sta SPISSRB + +#define spi_wra() \ + .( :\ + sta SPIDR :\ +l_ bit SPISR :\ + bpl l_ :\ + lda SPIDR :\ + .) + +#define max3420e_enable() \ + spi_enable(MAX3420E_EnMask) + +#define max3420e_disable() \ + spi_disable(MAX3420E_EnMask) + +#define wrac(reg) \ + pha :\ + max3420e_enable() :\ + lda #(reg) | 0x02 :\ + spi_wra() :\ + pla :\ + spi_wra() :\ + max3420e_disable() + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + rreg(reg) :\ + and #255-val :\ + wrac(reg) + + + diff --git a/xa/tests/ppdefines/test6.o65 b/xa/tests/ppdefines/test6.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test6a.a65 b/xa/tests/ppdefines/test6a.a65 new file mode 100644 index 0000000..55c8464 --- /dev/null +++ b/xa/tests/ppdefines/test6a.a65 @@ -0,0 +1,28 @@ + +// testing some more complicated defines + + +#define max3420e_enable() \ + spi_enable(MAX3420E_EnMask) + +#define max3420e_disable() \ + spi_disable(MAX3420E_EnMask) + +#define wrac(reg) \ + pha :\ + max3420e_enable() :\ + lda #(reg) | 0x02 :\ + spi_wra() :\ + pla :\ + spi_wra() :\ + max3420e_disable() + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + rreg(reg) :\ + and #255-val :\ + wrac(reg) + + + diff --git a/xa/tests/ppdefines/test6a.o65 b/xa/tests/ppdefines/test6a.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test6b.a65 b/xa/tests/ppdefines/test6b.a65 new file mode 100644 index 0000000..9d3dea5 --- /dev/null +++ b/xa/tests/ppdefines/test6b.a65 @@ -0,0 +1,20 @@ + +// testing some more complicated defines +// this is the minimum I found to trigger the hang symptom + + +#define max3420e_enable() nop + +#define wrac(reg) \ + max3420e_enable() :\ + lda #(reg) + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + wrac(reg) + + +// *=$c000 +// CLRBIT(1,2) + diff --git a/xa/tests/ppdefines/test6b.o65 b/xa/tests/ppdefines/test6b.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test7.a65 b/xa/tests/ppdefines/test7.a65 new file mode 100644 index 0000000..a9da2ee --- /dev/null +++ b/xa/tests/ppdefines/test7.a65 @@ -0,0 +1,23 @@ + +// due to a bug, the first definition was not behaving correct with the +// parameters during evaluation (which wasn't tested in test6*). +// With max3420e_enable2() first, the code would work, as it +// was not used, with the used max3420e_enable() first it would break. + +#define max3420e_enable() nop + +#define max3420e_enable2() nop + +#define wrac(reg) \ + max3420e_enable() :\ + lda #(reg) + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + wrac(reg) + + + *=$c000 + CLRBIT(1,2) + diff --git a/xa/tests/ppdefines/test7.o65 b/xa/tests/ppdefines/test7.o65 new file mode 100644 index 0000000..043ac56 --- /dev/null +++ b/xa/tests/ppdefines/test7.o65 @@ -0,0 +1 @@ +ê© \ No newline at end of file diff --git a/xa/tests/ppstrings/ok b/xa/tests/ppstrings/ok index 64104b3d39834621a068368b6e23242bdbb341de..0a91703d2907e500a0e847f62cfa4474c16ee1d7 100644 GIT binary patch literal 23 ZcmZ<>4Ty6va0v}?0OB|h;Svhu0sv6K2D1PF literal 21 UcmZ<>4PY>E0TNK`5(?x205@j^Hvj+t diff --git a/xa/tests/ppstrings/test.s b/xa/tests/ppstrings/test.s index ba9f521..2c96cef 100644 --- a/xa/tests/ppstrings/test.s +++ b/xa/tests/ppstrings/test.s @@ -3,7 +3,7 @@ .asc "DUP^@" - .asc '0DUP^@' + .asc '0DUP\@' .asc "D","UP^@" diff --git a/xa/tests/recucom/ok b/xa/tests/recucom/ok new file mode 100644 index 0000000000000000000000000000000000000000..3153e5f79e4ea7ade95c78276dd10c8504bb697d GIT binary patch literal 16 XcmZ3O3gYA2Rs6ri9dMCb;C2-H)3ky2IvLmsN#Guu4URe0vw5-k aq~{(x;bTEJ1k*;KYI~4ux)VuyAjN(=Uk*tC literal 0 HcmV?d00001 diff --git a/xa/tests/relmode/mix1.a65 b/xa/tests/relmode/mix1.a65 new file mode 100644 index 0000000..bd4cb89 --- /dev/null +++ b/xa/tests/relmode/mix1.a65 @@ -0,0 +1,11 @@ + + .text + + .word $0401 + *=$0401 + *= + + .data +NextPacketPtr: .byte 0,0 ; word + + diff --git a/xa/tests/relmode/mix1.ok b/xa/tests/relmode/mix1.ok new file mode 100644 index 0000000000000000000000000000000000000000..f86cb21a77b4b6f8e86cb0dc70493654762369e4 GIT binary patch literal 54 wcmZQ%$Tu@(00IFf1_l-&b^uZ!J_7?IjArmlttbgdOwLX%2`DLIU}j(e0CLj?asU7T literal 0 HcmV?d00001 diff --git a/xa/tests/relmode/mix2.a65 b/xa/tests/relmode/mix2.a65 new file mode 100644 index 0000000..c61e3ab --- /dev/null +++ b/xa/tests/relmode/mix2.a65 @@ -0,0 +1,11 @@ + + .text + + .word $0401 + *=$0401 + + + .data +NextPacketPtr: .byte 0,0 ; word + + diff --git a/xa/tests/relmode/mix2.ok b/xa/tests/relmode/mix2.ok new file mode 100644 index 0000000000000000000000000000000000000000..f86cb21a77b4b6f8e86cb0dc70493654762369e4 GIT binary patch literal 54 wcmZQ%$Tu@(00IFf1_l-&b^uZ!J_7?IjArmlttbgdOwLX%2`DLIU}j(e0CLj?asU7T literal 0 HcmV?d00001 diff --git a/xa/tests/relmode/mixabsolute.a65 b/xa/tests/relmode/mixabsolute.a65 new file mode 100644 index 0000000..d1a9f7a --- /dev/null +++ b/xa/tests/relmode/mixabsolute.a65 @@ -0,0 +1,23 @@ + + .text + +l1 lda l1 + + *=$2000 + +l2 lda l2 + + *= + +l2a lda l2a + + .data + +l3 .word l3 + + .text + +l4 lda l4 + + + diff --git a/xa/tests/relmode/testseg.ok b/xa/tests/relmode/testseg.ok new file mode 100644 index 0000000000000000000000000000000000000000..6a377b340e264f204409f9b260754dd221183f03 GIT binary patch literal 220 zcmXAh(Fy@k6h-$OJW)>ZK=C3x8_bM|M#&%efZMq@ZkZX)OvKM~%6?gU*J=kS;s_eP z08M53hqkHq(&Z*|sH8Nt+#to{joiKPG test2.o65.hex -compare: +compare: a.o65 b.o65 ../hextool -cmp=a.ok < a.o65 ../hextool -cmp=b.ok < b.o65 diff --git a/xa/tests/reset_segment/Makefile b/xa/tests/reset_segment/Makefile index acb6107..b929dcf 100644 --- a/xa/tests/reset_segment/Makefile +++ b/xa/tests/reset_segment/Makefile @@ -7,4 +7,4 @@ test1: ../hextool -cmp=ok2 < test2.o clean: - rm -f *.o + rm -f *.o a.o65 diff --git a/xa/tests/reset_segment/test2a.s b/xa/tests/reset_segment/test2a.s new file mode 100644 index 0000000..ada880e --- /dev/null +++ b/xa/tests/reset_segment/test2a.s @@ -0,0 +1,8 @@ + + *=$1234 + + *= + + + + diff --git a/xa/tests/stringcom/ok b/xa/tests/stringcom/ok index a7a755e3ce51c690931d861a6ac35df3822764fd..346e213695e54eeadfd4a217f2193b0bcae16f49 100644 GIT binary patch delta 52 tcmeazpWvV$;20dN6aymlwLqknzCKt?UmqeG?CGknWn^lmrSAul1^|Hh4e$T} delta 20 bcmd1zpWwhB?CGknWn^lmrSBKu7#s`$I*tWX diff --git a/xa/tests/stringcom/test.s b/xa/tests/stringcom/test.s index c68b354..77c3fb7 100644 --- a/xa/tests/stringcom/test.s +++ b/xa/tests/stringcom/test.s @@ -9,13 +9,10 @@ .asc "SIEy256SN" // baz .asc "PASS/*PASS*///PASS//PASS" -#if(0) -/* enable when backslashed quotes are supported in 2.4 */ .asc "PASS\"\\PASS/*PASS*///PASS//\"\\PASS" -#endif .asc "SIE/*256*/N" - /* .asc "SIE/*256*/N" + /* .asc "SIE/*256 .asc "FAIL" */ .asc "PASS" // .asc "FAIL" /* .asc "FAIL*/" */ diff --git a/xa/tests/undef/Makefile b/xa/tests/undef/Makefile new file mode 100644 index 0000000..c6cc41e --- /dev/null +++ b/xa/tests/undef/Makefile @@ -0,0 +1,65 @@ +# +# Makefile for tests +# + +XA=../../xa +OBJS=undef2 undef3 undef5 undef6 +tests: bannerf undef1 undef4 undef5f undef6f banner $(OBJS) + + +banner: + @echo ======================================= + @echo All tests meant to fail have done so correctly; + @echo The following tests should pass + +bannerf: + @echo ======================================= + @echo The following should fail + +undef1: undef.a65 + @echo These should fail + ${XA} undef.a65 || exit 0 && exit 1 + ${XA} -R undef.a65 || exit 0 && exit 1 + ${XA} -R -U -DFAIL undef.a65 || exit 0 && exit 1 + ${XA} -R -Ll1 -Ll3 -Ll4 -Ll5 undef.a65 || exit 0 && exit 1 + +undef2: undef.a65 + ${XA} -R -Ll1 -Ll3 undef.a65 -o $@.tmp + ../../reloc65 -bt 40960 -o $@ $@.tmp + ../hextool -cmp=undef2.ok < $@ + +undef3: undef.a65 + ${XA} -R -U undef.a65 -o $@.tmp + ../../reloc65 -bt 40960 -o $@ $@.tmp + ../hextool -cmp=undef2.ok < $@ + +undef4: undef4.a65 + @echo These should fail + ${XA} undef4.a65 || exit 0 && exit 1 + ${XA} -R undef4.a65 || exit 0 && exit 1 + ${XA} -R -Ll1 undef4.a65 || exit 0 && exit 1 + ${XA} -R -U undef4.a65 || exit 0 && exit 1 + +undef5f: undef5.a65 + @echo These should fail + ${XA} undef5.a65 || exit 0 && exit 1 + ${XA} -R undef5.a65 || exit 0 && exit 1 + ${XA} -R -Ll1 undef5.a65 || exit 0 && exit 1 + +undef5: undef5.a65 + ${XA} -R -U undef5.a65 -o $@ + ../hextool -cmp=undef5.ok < $@ + +undef6f: undef6.a65 + @echo These should fail + ${XA} undef6.a65 || exit 0 && exit 1 + ${XA} -R undef6.a65 || exit 0 && exit 1 + ${XA} -R -Ll1 undef6.a65 || exit 0 && exit 1 + +undef6: undef6.a65 + ${XA} -R -U undef6.a65 -o $@ + ../hextool -cmp=undef6.ok < $@ + +clean: + rm -f a.err a.o65 b.o65 *.tmp $(OBJS) + diff --git a/xa/tests/undef/undef.a65 b/xa/tests/undef/undef.a65 new file mode 100644 index 0000000..ead64c0 --- /dev/null +++ b/xa/tests/undef/undef.a65 @@ -0,0 +1,23 @@ + + .text + + lda l1 + + *=$2000 + +#ifdef FAIL + lda l2 +#endif + + *= + + lda l3 + + .( + + lda l4 + + .) +l4=1 + lda l5 +l5 diff --git a/xa/tests/undef/undef2.ok b/xa/tests/undef/undef2.ok new file mode 100644 index 0000000000000000000000000000000000000000..d412f4c8f7ed7f354427d5777dec8e34c915734f GIT binary patch literal 73 zcmZQ%$Tu@(0D=WP3=Awl+5tiVS!*GPkzp;*0w#tWLxvn<2BroE2IdAv2DT;!2B4S; O10y3tjwu5Z&jJ8Y_X+R- literal 0 HcmV?d00001 diff --git a/xa/tests/undef/undef4.a65 b/xa/tests/undef/undef4.a65 new file mode 100644 index 0000000..0d66284 --- /dev/null +++ b/xa/tests/undef/undef4.a65 @@ -0,0 +1,14 @@ + + .text + + lda l1 + + .( + + .( + + lda l1 + + .) +l1 + .) diff --git a/xa/tests/undef/undef5.a65 b/xa/tests/undef/undef5.a65 new file mode 100644 index 0000000..1850a35 --- /dev/null +++ b/xa/tests/undef/undef5.a65 @@ -0,0 +1,16 @@ + + .text + + + .( + + .( + + lda l1 + + .) +l1 + .) + + lda l1 + diff --git a/xa/tests/undef/undef5.ok b/xa/tests/undef/undef5.ok new file mode 100644 index 0000000000000000000000000000000000000000..5d42b4d966bf421c4299a5d702bf07c56dde39d9 GIT binary patch literal 48 scmZQ%$Tu@(00IFv1_l-&?Es;GthLMnYZ(|A8FCC6n3|XyfFeKu0AAPxOaK4? literal 0 HcmV?d00001 diff --git a/xa/tests/undef/undef6.a65 b/xa/tests/undef/undef6.a65 new file mode 100644 index 0000000..84a5c64 --- /dev/null +++ b/xa/tests/undef/undef6.a65 @@ -0,0 +1,26 @@ + + .text + + + .( + + .( + + lda l1 + + .) +l1 + .) + + .( + + .( + + lda l1 + + .) +l1 + .) + + lda l1 + diff --git a/xa/tests/undef/undef6.ok b/xa/tests/undef/undef6.ok new file mode 100644 index 0000000000000000000000000000000000000000..4055e33576e92af5b2c7a2df86f46bf1860c7069 GIT binary patch literal 53 xcmZQ%$Tu@(00IF{1_l-&?Es;GthLMnYuN(1zP|B literal 0 HcmV?d00001