diff --git a/.github/checks/Makefile b/.github/checks/Makefile index 93eeddd19..ee373d53d 100644 --- a/.github/checks/Makefile +++ b/.github/checks/Makefile @@ -5,14 +5,18 @@ endif ifdef CMD_EXE -.PHONY: checkstyle +.PHONY: checkstyle sorted checkstyle: $(info INFO: style checks require bash.) +sorted: + $(info INFO: table checks require bash.) else -.PHONY: checkstyle lineendings tabs lastline spaces noexec +.PHONY: checkstyle lineendings tabs lastline spaces noexec sorted + +all: checkstyle sorted checkstyle: lineendings tabs lastline spaces noexec @@ -31,4 +35,9 @@ spaces: spaces.sh noexec: noexec.sh @./noexec.sh +sorted: sorted.sh sorted_codeopt.sh sorted_opcodes.sh + @./sorted.sh + @./sorted_codeopt.sh + @./sorted_opcodes.sh + endif diff --git a/.github/checks/sorted.sh b/.github/checks/sorted.sh new file mode 100755 index 000000000..4f53b0484 --- /dev/null +++ b/.github/checks/sorted.sh @@ -0,0 +1,38 @@ +#! /bin/bash +OLDCWD=`pwd` +SCRIPT_PATH=`dirname $0` + +CHECK_DIR=../../src + +SORT_OPT="-u -c" + +# $1: filename +function checkarray_quoted_name +{ + CHECK_FILE="$1" + START="\\/\\* BEGIN SORTED.SH \\*\\/" + END="\\/\\* END SORTED.SH \\*\\/" + + awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {printf("%04d##%s\n", count, $0)}' "$CHECK_FILE" | \ + sed -e 's:\(.*\)##.*\"\(.*\)\".*:\1##\2:g' > .a.tmp + + if [[ -z $(grep '[^[:space:]]' .a.tmp) ]] ; then + echo "error: "$1" table is empty" + rm -rf .a.tmp + exit -1 + fi + + if `LC_COLLATE=C sort $SORT_OPT .a.tmp`; then + echo ""$1" tables OK" + else + echo "error: "$1" tables are not sorted." + rm -rf .a.tmp + exit -1 + fi + rm -rf .a.tmp +} + + +for N in `grep -rl "BEGIN SORTED.SH" "$CHECK_DIR"`; do + checkarray_quoted_name $N +done diff --git a/.github/checks/sorted_codeopt.sh b/.github/checks/sorted_codeopt.sh new file mode 100755 index 000000000..c78662b9d --- /dev/null +++ b/.github/checks/sorted_codeopt.sh @@ -0,0 +1,68 @@ +#! /bin/bash +OLDCWD=`pwd` +SCRIPT_PATH=`dirname $0` + +CHECK_DIR=../../src + +SORT_OPT="-u -c" + +# $1: filename +function checkarray +{ + CHECK_FILE="$1" + START="\\/\\* BEGIN DECL SORTED_CODEOPT.SH \\*\\/" + END="\\/\\* END DECL SORTED_CODEOPT.SH \\*\\/" + + awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {printf("%04d##%s\n", count, $0)}' "$CHECK_FILE" | \ + sed -e 's:\(.*##\).*"\(.*\)",.*:\1\2:g' > .a.tmp + + if [[ -z $(grep '[^[:space:]]' .a.tmp) ]] ; then + echo "error: "$1" table is empty" + rm -rf .a.tmp + exit -1 + fi + + if `LC_COLLATE=C sort $SORT_OPT .a.tmp`; then + echo ""$1" decls sorted." + else + echo "error: "$1" decls are not sorted." + rm -rf .a.tmp + exit -1 + fi + + START="\\/\\* BEGIN SORTED_CODEOPT.SH \\*\\/" + END="\\/\\* END SORTED_CODEOPT.SH \\*\\/" + + awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {printf("%04d##%s\n", count, $0)}' "$CHECK_FILE" | \ + sed -e 's:\(.*##\).*&D\(.*\),.*:\1\2:g' > .b.tmp + + if [[ -z $(grep '[^[:space:]]' .b.tmp) ]] ; then + echo "error: "$1" table is empty" + rm -rf .a.tmp .b.tmp + exit -1 + fi + + if `LC_COLLATE=C sort $SORT_OPT .b.tmp`; then + echo ""$1" tables sorted." + else + echo "error: "$1" tables are not sorted." + rm -rf .a.tmp .b.tmp + exit -1 + fi + + if cmp --silent -- .a.tmp .b.tmp; then + echo ""$1" tables OK" + else + echo "error: "$1" tables are different." + diff -y .a.tmp .b.tmp + rm -rf .a.tmp .b.tmp + exit -1 + fi + + rm -rf .a.tmp .b.tmp +} + + +for N in `grep -rl "BEGIN DECL SORTED_CODEOPT.SH" "$CHECK_DIR"`; do + checkarray $N +done diff --git a/.github/checks/sorted_opcodes.sh b/.github/checks/sorted_opcodes.sh new file mode 100755 index 000000000..3e45ea752 --- /dev/null +++ b/.github/checks/sorted_opcodes.sh @@ -0,0 +1,40 @@ +#! /bin/bash +OLDCWD=`pwd` +SCRIPT_PATH=`dirname $0` + +CHECK_DIR=../../src + +SORT_OPT="-u -c" + +# $1: filename +function checkarray_quoted_name +{ + CHECK_FILE="$1" + START="\\/\\* BEGIN SORTED_OPCODES.SH \\*\\/" + END="\\/\\* END SORTED_OPCODES.SH \\*\\/" + + awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {printf("%04d##%s\n", count, $0)}' "$CHECK_FILE" | \ + sed 's:/\*.*::g' | \ + grep '".*",' | \ + sed -e 's:\(.*\)##.*\"\(.*\)\".*:\1##\2:g' > .a.tmp + + if [[ -z $(grep '[^[:space:]]' .a.tmp) ]] ; then + echo "error: "$1" table is empty" + rm -rf .a.tmp + exit -1 + fi + + if `LC_COLLATE=C sort $SORT_OPT .a.tmp`; then + echo ""$1" tables OK" + else + echo "error: "$1" tables are not sorted." + rm -rf .a.tmp + exit -1 + fi + rm -rf .a.tmp +} + +for N in `grep -rl "BEGIN SORTED_OPCODES.SH" "$CHECK_DIR"`; do + checkarray_quoted_name $N +done + diff --git a/.github/workflows/build-on-pull-request.yml b/.github/workflows/build-on-pull-request.yml index 7b762844b..af79733cf 100644 --- a/.github/workflows/build-on-pull-request.yml +++ b/.github/workflows/build-on-pull-request.yml @@ -24,9 +24,15 @@ jobs: - name: Do some simple style checks shell: bash run: make -j2 checkstyle + - name: Check bsearch tables + shell: bash + run: make -j2 sorted - name: Build the tools. shell: bash run: make -j2 bin USER_CFLAGS=-Werror + - name: Build the dbginfo example + shell: bash + run: make -j2 -C src test - name: Build the utilities. shell: bash run: make -j2 util diff --git a/.github/workflows/snapshot-on-push-master.yml b/.github/workflows/snapshot-on-push-master.yml index 42794f10b..557ba24af 100644 --- a/.github/workflows/snapshot-on-push-master.yml +++ b/.github/workflows/snapshot-on-push-master.yml @@ -49,6 +49,9 @@ jobs: - name: Do some simple style checks shell: bash run: make -j2 checkstyle + - name: Check bsearch tables + shell: bash + run: make -j2 sorted - name: Build the tools. shell: bash run: | diff --git a/Makefile b/Makefile index 91c1d78df..912dbf7cb 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,11 @@ util: # check the code style checkstyle: - @$(MAKE) -C .github/checks --no-print-directory $@ + @$(MAKE) -C .github/checks --no-print-directory $@ + +# check bsearch tables +sorted: + @$(MAKE) -C .github/checks --no-print-directory $@ # runs regression tests, requires libtest target libraries test: @@ -60,6 +64,8 @@ test: # GNU "check" target, which runs all tests check: @$(MAKE) -C .github/checks checkstyle --no-print-directory + @$(MAKE) -C .github/checks sorted --no-print-directory + @$(MAKE) -C src test --no-print-directory @$(MAKE) test @$(MAKE) -C targettest platforms --no-print-directory @$(MAKE) -C samples platforms --no-print-directory diff --git a/README.md b/README.md index e3f1ab30f..891c31e86 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ the [cc65 web site](https://cc65.github.io): | Dr. Jozo Dujmović | Picocomputer (RP6502) | | Watara | Watura/QuickShot Supervision | | Synertek | SYM-1 | +| USSR | Agat-7/9 | A generic configuration to adapt cc65 to new targets is also around. diff --git a/asminc/agat.inc b/asminc/agat.inc new file mode 100644 index 000000000..b96d31834 --- /dev/null +++ b/asminc/agat.inc @@ -0,0 +1,39 @@ + +;----------------------------------------------------------------------------- +; Zero page stuff + +WNDLFT := $20 ; Text window left +WNDWDTH := $21 ; Text window width +WNDTOP := $22 ; Text window top +WNDBTM := $23 ; Text window bottom+1 +CH := $24 ; Cursor horizontal position +CV := $25 ; Cursor vertical position +BASL := $28 ; Text base address low +BASH := $29 ; Text base address high +CURSOR := $2D ; Cursor character +TATTR := $32 ; Text attributes +PROMPT := $33 ; Used by GETLN +VCOUT := $36 ; COUT Subroutine Vector +VCIN := $38 ; CIN Subroutine Vector +RNDL := $4E ; Random counter low +RNDH := $4F ; Random counter high +HIMEM := $73 ; Highest available memory address+1 + +;----------------------------------------------------------------------------- +; Vectors + +DOSWARM := $03D0 ; DOS warmstart vector +BRKVec := $03F0 ; Break vector +SOFTEV := $03F2 ; Vector for warm start +PWREDUP := $03F4 ; This must be = EOR #$A5 of SOFTEV+1 + +;----------------------------------------------------------------------------- +; Hardware + +; Keyboard input +KBD := $C000 ; Read keyboard +KBDSTRB := $C010 ; Clear keyboard strobe + +; Game controller +BUTN0 := $C061 ; Open-Apple Key +BUTN1 := $C062 ; Closed-Apple Key diff --git a/asminc/apple2.inc b/asminc/apple2.inc index fb4a1b2f0..bde383882 100644 --- a/asminc/apple2.inc +++ b/asminc/apple2.inc @@ -24,6 +24,8 @@ DOSWARM := $03D0 ; DOS warmstart vector BRKVec := $03F0 ; Break vector SOFTEV := $03F2 ; Vector for warm start PWREDUP := $03F4 ; This must be = EOR #$A5 of SOFTEV+1 +ROM_RST := $FFFC ; 6502 reset vector +ROM_IRQ := $FFFE ; 6502 IRQ vector ;----------------------------------------------------------------------------- ; 80 column firmware diff --git a/cfg/agat.cfg b/cfg/agat.cfg new file mode 100644 index 000000000..1a740cfc7 --- /dev/null +++ b/cfg/agat.cfg @@ -0,0 +1,44 @@ +# Default configuration + +FEATURES { + STARTADDRESS: default = $1903; +} +SYMBOLS { + __EXEHDR__: type = import; + __FILETYPE__: type = weak, value = $0006; # file type + __STACKSIZE__: type = weak, value = $0400; # 1k stack + __HIMEM__: type = weak, value = $C000; # Presumed RAM end +} +MEMORY { + ZP: file = "", define = yes, start = $0080, size = $001A; + HEADER: file = %O, start = %S - $003A, size = $003A; + MAIN: file = %O, define = yes, start = %S, size = __HIMEM__ - %S; + BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __STACKSIZE__ - __ONCE_RUN__; +} +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + EXEHDR: load = HEADER, type = ro, optional = yes; + STARTUP: load = MAIN, type = ro, optional = yes; + LOWCODE: load = MAIN, type = ro, optional = yes; + CODE: load = MAIN, type = ro; + RODATA: load = MAIN, type = ro; + DATA: load = MAIN, type = rw; + INIT: load = MAIN, type = rw, optional = yes; + ONCE: load = MAIN, type = ro, define = yes; + BSS: load = BSS, type = bss, define = yes; +} +FEATURES { + CONDES: type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__, + segment = ONCE; + CONDES: type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__, + segment = RODATA; + CONDES: type = interruptor, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__, + segment = RODATA, + import = __CALLIRQ__; +} diff --git a/cfg/plus4-hires.cfg b/cfg/plus4-hires.cfg new file mode 100644 index 000000000..0426c8d8c --- /dev/null +++ b/cfg/plus4-hires.cfg @@ -0,0 +1,56 @@ +# Linker configuration that allows for a hi-res bitmap at $C000-$DF3F, but +# puts the stack (and a "HIBSS" segment) in the remaining RAM at $DF40-$FD00. + +FEATURES { + STARTADDRESS: default = $1001; +} +SYMBOLS { + __LOADADDR__: type = import; + __EXEHDR__: type = import; + __STACKSIZE__: type = weak, value = $0800; # 2k stack + __HIMEM__: type = weak, value = $FD00; +} +MEMORY { + # Reserve 8000 bytes at $C000 for 320x200 bitmap + RESERVED: file = "", define = yes, start = $C000, size = 8000; + + ZP: file = "", define = yes, start = $0002, size = $001A; + LOADADDR: file = %O, start = %S - 2, size = $0002; + HEADER: file = %O, define = yes, start = %S, size = $000D; + MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __RESERVED_START__ - __MAIN_START__; + + # Space between bitmap and top of memory + HIRAM: file = "", define = yes, start = __RESERVED_LAST__, size = __HIMEM__ - __HIRAM_START__ - __STACKSIZE__; +} +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + LOADADDR: load = LOADADDR, type = ro; + EXEHDR: load = HEADER, type = ro; + STARTUP: load = MAIN, type = ro; + LOWCODE: load = MAIN, type = ro, optional = yes; + CODE: load = MAIN, type = ro; + ONCE: load = MAIN, type = ro, optional = yes; + RODATA: load = MAIN, type = ro; + DATA: load = MAIN, type = rw; + INIT: load = MAIN, type = bss; + BSS: load = MAIN, type = bss, define = yes; + + # Allow data between bitmap and top of memory to be used as a second BSS + # space. Define symbols for it so that it can be supplied to _heapadd(). + HIBSS: load = HIRAM, type = bss, optional = yes, define = yes; +} +FEATURES { + CONDES: type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__, + segment = ONCE; + CONDES: type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__, + segment = RODATA; + CONDES: type = interruptor, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__, + segment = RODATA, + import = __CALLIRQ__; +} diff --git a/doc/agat.sgml b/doc/agat.sgml new file mode 100644 index 000000000..ca5338c5f --- /dev/null +++ b/doc/agat.sgml @@ -0,0 +1,79 @@ + + +
+Agat-7/9 - specific information for cc65 + +<author><url url="https://sourceforge.net/u/olegodintsov/profile/" name="Oleg A. Odintsov">,<newline> +<url url="mailto:sintechs@gmail.com" name="Konstantin Fedorov"> + +<abstract> +An overview over the Agat-7 and Agat-9 and theirs interfaces to the cc65 C +compiler. +</abstract> + +<!-- Table of contents --> +<toc> + +<!-- Begin the document --> + +<sect>Overview + +<p>The Agat was a series of 8-bit computers produced in the Soviet Union from 1983 to 1993. +It was based on Apple II architecture with all electronic components made in the Soviet Union except for 6502 microprocessors supplied by UMC (UM6502A). +<p>If compared to Apple II, Agat had many improvements such as color text mode, additional graphic modes and flexible memory controller. +Agat-7 had an Apple II compatibility card called "Module 121", while Agat-9 had a built-in Apple II+ mode activated by soft-switch. +<p>All mass-produced Agat models were disk-based systems, 2K ROM contained only basic machine language monitor and disassembler. +Agat-7 had 140K floppy-drive based on Apple DISK II, while Agat-9 was supplied with 840K drive having its own sector format and controller. + +<sect>Binary format<p> + +The standard binary file format generated by the linker for the Agat target is +an AppleSingle file to be compatible with AppleCommander <url url="https://applecommander.github.io/">. +The default load address is $1903. + + + +<sect>Platform-specific header files<p> + +Programs containing Agat-specific code may use the <tt/agat.h/ or +<tt/agat.inc/ include files. + +<sect>Usefull info<p> + +<sect1>Emulation<p> + +<enum> +<item> Oleg Odintsov's Agat Emulator - <url url="https://agatemulator.sourceforge.net/english.html"> +<item> MAME - <url url="https://www.mamedev.org/"> +</enum> + +<sect1>Links<p> +<enum> +<item> Most informative source on Agat (in russian) - <url url="https://agatcomp.ru"> +<item> Wikipedia - <url url="https://en.wikipedia.org/wiki/Agat_(computer)"> +<item> Controversial article on Agat from <url name="BYTE Magazine November 1984 Vol. 9, No. 12" url="https://archive.org/details/byte-magazine-1984-11/page/n135/mode/2up?view=theater">. +The author reviewed custom-build mockup Agat bearing little relation to even the early Agat systems. +</enum> + + +<sect>License<p> + +This software is provided "as-is", without any expressed or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +<enum> +<item> The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated, but is not required. +<item> Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. +<item> This notice may not be removed or altered from any source + distribution. +</enum> + +</article> diff --git a/doc/apple2.sgml b/doc/apple2.sgml index 719e799f4..ec9598d04 100644 --- a/doc/apple2.sgml +++ b/doc/apple2.sgml @@ -87,7 +87,7 @@ several useful settings: exit then a plain vanilla ProDOS 8 doesn't make use of the Language Card bank 2 at all. - <tag>LC address: $D000, LC size: $3000</tag> + <tag>LC address: $D000, LC size: $2FFC</tag> For plain vanilla DOS 3.3 which doesn't make use of the Language Card at all. </descrip><p> diff --git a/doc/apple2enh.sgml b/doc/apple2enh.sgml index 094ddd93e..1e94d3b60 100644 --- a/doc/apple2enh.sgml +++ b/doc/apple2enh.sgml @@ -88,7 +88,7 @@ several useful settings: exit then a plain vanilla ProDOS 8 doesn't make use of the Language Card bank 2 at all. - <tag>LC address: $D000, LC size: $3000</tag> + <tag>LC address: $D000, LC size: $2FFC</tag> For plain vanilla DOS 3.3 which doesn't make use of the Language Card at all. </descrip><p> diff --git a/doc/ca65.sgml b/doc/ca65.sgml index 80224a84e..a12a4accb 100644 --- a/doc/ca65.sgml +++ b/doc/ca65.sgml @@ -3234,6 +3234,12 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".CHARMAP" name=".CH (see <tt><ref id=".P02" name=".P02"></tt> command). +<sect1><tt>.IFP02X</tt><label id=".IFP02X"><p> + + Conditional assembly: Check if the assembler is currently in 6502X mode + (see <tt><ref id=".P02X" name=".P02X"></tt> command). + + <sect1><tt>.IFP4510</tt><label id=".IFP4510"><p> Conditional assembly: Check if the assembler is currently in 4510 mode @@ -3621,6 +3627,16 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE" <tt><ref id=".P4510" name=".P4510"></tt> +<sect1><tt>.P02X</tt><label id=".P02X"><p> + + Enable the 6502X instruction set, disable 65SC02, 65C02 and 65816 + instructions. + + See: <tt><ref id=".PC02" name=".PC02"></tt>, <tt><ref id=".PSC02" + name=".PSC02"></tt>, <tt><ref id=".P816" name=".P816"></tt> and + <tt><ref id=".P4510" name=".P4510"></tt> + + <sect1><tt>.P4510</tt><label id=".P4510"><p> Enable the 4510 instruction set. This is a superset of the 65C02 and @@ -4016,11 +4032,13 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE" See: <tt><ref id=".CPU" name=".CPU"></tt>, <tt><ref id=".IFP02" name=".IFP02"></tt>, + <tt><ref id=".IFP02X" name=".IFP02X"></tt>, <tt><ref id=".IFPDTV" name=".IFPDTV"></tt>, <tt><ref id=".IFP816" name=".IFP816"></tt>, <tt><ref id=".IFPC02" name=".IFPC02"></tt>, <tt><ref id=".IFPSC02" name=".IFPSC02"></tt>, <tt><ref id=".P02" name=".P02"></tt>, + <tt><ref id=".P02X" name=".P02X"></tt>, <tt><ref id=".P816" name=".P816"></tt>, <tt><ref id=".P4510" name=".P4510"></tt>, <tt><ref id=".PC02" name=".PC02"></tt>, diff --git a/doc/cc65.sgml b/doc/cc65.sgml index 6793603d5..383a6dd6a 100644 --- a/doc/cc65.sgml +++ b/doc/cc65.sgml @@ -63,6 +63,8 @@ Short options: -V Print the compiler version number -W [-+]warning[,...] Control warnings ('-' disables, '+' enables) -d Debug mode + -dM Output all user macros (needs -E) + -dP Output all predefined macros (needs -E) -g Add debug info to object file -h Help (this text) -j Default characters are signed @@ -199,6 +201,28 @@ Here is a description of all the command line options: Enables debug mode, for debugging the behavior of cc65. + + <label id="option-dM"> + <tag><tt>-dM</tt></tag> + + When used with -E, will output <tt>#define</tt> directives for all the user + macros defined during execution of the preprocessor. This does not include + macros defined by the compiler. + + Note: Can be combined with <tt/<ref id="option-dP" name="-dP">/ by using + <tt/-dMP/. + + + <label id="option-dP"> + <tag><tt>-dP</tt></tag> + + When used with -E, will output <tt>#define</tt> directives for all the macros + defined by the compiler itself. This does not include any user defined macros. + + Note: Can be combined with <tt/<ref id="option-dM" name="-dM">/ by using + <tt/-dMP/. + + <tag><tt>--debug-tables name</tt></tag> Writes symbol table information to a file, which includes details on structs, unions @@ -1154,6 +1178,96 @@ The compiler defines several macros at startup: <item><tt/__CC65_STD_CC65__/ </itemize> + <label id="macro-CPU"> + <tag><tt>__CPU__</tt></tag> + + This macro contains a bitset that allows to check if a specific instruction + set is supported. For example, the 65C02 CPU supports all instructions of the + 65SC02. So testing for the instruction set of the 65SC02 using the following + check will succeed for both CPUs (and also for the 65816 and HUC6280). + + <tscreen><verb> + #if (__CPU__ & __CPU_ISET_65SC02__) + </verb></tscreen> + + This is much simpler and more future proof than checking for specific CPUs. + + The compiler defines a set of constants named <tt/__CPU_ISET_xxx/ to do the + checks. The <tt/__CPU__/ variable is usually derived from the target system + given, but can be changed using the <tt/<ref id="option--cpu" name="--cpu">/ + command line option. + + <tag><tt>__CPU_6502__</tt></tag> + + This macro is defined if the code is compiled for a 6502 CPU. + + <tag><tt>__CPU_6502X__</tt></tag> + + This macro is defined if the code is compiled for a 6502 CPU with invalid + opcodes. + + <tag><tt>__CPU_6502DTV__</tt></tag> + + This macro is defined if the code is compiled for a DTV CPU. + + <tag><tt>__CPU_65SC02__</tt></tag> + + This macro is defined if the code is compiled for a 65SC02 CPU. + + <tag><tt>__CPU_65C02__</tt></tag> + + This macro is defined if the code is compiled for a 65C02 CPU. + + <tag><tt>__CPU_65816__</tt></tag> + + This macro is defined if the code is compiled for a 65816 CPU. + + <tag><tt>__CPU_HUC6280__</tt></tag> + + This macro is defined if the code is compiled for a HUC6280 CPU. + + <tag><tt>__CPU_ISET_6502__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 6502 CPU. + + <tag><tt>__CPU_ISET_6502X__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 6502X CPU. + + <tag><tt>__CPU_ISET_6502DTV__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 6502DTV CPU. + + <tag><tt>__CPU_ISET_65SC02__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 65SC02 CPU. + + <tag><tt>__CPU_ISET_65C02__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 65C02 CPU. + + <tag><tt>__CPU_ISET_65816__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the 65816 CPU. + + <tag><tt>__CPU_ISET_HUC6280__</tt></tag> + + This macro expands to a numeric constant that can be used to check the + <tt/<ref id="macro-CPU" name="__CPU__">/ macro for the instruction set + of the HUC6280 CPU. + <tag><tt>__CX16__</tt></tag> This macro is defined if the target is the Commander X16 (-t cx16). diff --git a/doc/index.sgml b/doc/index.sgml index 92df5e018..e39fd11b4 100644 --- a/doc/index.sgml +++ b/doc/index.sgml @@ -109,6 +109,9 @@ <descrip> + <tag><htmlurl url="agat.html" name="agat.html"></tag> + Topics specific to the Agat machines. + <tag><htmlurl url="apple2.html" name="apple2.html"></tag> Topics specific to the Apple ][. diff --git a/doc/plus4.sgml b/doc/plus4.sgml index 79a2597d0..578f61c33 100644 --- a/doc/plus4.sgml +++ b/doc/plus4.sgml @@ -165,8 +165,26 @@ The names in the parentheses denote the symbols to be used for static linking of <sect1>Graphics drivers<p> -No graphics drivers are currently available for the Plus/4. +<descrip> + <tag><tt/ted-hi.tgi (ted_hi_tgi)/</tag> + This driver features a resolution of 320*200 with two colors and an + adjustable palette (that means that the two colors can be chosen out of a + palette of the 121 TED colors). + Note that the text-mode character matrix and color data are destroyed by this + driver. The driver calls the Kernal <tt/CLRSCR/ routine to return the text + screen to a usable (if empty) state on <tt/tgi_done()/. + + This driver places the bitmap at $C000-$E000. Programs using + this driver must either be linked with the option <tt/-D + __HIMEM__=$C000/, or use the <tt/plus4-hires.cfg/ linker configuration. + + The <tt/plus4-hires.cfg/ is preferable, as it allows the stack to remain at + $FCFF, and exposes the remaining high memory from the end of the bitmap + to the stack top as a <tt/HIBSS/ segment that can be used by the programmer, + or given to <tt/_heapadd()/ (using the symbols <tt/_HIBSS_START__/ and + <tt/_HIBSS_SIZE__/). +</descrip><p> <sect1>Extended memory drivers<p> diff --git a/include/agat.h b/include/agat.h new file mode 100644 index 000000000..04ec16984 --- /dev/null +++ b/include/agat.h @@ -0,0 +1,76 @@ +#ifndef _AGAT_H +#define _AGAT_H + +/* Check for errors */ +#if !defined(__AGAT__) +# error This module may only be used when compiling for the Agat! +#endif + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Color defines */ +#define COLOR_BLACK 0x00 +#define COLOR_RED 0x01 +#define COLOR_GREEN 0x02 +#define COLOR_YELLOW 0x03 +#define COLOR_BLUE 0x04 +#define COLOR_MAGENTA 0x05 +#define COLOR_CYAN 0x06 +#define COLOR_WHITE 0x07 + +/* Characters codes */ +#define CH_CTRL_C 0x03 +#define CH_ENTER 0x0D +#define CH_ESC 0x1B +#define CH_CURS_LEFT 0x08 +#define CH_CURS_RIGHT 0x15 +#define CH_CURS_UP 0x19 +#define CH_CURS_DOWN 0x1A +#define CH_ESC 0x1B +#define CH_HLINE 0x1B +#define CH_VLINE 0x5C +#define CH_ULCORNER 0x10 +#define CH_URCORNER 0x12 +#define CH_LLCORNER 0x1D +#define CH_LRCORNER 0x1F + +/* Masks for joy_read */ +#define JOY_UP_MASK 0x10 +#define JOY_DOWN_MASK 0x20 +#define JOY_LEFT_MASK 0x04 +#define JOY_RIGHT_MASK 0x08 +#define JOY_BTN_1_MASK 0x40 +#define JOY_BTN_2_MASK 0x80 + +/* Return codes for get_ostype */ +#define AGAT_UNKNOWN 0x00 +#define AGAT_7 0x10 /* Agat 7 */ +#define AGAT_9 0x20 /* Agat 9 */ + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + +unsigned char get_ostype (void); +/* Get the machine type. Returns one of the AGAT_xxx codes. */ + +void rebootafterexit (void); +/* Reboot machine after program termination has completed. */ + +/* The following #defines will cause the matching functions calls in conio.h +** to be overlaid by macros with the same names, saving the function call +** overhead. +*/ +#define _bgcolor(color) COLOR_BLACK +#define _bordercolor(color) COLOR_BLACK + +/* End of agat.h */ + + +#endif diff --git a/include/arpa/inet.h b/include/arpa/inet.h index cd353a2bb..3d715766f 100644 --- a/include/arpa/inet.h +++ b/include/arpa/inet.h @@ -40,6 +40,20 @@ /*****************************************************************************/ +#if (__CPU__ & __CPU_ISET_65SC02__) +/* Always inline, three bytes is not more than a jsr */ + +#define ntohs(x) \ + ( \ + __AX__=(x), \ + asm("phx"), \ + asm("tax"), \ + asm("pla"), \ + __AX__ \ + ) +#define htons(x) ntohs(x) + +#else #if (__OPT_i__ < 200) int __fastcall__ ntohs (int val); @@ -56,12 +70,12 @@ int __fastcall__ htons (int val); ) #define htons(x) ntohs(x) -#endif +#endif /* __OPT_i__ < 200 */ + +#endif /* __CPU__ & __CPU_ISET_65SC02__ */ long __fastcall__ ntohl (long val); long __fastcall__ htonl (long val); - - /* End of arpa/inet.h */ #endif diff --git a/include/cbm264.h b/include/cbm264.h index ab634b721..c220bf407 100644 --- a/include/cbm264.h +++ b/include/cbm264.h @@ -110,7 +110,23 @@ #define COLOR_LIGHTBLUE (BCOLOR_LIGHTBLUE | CATTR_LUMA7) #define COLOR_GRAY3 (BCOLOR_WHITE | CATTR_LUMA5) - +/* TGI color defines */ +#define TGI_COLOR_BLACK (BCOLOR_BLACK) +#define TGI_COLOR_WHITE (BCOLOR_WHITE | CATTR_LUMA7) +#define TGI_COLOR_RED (BCOLOR_RED | CATTR_LUMA4) +#define TGI_COLOR_CYAN (BCOLOR_CYAN | CATTR_LUMA7) +#define TGI_COLOR_PURPLE (BCOLOR_LIGHTVIOLET | CATTR_LUMA7) +#define TGI_COLOR_GREEN (BCOLOR_GREEN | CATTR_LUMA7) +#define TGI_COLOR_BLUE (BCOLOR_BLUE | CATTR_LUMA7) +#define TGI_COLOR_YELLOW (BCOLOR_YELLOW | CATTR_LUMA7) +#define TGI_COLOR_ORANGE (BCOLOR_ORANGE | CATTR_LUMA7) +#define TGI_COLOR_BROWN (BCOLOR_BROWN | CATTR_LUMA7) +#define TGI_COLOR_LIGHTRED (BCOLOR_RED | CATTR_LUMA7) +#define TGI_COLOR_GRAY1 (BCOLOR_WHITE | CATTR_LUMA1) +#define TGI_COLOR_GRAY2 (BCOLOR_WHITE | CATTR_LUMA3) +#define TGI_COLOR_LIGHTGREEN (BCOLOR_LIGHTGREEN | CATTR_LUMA7) +#define TGI_COLOR_LIGHTBLUE (BCOLOR_LIGHTBLUE | CATTR_LUMA7) +#define TGI_COLOR_GRAY3 (BCOLOR_WHITE | CATTR_LUMA5) /* Masks for joy_read */ #define JOY_UP_MASK 0x01 diff --git a/include/plus4.h b/include/plus4.h index 7730938e8..5eb14d24d 100644 --- a/include/plus4.h +++ b/include/plus4.h @@ -57,8 +57,7 @@ /* The addresses of the static drivers */ extern void plus4_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */ extern void plus4_stdser_ser[]; /* Referred to by ser_static_stddrv[] */ - - +extern void ted_hi_tgi[]; /* End of plus4.h */ #endif diff --git a/include/target.h b/include/target.h index 7663a39dd..5f9d8859c 100644 --- a/include/target.h +++ b/include/target.h @@ -37,6 +37,8 @@ # include <apple2enh.h> #elif defined(__APPLE2__) # include <apple2.h> +#elif defined(__AGAT__) +# include <agat.h> #elif defined(__ATARI__) # include <atari.h> #elif defined(__ATARI2600__) diff --git a/libsrc/Makefile b/libsrc/Makefile index c3651e069..487c9d8a1 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -25,7 +25,8 @@ CBMS = c128 \ GEOS = geos-apple \ geos-cbm -TARGETS = apple2 \ +TARGETS = agat \ + apple2 \ apple2enh \ atari \ atarixl \ diff --git a/libsrc/agat/_scrsize.s b/libsrc/agat/_scrsize.s new file mode 100644 index 000000000..09d7e879f --- /dev/null +++ b/libsrc/agat/_scrsize.s @@ -0,0 +1,23 @@ +; +; Ullrich von Bassewitz, 26.10.2000 +; Konstantin Fedorov, 12.06.2025 +; +; Screen size variables +; + + .export screensize + + .include "agat.inc" + +screensize: + lda WNDWDTH + bit TATTR + bmi t64 + lsr +t64: + tax + lda WNDBTM + sec + sbc WNDTOP + tay + rts diff --git a/libsrc/agat/break.s b/libsrc/agat/break.s new file mode 100644 index 000000000..d46679ba2 --- /dev/null +++ b/libsrc/agat/break.s @@ -0,0 +1,113 @@ +; +; Ullrich von Bassewitz, 27.09.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ set_brk (unsigned Addr); +; void reset_brk (void); +; + + .export _set_brk, _reset_brk + .destructor _reset_brk + + ; Be sure to export the following variables absolute + .export _brk_a: abs, _brk_x: abs, _brk_y: abs + .export _brk_sr: abs, _brk_pc: abs + + .include "agat.inc" + +_brk_a = $45 +_brk_x = $46 +_brk_y = $47 +_brk_sr = $48 +_brk_sp = $49 +_brk_pc = $3A + +.bss +oldvec: .res 2 ; Old vector + + +.data +uservec: jmp $FFFF ; Patched at runtime + + +.code + +; Set the break vector +.proc _set_brk + + sta uservec+1 + stx uservec+2 ; Set the user vector + + lda oldvec + ora oldvec+1 ; Did we save the vector already? + bne L1 ; Jump if we installed the handler already + + lda BRKVec + sta oldvec + lda BRKVec+1 + sta oldvec+1 ; Save the old vector + +L1: lda #<brk_handler ; Set the break vector to our routine + ldx #>brk_handler + sta BRKVec + stx BRKVec+1 + rts + +.endproc + + +; Reset the break vector +.proc _reset_brk + + lda oldvec + ldx oldvec+1 + beq @L9 ; Jump if vector not installed + sta BRKVec + stx BRKVec+1 + lda #$00 + sta oldvec ; Clear the old vector + stx oldvec+1 +@L9: rts + +.endproc + + + +; Break handler, called if a break occurs + +.proc brk_handler + + sec + lda _brk_pc + sbc #$02 ; Point to start of brk + sta _brk_pc + lda _brk_pc+1 + sbc #$00 + sta _brk_pc+1 + + clc + lda _brk_sp + adc #$04 ; Adjust stack pointer + sta _brk_sp + + lda _brk_sr ; Clear brk + and #$EF + sta _brk_sr + + jsr uservec ; Call the user's routine + + lda _brk_pc+1 + pha + lda _brk_pc + pha + lda _brk_sr + pha + + ldx _brk_x + ldy _brk_y + lda _brk_a + + rti ; Jump back... + +.endproc + diff --git a/libsrc/agat/cclear.s b/libsrc/agat/cclear.s new file mode 100644 index 000000000..93a561ef4 --- /dev/null +++ b/libsrc/agat/cclear.s @@ -0,0 +1,18 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ cclear (unsigned char length); +; + + .export _cclear + .import COUT + .include "zeropage.inc" + +_cclear: + sta ptr1 + lda #$A0 +next: + jsr COUT + dec ptr1 + bne next + rts diff --git a/libsrc/agat/cgetc.s b/libsrc/agat/cgetc.s new file mode 100644 index 000000000..839e4314a --- /dev/null +++ b/libsrc/agat/cgetc.s @@ -0,0 +1,23 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; char cgetc (void); +; + + .export _cgetc + .import cursor + .include "agat.inc" + +_cgetc: + lda #$DF ; _ + bit cursor + bne hascur + lda #$00 +hascur: + sta CURSOR + jsr j1 + cmp #$A0 + bpl :+ + and #$7F +: rts +j1: jmp (VCIN) diff --git a/libsrc/agat/chline.s b/libsrc/agat/chline.s new file mode 100644 index 000000000..bc95b2a16 --- /dev/null +++ b/libsrc/agat/chline.s @@ -0,0 +1,33 @@ +; +; Ullrich von Bassewitz, 08.08.1998 +; Colin Leroy-Mira, 26.05.2025 +; Konstantin Fedorov, 12.06.2025 +; +; void chlinexy (unsigned char x, unsigned char y, unsigned char length); +; void chline (unsigned char length); +; + + .export _chlinexy, _chline, chlinedirect + .import gotoxy, putchar + + .include "zeropage.inc" + +_chlinexy: + pha ; Save the length + jsr gotoxy ; Call this one, will pop params + pla ; Restore the length and run into _chline + +_chline: + ldx #$1B ; horizontal line character + +chlinedirect: + stx tmp1 + cmp #$00 ; Is the length zero? + beq done ; Jump if done + sta tmp2 +: lda tmp1 ; Screen code + jsr putchar ; Direct output + dec tmp2 + bne :- +done: rts + diff --git a/libsrc/agat/clrscr.s b/libsrc/agat/clrscr.s new file mode 100644 index 000000000..8b2d7100b --- /dev/null +++ b/libsrc/agat/clrscr.s @@ -0,0 +1,10 @@ +; +; Kevin Ruland +; +; void clrscr (void); +; + + .export _clrscr + .import HOME + +_clrscr := HOME diff --git a/libsrc/agat/color.s b/libsrc/agat/color.s new file mode 100644 index 000000000..0992bb860 --- /dev/null +++ b/libsrc/agat/color.s @@ -0,0 +1,20 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char __fastcall__ textcolor (unsigned char color); +; + + + .export _textcolor + .include "agat.inc" + + +_textcolor: + ldx TATTR + eor TATTR + and #$07 + eor TATTR + sta TATTR + txa + and #$0F + rts diff --git a/libsrc/agat/cout.s b/libsrc/agat/cout.s new file mode 100644 index 000000000..ae9d8a177 --- /dev/null +++ b/libsrc/agat/cout.s @@ -0,0 +1,14 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; COUT routine +; + + .export COUT + .include "agat.inc" + +COUT: + cmp #$10 + bpl out + ora #$80 +out: jmp (VCOUT) diff --git a/libsrc/agat/cputc.s b/libsrc/agat/cputc.s new file mode 100644 index 000000000..b82ce22e6 --- /dev/null +++ b/libsrc/agat/cputc.s @@ -0,0 +1,60 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; Konstantin Fedorov, 12.06.2025 +; +; void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c); +; void __fastcall__ cputc (char c); +; + + .import COUT + .export _cputcxy, _cputc, newline, putchar,putchardirect + .import gotoxy, VTABZ + .include "agat.inc" + +_cputcxy: + pha + jsr gotoxy + pla +_cputc: + cmp #$0D ; Test for \r = carriage return + bne notleft + ldy #$00 + sty CH + rts +notleft: + cmp #$0A ; Test for \n = line feed + beq newline + +putchar: + ldy CH + sta (BASL),Y + iny + lda TATTR + bmi wch ; Skip if t64 + sta (BASL),Y + iny +wch: + sty CH + cpy WNDWDTH + bcc noend + ldy #$00 + sty CH +newline: + inc CV + lda CV + cmp WNDBTM + bcc :+ + lda WNDTOP + sta CV +: jmp VTABZ +noend: + rts + +putchardirect: + ldy CH + sta (BASL),Y + lda TATTR + bmi :+ + iny + sta (BASL),Y +: rts diff --git a/libsrc/agat/crt0.s b/libsrc/agat/crt0.s new file mode 100644 index 000000000..41f03b24d --- /dev/null +++ b/libsrc/agat/crt0.s @@ -0,0 +1,78 @@ +; +; Startup code for cc65 (Agat version) +; + + .export __STARTUP__ : absolute = 1 ; Mark as startup + .export _exit + + .import initlib, donelib + .import zerobss, callmain + .import __ONCE_LOAD__, __ONCE_SIZE__ ; Linker generated + + .include "zeropage.inc" + .include "agat.inc" + +; ------------------------------------------------------------------------ + + .segment "STARTUP" + jsr init + jsr zerobss + jsr callmain +_exit: + ldx #<exit + lda #>exit + jsr reset + jsr donelib +exit: + ldx #$02 +: lda rvsave,x + sta SOFTEV,x + dex + bpl :- + ldx #zpspace-1 +: lda zpsave,x + sta sp,x + dex + bpl :- + ldx #$FF + txs + jmp DOSWARM + + + + .segment "ONCE" + +init: + ldx #zpspace-1 +: lda sp,x + sta zpsave,x + dex + bpl :- + + ldx #$02 +: lda SOFTEV,x + sta rvsave,x + dex + bpl :- + + lda HIMEM + ldx HIMEM+1 + sta sp + stx sp+1 + ldx #<_exit + lda #>_exit + jsr reset + jmp initlib + + .code + +reset: + stx SOFTEV + sta SOFTEV+1 + eor #$A5 + sta PWREDUP + rts + + .segment "INIT" +zpsave: .res zpspace +rvsave: .res 3 diff --git a/libsrc/agat/cvline.s b/libsrc/agat/cvline.s new file mode 100644 index 000000000..63c0d4daf --- /dev/null +++ b/libsrc/agat/cvline.s @@ -0,0 +1,29 @@ +; +; Ullrich von Bassewitz, 08.08.1998 +; Colin Leroy-Mira, 26.05.2025 +; Konstantin Fedorov, 12.06.2025 +; +; void cvlinexy (unsigned char x, unsigned char y, unsigned char length); +; void cvline (unsigned char length); +; + + .export _cvlinexy, _cvline + .import gotoxy, putchardirect, newline + + .include "zeropage.inc" + +_cvlinexy: + pha ; Save the length + jsr gotoxy ; Call this one, will pop params + pla ; Restore the length and run into _cvline + +_cvline: + cmp #$00 ; Is the length zero? + beq done ; Jump if done + sta tmp2 +: lda #$5C ; vertical line character + jsr putchardirect ; Write, no cursor advance + jsr newline ; Advance cursor to next line + dec tmp2 + bne :- +done: rts diff --git a/libsrc/agat/exehdr.s b/libsrc/agat/exehdr.s new file mode 100644 index 000000000..3f3047bf9 --- /dev/null +++ b/libsrc/agat/exehdr.s @@ -0,0 +1,43 @@ +; +; Oliver Schmidt, 2012-06-10 +; +; This module supplies an AppleSingle version 2 file header + entry with +; ID 11 according to https://tools.ietf.org/rfc/rfc1740.txt Appendix A. +; +; Agat target uses this header only for compatibility with Apple Commander +; because Agat's 140K disk filesystem is identical to Apple II DOS 3.3 and +; "ac.jar -as" option can be used to import binaries into disk images. + + .export __EXEHDR__ : absolute = 1 ; Linker referenced + .import __FILETYPE__ ; Linker generated + .import __MAIN_START__, __MAIN_LAST__ ; Linker generated + +; ------------------------------------------------------------------------ + +; Data Fork +ID01_LENGTH = __MAIN_LAST__ - __MAIN_START__ +ID01_OFFSET = ID01 - START + +; ProDOS File Info +ID11_LENGTH = ID01 - ID11 +ID11_OFFSET = ID11 - START + +; ------------------------------------------------------------------------ + + .segment "EXEHDR" + +START: .byte $00, $05, $16, $00 ; Magic number + .byte $00, $02, $00, $00 ; Version number + .res 16 ; Filler + .byte 0, 2 ; Number of entries + .byte 0, 0, 0, 1 ; Entry ID 1 - Data Fork + .byte 0, 0, >ID01_OFFSET, <ID01_OFFSET ; Offset + .byte 0, 0, >ID01_LENGTH, <ID01_LENGTH ; Length + .byte 0, 0, 0, 11 ; Entry ID 11 - ProDOS File Info + .byte 0, 0, >ID11_OFFSET, <ID11_OFFSET ; Offset + .byte 0, 0, >ID11_LENGTH, <ID11_LENGTH ; Length +ID11: .byte 0, %11000011 ; Access - Destroy, Rename, Write, Read + .byte >__FILETYPE__, <__FILETYPE__ ; File Type + .byte 0, 0 ; Auxiliary Type high + .byte >__MAIN_START__, <__MAIN_START__ ; Auxiliary Type low +ID01: diff --git a/libsrc/agat/gotoxy.s b/libsrc/agat/gotoxy.s new file mode 100644 index 000000000..13e7cb747 --- /dev/null +++ b/libsrc/agat/gotoxy.s @@ -0,0 +1,28 @@ +; +; Ullrich von Bassewitz, 06.08.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ gotoxy (unsigned char x, unsigned char y); +; void __fastcall__ gotox (unsigned char x); +; + + .export gotoxy, _gotoxy, _gotox + .import popa, VTABZ + + .include "agat.inc" + +gotoxy: + jsr popa ; Get Y +_gotoxy: + clc + adc WNDTOP + sta CV ; Store Y + jsr VTABZ + jsr popa ; Get X +_gotox: + bit TATTR + bmi t64 + asl +t64: + sta CH ; Store X + rts diff --git a/libsrc/agat/gotoy.s b/libsrc/agat/gotoy.s new file mode 100644 index 000000000..ea0eadbf2 --- /dev/null +++ b/libsrc/agat/gotoy.s @@ -0,0 +1,16 @@ +; +; Ullrich von Bassewitz, 06.08.1998 +; Oleg A. Odintsov, Moscow, 2024 +; +; void __fastcall__ gotoy (unsigned char y); +; + + .import VTABZ + .export _gotoy + .include "agat.inc" + +_gotoy: + clc + adc WNDTOP + sta CV + jmp VTABZ diff --git a/libsrc/agat/home.s b/libsrc/agat/home.s new file mode 100644 index 000000000..a0434c9bb --- /dev/null +++ b/libsrc/agat/home.s @@ -0,0 +1,15 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; HOME routine +; + + .export HOME + .import COUT + + .include "agat.inc" + +HOME: + lda #$8C + jmp COUT + rts diff --git a/libsrc/agat/kbhit.s b/libsrc/agat/kbhit.s new file mode 100644 index 000000000..f2bc4fc9f --- /dev/null +++ b/libsrc/agat/kbhit.s @@ -0,0 +1,19 @@ +; +; Kevin Ruland +; Ullrich von Bassewitz, 2005-03-25 +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char kbhit (void); +; + + .export _kbhit + + .include "agat.inc" + +_kbhit: + lda KBD ; Reading KBD checks for keypress + rol ; if high bit is set, key was pressed + lda #$00 + tax + rol + rts diff --git a/libsrc/agat/randomize.s b/libsrc/agat/randomize.s new file mode 100644 index 000000000..9eef16f05 --- /dev/null +++ b/libsrc/agat/randomize.s @@ -0,0 +1,18 @@ +; +; Ullrich von Bassewitz, 07.11.2002 +; Oleg A. Odintsov, Moscow, 2024 +; +; void _randomize (void); +; /* Initialize the random number generator */ +; + + .export __randomize + .import _srand + + .include "agat.inc" + +__randomize: + ldx RNDH ; Use random value supplied by ROM + lda RNDL + jmp _srand ; Initialize generator + diff --git a/libsrc/agat/revers.s b/libsrc/agat/revers.s new file mode 100644 index 000000000..20c1b9bdb --- /dev/null +++ b/libsrc/agat/revers.s @@ -0,0 +1,38 @@ +; +; Ullrich von Bassewitz, 2005-03-28 +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char __fastcall__ revers (unsigned char onoff) +; unsigned char __fastcall__ flash (unsigned char onoff) +; + + .export _revers, _flash + + .include "agat.inc" + +_revers: + tax + beq noinv + lda TATTR + and #$D7 + sta TATTR + rts +noinv: + lda TATTR + ora #$20 + sta TATTR + rts + +_flash: + tax + beq noflash + lda TATTR + and #$DF + ora #$08 + sta TATTR + rts +noflash: + lda TATTR + ora #$20 + sta TATTR + rts diff --git a/libsrc/agat/vtabz.s b/libsrc/agat/vtabz.s new file mode 100644 index 000000000..88166eb35 --- /dev/null +++ b/libsrc/agat/vtabz.s @@ -0,0 +1,24 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; VTABZ routine +; + + .export VTABZ + .include "agat.inc" + +VTABZ: + lda CV + ror + ror + ror + and #$C0 + sta BASL + lda CV + lsr + lsr + eor BASH + and #$07 + eor BASH + sta BASH + rts diff --git a/libsrc/agat/wherex.s b/libsrc/agat/wherex.s new file mode 100644 index 000000000..a83f7cd75 --- /dev/null +++ b/libsrc/agat/wherex.s @@ -0,0 +1,19 @@ +; +; Kevin Ruland +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char wherex (void); +; + + .export _wherex + + .include "agat.inc" + +_wherex: + lda CH + bit TATTR + bmi t64 + lsr +t64: + ldx #$00 + rts diff --git a/libsrc/agat/wherey.s b/libsrc/agat/wherey.s new file mode 100644 index 000000000..4660a55f9 --- /dev/null +++ b/libsrc/agat/wherey.s @@ -0,0 +1,17 @@ +; +; Kevin Ruland +; Oleg A. Odintsov, Moscow, 2024 +; +; unsigned char wherey (void); +; + + .export _wherey + + .include "agat.inc" + +_wherey: + lda CV + sec + sbc WNDTOP + ldx #$00 + rts diff --git a/libsrc/agat/write.s b/libsrc/agat/write.s new file mode 100644 index 000000000..6ac28f32c --- /dev/null +++ b/libsrc/agat/write.s @@ -0,0 +1,50 @@ +; +; Oleg A. Odintsov, Moscow, 2024 +; +; int __fastcall__ write (int fd, const void* buf, unsigned count); +; + + .export _write + .import popax, popptr1 + .import COUT + + .include "zeropage.inc" + +_write: + sta ptr2 + stx ptr2+1 + jsr popptr1 + jsr popax + + ; Check for zero count + ora ptr2 + beq done + + ; Get char from buf +next: ldy #$00 + lda (ptr1),y + + ; Replace '\n' with '\r' + cmp #$0A + bne output + lda #$8D + + ; Set hi bit and write to device +output: + jsr COUT ; Preserves X and Y + + ; Increment pointer + inc ptr1 + bne :+ + inc ptr1+1 + + ; Decrement count +: dec ptr2 + bne next + dec ptr2+1 + bpl next + + ; Return success +done: lda #$00 + rts + diff --git a/libsrc/apple2/crt0.s b/libsrc/apple2/crt0.s index 628303687..ce14cc1e3 100644 --- a/libsrc/apple2/crt0.s +++ b/libsrc/apple2/crt0.s @@ -58,6 +58,7 @@ init: ldx #zpspace-1 ; Check for ProDOS. ldy $BF00 ; MLI call entry point cpy #$4C ; Is MLI present? (JMP opcode) + php ; Remember whether we're running ProDOS bne basic ; Check the ProDOS system bit map. @@ -99,7 +100,20 @@ basic: lda HIMEM bit $C081 bit $C081 - ; Set the source start address. + plp ; Are we running ProDOS? + beq :+ ; Yes, no need to patch vectors + + lda #<reset_6502 + ldx #>reset_6502 + sta ROM_RST + stx ROM_RST+1 + + lda #<irq_6502 + ldx #>irq_6502 + sta ROM_IRQ + stx ROM_IRQ+1 + +: ; Set the source start address. ; Aka __LC_LOAD__ iff segment LC exists. lda #<(__ONCE_LOAD__ + __ONCE_SIZE__) ldy #>(__ONCE_LOAD__ + __ONCE_SIZE__) @@ -144,6 +158,14 @@ quit: jsr $BF00 ; MLI call entry point .byte $65 ; Quit .word q_param +reset_6502: ; Used with DOS3.3 programs + bit $C082 ; Switch in ROM + jmp (ROM_RST) ; Jump to ROM's RESET vector + +irq_6502: ; Used with DOS3.3 programs + bit $C082 ; Switch in ROM + jmp (ROM_IRQ) ; Jump to ROM's IRQ/BRK vector + ; ------------------------------------------------------------------------ .rodata diff --git a/libsrc/plus4/cgetc.s b/libsrc/plus4/cgetc.s index 62863c06e..8c8bb0082 100644 --- a/libsrc/plus4/cgetc.s +++ b/libsrc/plus4/cgetc.s @@ -18,11 +18,16 @@ _cgetc: lda KEY_COUNT ; Get number of characters ora FKEY_COUNT ; Or with number of function key chars bne L2 ; Jump if there are already chars waiting + lda #%00100000 + bit $FF06 + bne L2 ; always disable cursor if in bitmap mode + ; Switch on the cursor if needed ldy CURS_X lda (CRAM_PTR),y ; Get current char pha ; And save it + lda CHARCOLOR sta (CRAM_PTR),y diff --git a/libsrc/plus4/crt0.s b/libsrc/plus4/crt0.s index 6b44a2b7e..d1eea9472 100644 --- a/libsrc/plus4/crt0.s +++ b/libsrc/plus4/crt0.s @@ -9,8 +9,7 @@ .import callirq_y, initlib, donelib .import callmain, zerobss .import __INTERRUPTOR_COUNT__ - .import __MAIN_START__, __MAIN_SIZE__ ; Linker generated - .import __STACKSIZE__ ; Linker generated + .import __HIMEM__ ; Linker generated .importzp ST .include "zeropage.inc" @@ -52,19 +51,28 @@ L1: lda sp,x tsx stx spsave ; Save system stk ptr - lda #<(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__) - ldx #>(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__) + lda #<__HIMEM__ + ldx #>__HIMEM__ sta sp stx sp+1 ; Set up the IRQ vector in the banked RAM; and, switch off the ROM. - ldx #<IRQ - ldy #>IRQ + lda #<IRQ + ldx #>IRQ sei ; No ints, handler not yet in place sta ENABLE_RAM - stx $FFFE ; Install interrupt handler - sty $FFFF + sta $FFFE ; Install interrupt handler + stx $FFFF + lda IRQVec + ldx IRQVec+1 + sta IRQInd+1 + stx IRQInd+2 + lda #<IRQStub + ldx #>IRQStub + sta IRQVec + stx IRQVec+1 + cli ; Allow interrupts ; Clear the BSS data. @@ -95,6 +103,13 @@ _exit: pha ; Save the return code lda #0 sta irqcount ; Disable custom IRQ handlers + sei + ldx IRQInd+1 + ldy IRQInd+2 + stx IRQVec + sty IRQVec+1 + cli + ; Copy back the zero-page stuff. ldx #zpspace-1 @@ -122,9 +137,13 @@ L2: lda zpsave,x ; IRQ handler. The handler in the ROM enables the Kernal, and jumps to ; $CE00, where the ROM code checks for a BRK or IRQ, and branches via the ; indirect vectors at $314/$316. -; To make our stub as fast as possible, we skip the whole part of the ROM -; handler, and jump to the indirect vectors directly. We do also call our -; own interrupt handlers if we have any; so, they need not use $314. +; +; When RAM is banked in, we skip the whole part of the ROM handler, and jump to +; the indirect vectors directly, after calling our own interrupt handlers. +; +; When ROM is banked in, a stub installed in the $314 indirect vector ensures +; that our interrupt handlers are still called (otherwise, interrupts that are +; not serviced by the ROM handler may cause a deadlock). .segment "LOWCODE" @@ -139,15 +158,6 @@ IRQ: cld ; Just to be sure and #$10 ; Test for BRK bit bne dobreak -; It's an IRQ; and, RAM is enabled. If we have handlers, call them. We will use -; a flag here instead of loading __INTERRUPTOR_COUNT__ directly, since the -; condes function is not reentrant. The irqcount flag will be set/reset from -; the main code, to avoid races. - - ldy irqcount - beq @L1 - jsr callirq_y ; Call the IRQ functions - ; Since the ROM handler will end with an RTI, we have to fake an IRQ return ; on the stack, so that we get control of the CPU after the ROM handler, ; and can switch back to RAM. @@ -161,7 +171,7 @@ IRQ: cld ; Just to be sure pha ; Push faked X register pha ; Push faked Y register sta ENABLE_ROM ; Switch to ROM - jmp (IRQVec) ; Jump indirect to Kernal IRQ handler + jmp (IRQVec) ; Jump indirect to IRQ stub irq_ret: sta ENABLE_RAM ; Switch back to RAM @@ -183,6 +193,22 @@ nohandler: sta ENABLE_ROM jmp (BRKVec) ; Jump indirect to the break vector + +; IRQ stub installed at $314, called by our handler above if RAM is banked in, +; or the Kernal IRQ handler if ROM is banked in. + +; If we have handlers, call them. We will use a flag here instead of loading +; __INTERRUPTOR_COUNT__ directly, since the condes function is not reentrant. +; The irqcount flag will be set/reset from the main code, to avoid races. +IRQStub: + cld ; Just to be sure + sta ENABLE_RAM + ldy irqcount + beq @L1 + jsr callirq_y ; Call the IRQ functions +@L1: sta ENABLE_ROM + jmp (IRQInd+1) ; Jump to the saved IRQ vector + ; ------------------------------------------------------------------------ ; Data diff --git a/libsrc/plus4/libref.s b/libsrc/plus4/libref.s index 0bda1e7e8..62c78b8c5 100644 --- a/libsrc/plus4/libref.s +++ b/libsrc/plus4/libref.s @@ -2,8 +2,9 @@ ; Oliver Schmidt, 2013-05-31 ; - .export joy_libref, ser_libref + .export joy_libref, ser_libref, tgi_libref .import _exit joy_libref := _exit ser_libref := _exit +tgi_libref := _exit diff --git a/libsrc/plus4/ser/plus4-stdser.s b/libsrc/plus4/ser/plus4-stdser.s index 77445c7a2..38809d6ab 100644 --- a/libsrc/plus4/ser/plus4-stdser.s +++ b/libsrc/plus4/ser/plus4-stdser.s @@ -64,15 +64,15 @@ ACIA_STATUS := ACIA+1 ; Status register ACIA_CMD := ACIA+2 ; Command register ACIA_CTRL := ACIA+3 ; Control register +RecvHead := $07D1 ; Head of receive buffer +RecvTail := $07D2 ; Tail of receive buffer +RecvFreeCnt := $07D3 ; Number of bytes in receive buffer ;---------------------------------------------------------------------------- ; ; Global variables ; .bss -RecvHead: .res 1 ; Head of receive buffer -RecvTail: .res 1 ; Tail of receive buffer -RecvFreeCnt: .res 1 ; Number of bytes in receive buffer SendHead: .res 1 ; Head of send buffer SendTail: .res 1 ; Tail of send buffer SendFreeCnt: .res 1 ; Number of bytes in send buffer @@ -88,7 +88,7 @@ SendBuf: .res 256 ; Tables used to translate RS232 params into register values -BaudTable: ; bit7 = 1 means setting is invalid +BaudTable: ; Bit7 = 1 means setting is invalid .byte $FF ; SER_BAUD_45_5 .byte $01 ; SER_BAUD_50 .byte $02 ; SER_BAUD_75 @@ -354,26 +354,27 @@ SER_IOCTL: ; SER_IRQ: - lda ACIA_STATUS ; Check ACIA status for receive interrupt - and #$08 - beq @L9 ; Jump if no ACIA interrupt (carry still clear) - lda ACIA_DATA ; Get byte from ACIA - ldx RecvFreeCnt ; Check if we have free space left - beq @L1 ; Jump if no space in receive buffer - ldy RecvTail ; Load buffer pointer - sta RecvBuf,y ; Store received byte in buffer - inc RecvTail ; Increment buffer pointer - dec RecvFreeCnt ; Decrement free space counter - cpx #33 ; Check for buffer space low - bcc @L1 ; Assert flow control if buffer space low + lda ACIA_STATUS ; (4) Check for byte received + and #$08 ; (2) + beq @L9 ; (2*) + + lda ACIA_DATA ; (4) Get byte and put into receive buffer + ldy RecvTail ; (4) + ldx RecvFreeCnt ; (4) + beq @L3 ; (2*) Jump if no space in receive buffer + sta RecvBuf,y ; (5) + inc RecvTail ; (6) + dec RecvFreeCnt ; (6) + cpx #33 ; (2) Check for buffer space low + bcc @L2 ; (2*) rts ; Return with carry set (interrupt handled) ; Assert flow control if buffer space too low -@L1: lda RtsOff - sta ACIA_CMD - sta Stopped - sec ; Interrupt handled +@L2: lda RtsOff ; (3) + sta ACIA_CMD ; (4) + sta Stopped ; (3) +@L3: sec ; Interrupt handled @L9: rts ;---------------------------------------------------------------------------- diff --git a/libsrc/plus4/tgi/ted-hi.s b/libsrc/plus4/tgi/ted-hi.s new file mode 100644 index 000000000..61dd9c2c4 --- /dev/null +++ b/libsrc/plus4/tgi/ted-hi.s @@ -0,0 +1,860 @@ +; +; Graphics driver for the 320x200x2 mode on Commodore Plus/4 systems. +; +; Luminance/Chrominance matrices at $800/$C00, overwriting text-mode character +; and color data. Bitmap is at $C000-$DF3F. Programs using this driver should +; either be linked with the option '-D __HIMEM__=0xC000'. +; +; Based on the c64-hi TGI driver, which in turn was based on Stephen L. Judd's +; GRLIB code. +; +; 2017-01-13, Greg King +; 2018-03-13, Sven Klose +; 2019-10-23, Richard Halkyard +; + .include "zeropage.inc" + + .include "tgi-kernel.inc" + .include "tgi-error.inc" + + .include "cbm_kernal.inc" + .include "plus4.inc" + + .macpack generic + .macpack module + +; ------------------------------------------------------------------------ +; Header. Includes jump table and constants. + + module_header _ted_hi_tgi + +; First part of the header is a structure that has a magic and defines the +; capabilities of the driver + + .byte $74, $67, $69 ; "tgi" + .byte TGI_API_VERSION ; TGI API version number + .addr $0000 ; Library reference + .word 320 ; X resolution + .word 200 ; Y resolution + .byte 2 ; Number of drawing colors + .byte 1 ; Number of screens available + .byte 8 ; System font X size + .byte 8 ; System font Y size + .word $00D4 ; Aspect ratio (based on 4/3 display) + .byte 0 ; TGI driver flags + +; Next comes the jump table. With the exception of IRQ, all entries must be +; valid and may point to an RTS for test versions (function not implemented). + + .addr INSTALL + .addr UNINSTALL + .addr INIT + .addr DONE + .addr GETERROR + .addr CONTROL + .addr CLEAR + .addr SETVIEWPAGE + .addr SETDRAWPAGE + .addr SETCOLOR + .addr SETPALETTE + .addr GETPALETTE + .addr GETDEFPALETTE + .addr SETPIXEL + .addr GETPIXEL + .addr LINE + .addr BAR + .addr TEXTSTYLE + .addr OUTTEXT + +; ------------------------------------------------------------------------ +; Data. + +; Variables mapped to the zero page segment variables. Some of these are +; used for passing parameters to the driver. + +X1 := ptr1 +Y1 := ptr2 +X2 := ptr3 +Y2 := ptr4 +TEXT := ptr3 + +TEMP := tmp4 +TEMP2 := sreg +POINT := regsave + +CHUNK := X2 ; Used in the line routine +OLDCHUNK := X2+1 ; Dito + +; Absolute variables used in the code + +.bss + +ERROR: .res 1 ; Error code +PALETTE: .res 2 ; The current palette + +BITMASK: .res 1 ; $00 = clear, $FF = set pixels + +; Line routine stuff +DX: .res 2 +DY: .res 2 + +; BAR variables +X1SAVE: .res 2 +Y1SAVE: .res 2 +X2SAVE: .res 2 +Y2SAVE: .res 2 + +; Text output stuff +TEXTMAGX: .res 1 +TEXTMAGY: .res 1 +TEXTDIR: .res 1 + +; Constants and tables + +.rodata + +DEFPALETTE: .byte $00, $71 ; White on black +PALETTESIZE = * - DEFPALETTE + +BITTAB: .byte $80,$40,$20,$10,$08,$04,$02,$01 +BITCHUNK: .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01 + +CHARROM := $D000 ; Character rom base address + +; The TED uses the CPU's memory configuration to fetch color data! Although +; we run with ROMs banked out, putting color data in banked RAM (above $8000) +; will result in color artifacts appearing when we bank ROM back in for +; interrupts and Kernal calls. Bitmap data is not affected by this limitation, +; but since there is no way to access RAM under IO (FE00-FF40), we can't put the +; bitmap at $E000 like we do on the C64, and have to use the next lowest +; position at $C000. + +LBASE := $0800 ; Luminance memory base address +VBASE := $C000 ; Bitmap base address + +CBASE := LBASE + $400 ; Chrominance memory base address (fixed relative to LBASE) +CHRBASE := $0800 ; Base address of text mode data + +.assert LBASE .mod $0800 = 0, error, "Luma/Chroma memory base address must be a multiple of 2K" +.assert VBASE .mod $2000 = 0, error, "Bitmap base address must be a multiple of 8K" +.assert LBASE + $800 < $8000, warning, "Luma/Chroma memory overlaps ROM. This will produce color artifacts." +.assert VBASE + $2000 < $FE00, error, "Bitmap overlaps IO space" + +.code + +; ------------------------------------------------------------------------ +; INSTALL routine. Is called after the driver is loaded into memory. May +; initialize anything that has to be done just once. Is probably empty +; most of the time. +; +; Must set an error code: NO +; + +INSTALL: +; rts ; Fall through + + +; ------------------------------------------------------------------------ +; UNINSTALL routine. Is called before the driver is removed from memory. May +; clean up anything done by INSTALL but is probably empty most of the time. +; +; Must set an error code: NO +; + +UNINSTALL: + rts + + +; ------------------------------------------------------------------------ +; INIT: Changes an already installed device from text mode to graphics +; mode. +; Note that INIT/DONE may be called multiple times while the driver +; is loaded, while INSTALL is only called once, so any code that is needed +; to initializes variables and so on must go here. Setting palette and +; clearing the screen is not needed because this is called by the graphics +; kernel later. +; The graphics kernel will never call INIT when a graphics mode is already +; active, so there is no need to protect against that. +; +; Must set an error code: YES +; + +INIT: + +; Initialize variables + + ldx #$FF + stx BITMASK + +; Switch into graphics mode + lda $FF12 ; Set bitmap address and enable fetch from RAM + and #%00000011 + ora #(>VBASE >> 2) + sta $FF12 + +.if LBASE <> CHRBASE + lda #>LBASE ; Set color memory address + sta $FF14 +.endif + + lda $FF06 ; Enable bitmap mode + ora #%00100000 + sta $FF06 + +; Done, reset the error code + + lda #TGI_ERR_OK + sta ERROR + rts + +; ------------------------------------------------------------------------ +; DONE: Will be called to switch the graphics device back into text mode. +; The graphics kernel will never call DONE when no graphics mode is active, +; so there is no need to protect against that. +; +; Must set an error code: NO +; + +DONE: lda $FF12 + ora #%00000100 ; Fetch from ROM + sta $FF12 + +.if LBASE <> CHRBASE + lda #>CHRBASE ; Reset character/color matrix address + sta $FF14 +.else + sta ENABLE_ROM ; Clear text display since we clobbered it + jsr CLRSCR + sta ENABLE_RAM +.endif + + lda $FF06 + and #%11011111 ; Exit bitmap mode + sta $FF06 + + rts + +; ------------------------------------------------------------------------ +; GETERROR: Return the error code in A and clear it. + +GETERROR: + ldx #TGI_ERR_OK + lda ERROR + stx ERROR + rts + +; ------------------------------------------------------------------------ +; CONTROL: Platform/driver specific entry point. +; +; Must set an error code: YES +; + +CONTROL: + lda #TGI_ERR_INV_FUNC + sta ERROR + rts + +; ------------------------------------------------------------------------ +; CLEAR: Clears the screen. +; +; Must set an error code: NO +; + +CLEAR: ldy #$00 + tya +@L1: sta VBASE+$0000,y + sta VBASE+$0100,y + sta VBASE+$0200,y + sta VBASE+$0300,y + sta VBASE+$0400,y + sta VBASE+$0500,y + sta VBASE+$0600,y + sta VBASE+$0700,y + sta VBASE+$0800,y + sta VBASE+$0900,y + sta VBASE+$0A00,y + sta VBASE+$0B00,y + sta VBASE+$0C00,y + sta VBASE+$0D00,y + sta VBASE+$0E00,y + sta VBASE+$0F00,y + sta VBASE+$1000,y + sta VBASE+$1100,y + sta VBASE+$1200,y + sta VBASE+$1300,y + sta VBASE+$1400,y + sta VBASE+$1500,y + sta VBASE+$1600,y + sta VBASE+$1700,y + sta VBASE+$1800,y + sta VBASE+$1900,y + sta VBASE+$1A00,y + sta VBASE+$1B00,y + sta VBASE+$1C00,y + sta VBASE+$1D00,y + sta VBASE+$1E00,y + sta VBASE+$1E40,y + iny + bne @L1 + rts + +; ------------------------------------------------------------------------ +; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n). +; The page number is already checked to be valid by the graphics kernel. +; +; Must set an error code: NO (will only be called if page ok) +; + +SETVIEWPAGE: +; rts ; Fall through + +; ------------------------------------------------------------------------ +; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n). +; The page number is already checked to be valid by the graphics kernel. +; +; Must set an error code: NO (will only be called if page ok) +; + +SETDRAWPAGE: + rts + +; ------------------------------------------------------------------------ +; SETCOLOR: Set the drawing color (in A). The new color is already checked +; to be in a valid range (0..maxcolor-1). +; +; Must set an error code: NO (will only be called if color ok) +; + +SETCOLOR: + tax + beq @L1 + lda #$FF +@L1: sta BITMASK + rts + +; ------------------------------------------------------------------------ +; SETPALETTE: Set the palette (not available with all drivers/hardware). +; A pointer to the palette is passed in ptr1. Must set an error if palettes +; are not supported +; +; Must set an error code: YES +; + +SETPALETTE: + ldy #PALETTESIZE - 1 +@L1: lda (ptr1),y ; Copy the palette + sta PALETTE,y + dey + bpl @L1 + +; Get luma values from the high nybble of the palette entries + lda PALETTE+1 ; Foreground luma + lsr a + lsr a + lsr a + lsr a + sta TEMP ; Foreground -> low nybble + lda PALETTE ; Background luma + and #$F0 + ora TEMP ; Background -> high nybble + +; Initialize the luma map with the new luma values + ldy #0 +@L2: sta LBASE+$0000,y + sta LBASE+$0100,y + sta LBASE+$0200,y + sta LBASE+$02e8,y + iny + bne @L2 + + +; Get chroma values from the low nybble of the palette entries + lda PALETTE+1 ; Foreground chroma + and #$0F + asl a + asl a + asl a + asl a + sta TEMP ; Foreground -> high nybble + lda PALETTE ; Background chroma + and #$0F + ora TEMP ; Background -> low nybble + +; Initialize the chroma map with the new chroma values + ldy #0 +@L3: sta CBASE+$0000,y + sta CBASE+$0100,y + sta CBASE+$0200,y + sta CBASE+$02e8,y + iny + bne @L3 + +; Done, reset the error code + lda #TGI_ERR_OK + sta ERROR + rts + +; ------------------------------------------------------------------------ +; GETPALETTE: Return the current palette in A/X. Even drivers that cannot +; set the palette should return the default palette here, so there's no +; way for this function to fail. +; +; Must set an error code: NO +; + +GETPALETTE: + lda #<PALETTE + ldx #>PALETTE + rts + +; ------------------------------------------------------------------------ +; GETDEFPALETTE: Return the default palette for the driver in A/X. All +; drivers should return something reasonable here, even drivers that don't +; support palettes, otherwise the caller has no way to determine the colors +; of the (not changeable) palette. +; +; Must set an error code: NO (all drivers must have a default palette) +; + +GETDEFPALETTE: + lda #<DEFPALETTE + ldx #>DEFPALETTE + rts + +; ------------------------------------------------------------------------ +; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing +; color. The coordinates passed to this function are never outside the +; visible screen area, so there is no need for clipping inside this function. +; +; Must set an error code: NO +; + +SETPIXEL: + jsr CALC ; Calculate coordinates + + lda (POINT),Y + eor BITMASK + and BITTAB,X + eor (POINT),Y + sta (POINT),Y + +@L9: rts + +; ------------------------------------------------------------------------ +; GETPIXEL: Read the color value of a pixel and return it in A/X. The +; coordinates passed to this function are never outside the visible screen +; area, so there is no need for clipping inside this function. + + +GETPIXEL: + jsr CALC ; Calculate coordinates + + lda (POINT),Y + ldy #$00 + and BITTAB,X + beq @L1 + iny + +@L1: + tya ; Get color value into A + ldx #$00 ; Clear high byte + rts + +; ------------------------------------------------------------------------ +; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and +; X2/Y2 = ptr3/ptr4 using the current drawing color. +; +; X1,X2 etc. are set up above (x2=LINNUM in particular) +; Format is LINE x2,y2,x1,y1 +; +; Must set an error code: NO +; + +LINE: + +@CHECK: lda X2 ; Make sure x1<x2 + sec + sbc X1 + tax + lda X2+1 + sbc X1+1 + bpl @CONT + lda Y2 ; If not, swap P1 and P2 + ldy Y1 + sta Y1 + sty Y2 + lda Y2+1 + ldy Y1+1 + sta Y1+1 + sty Y2+1 + lda X1 + ldy X2 + sty X1 + sta X2 + lda X2+1 + ldy X1+1 + sta X1+1 + sty X2+1 + bcc @CHECK + +@CONT: sta DX+1 + stx DX + + ldx #$C8 ; INY + lda Y2 ; Calculate dy + sec + sbc Y1 + tay + lda Y2+1 + sbc Y1+1 + bpl @DYPOS ; Is y2>=y1? + lda Y1 ; Otherwise dy=y1-y2 + sec + sbc Y2 + tay + ldx #$88 ; DEY + +@DYPOS: sty DY ; 8-bit DY -- FIX ME? + stx YINCDEC + stx XINCDEC + + jsr CALC ; Set up .X, .Y, and POINT + lda BITCHUNK,X + sta OLDCHUNK + sta CHUNK + + ldx DY + cpx DX ; Who's bigger: dy or dx? + bcc STEPINX ; If dx, then... + lda DX+1 + bne STEPINX + +; +; Big steps in Y +; +; To simplify my life, just use PLOT to plot points. +; +; No more! +; Added special plotting routine -- cool! +; +; X is now counter, Y is y-coordinate +; +; On entry, X=DY=number of loop iterations, and Y= +; Y1 AND #$07 +STEPINY: + lda #00 + sta OLDCHUNK ; So plotting routine will work right + lda CHUNK + lsr ; Strip the bit + eor CHUNK + sta CHUNK + txa + beq YCONT2 ; If dy=0, it's just a point +@CONT: lsr ; Init counter to dy/2 +; +; Main loop +; +YLOOP: sta TEMP + + lda (POINT),y + eor BITMASK + and CHUNK + eor (POINT),y + sta (POINT),y +YINCDEC: + iny ; Advance Y coordinate + cpy #8 + bcc @CONT ; No prob if Y=0..7 + jsr FIXY +@CONT: lda TEMP ; Restore A + sec + sbc DX + bcc YFIXX +YCONT: dex ; X is counter + bne YLOOP +YCONT2: lda (POINT),y ; Plot endpoint + eor BITMASK + and CHUNK + eor (POINT),y + sta (POINT),y + rts + +YFIXX: ; X=x+1 + adc DY + lsr CHUNK + bne YCONT ; If we pass a column boundary... + ror CHUNK ; Then reset CHUNK to $80 + sta TEMP2 + lda POINT ; And add 8 to POINT + adc #8 + sta POINT + bcc @CONT + inc POINT+1 +@CONT: lda TEMP2 + dex + bne YLOOP + beq YCONT2 + +; +; Big steps in X direction +; +; On entry, X=DY=number of loop iterations, and Y= +; Y1 AND #$07 + +.bss +COUNTHI: + .byte $00 ; Temporary counter, only used once. +.code +STEPINX: + ldx DX + lda DX+1 + sta COUNTHI + cmp #$80 + ror ; Need bit for initialization + sta Y1 ; High byte of counter + txa + bne @CONT ; Could be $100 + dec COUNTHI +@CONT: ror +; +; Main loop +; +XLOOP: lsr CHUNK + beq XFIXC ; If we pass a column boundary... +XCONT1: sbc DY + bcc XFIXY ; Time to step in Y? +XCONT2: dex + bne XLOOP + dec COUNTHI ; High bits set? + bpl XLOOP + + lsr CHUNK ; Advance to last point + jmp LINEPLOT ; Plot the last chunk +; +; CHUNK has passed a column, so plot and increment pointer +; and fix up CHUNK, OLDCHUNK. +; +XFIXC: sta TEMP + jsr LINEPLOT + lda #$FF + sta CHUNK + sta OLDCHUNK + lda POINT + clc + adc #8 + sta POINT + lda TEMP + bcc XCONT1 + inc POINT+1 + jmp XCONT1 +; +; Check to make sure there isn't a high bit, plot chunk, +; and update Y-coordinate. +; +XFIXY: dec Y1 ; Maybe high bit set + bpl XCONT2 + adc DX + sta TEMP + lda DX+1 + adc #$FF ; Hi byte + sta Y1 + + jsr LINEPLOT ; Plot chunk + lda CHUNK + sta OLDCHUNK + + lda TEMP +XINCDEC: + iny ; Y-coord + cpy #8 ; 0..7 is ok + bcc XCONT2 + sta TEMP + jsr FIXY + lda TEMP + jmp XCONT2 + +; +; Subroutine to plot chunks/points (to save a little +; room, gray hair, etc.) +; +LINEPLOT: ; Plot the line chunk + lda (POINT),Y + eor BITMASK + ora CHUNK + and OLDCHUNK + eor CHUNK + eor (POINT),Y + sta (POINT),Y + rts + +; +; Subroutine to fix up pointer when Y decreases through +; zero or increases through 7. +; +FIXY: cpy #255 ; Y=255 or Y=8 + beq @DECPTR + +@INCPTR: ; Add 320 to pointer + ldy #0 ; Y increased through 7 + lda POINT + adc #<320 + sta POINT + lda POINT+1 + adc #>320 + sta POINT+1 + rts + +@DECPTR: ; Okay, subtract 320 then + ldy #7 ; Y decreased through 0 + lda POINT + sec + sbc #<320 + sta POINT + lda POINT+1 + sbc #>320 + sta POINT+1 + rts + +; ------------------------------------------------------------------------ +; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where +; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color. +; Contrary to most other functions, the graphics kernel will sort and clip +; the coordinates before calling the driver, so on entry the following +; conditions are valid: +; X1 <= X2 +; Y1 <= Y2 +; (X1 >= 0) && (X1 < XRES) +; (X2 >= 0) && (X2 < XRES) +; (Y1 >= 0) && (Y1 < YRES) +; (Y2 >= 0) && (Y2 < YRES) +; +; Must set an error code: NO +; + +; Note: This function needs optimization. It's just a cheap translation of +; the original C wrapper and could be written much smaller (besides that, +; calling LINE is not a good idea either). + +BAR: lda Y2 + sta Y2SAVE + lda Y2+1 + sta Y2SAVE+1 + + lda X2 + sta X2SAVE + lda X2+1 + sta X2SAVE+1 + + lda Y1 + sta Y1SAVE + lda Y1+1 + sta Y1SAVE+1 + + lda X1 + sta X1SAVE + lda X1+1 + sta X1SAVE+1 + +@L1: lda Y1 + sta Y2 + lda Y1+1 + sta Y2+1 + jsr LINE + + lda Y1SAVE + cmp Y2SAVE + bne @L2 + lda Y1SAVE + cmp Y2SAVE + beq @L4 + +@L2: inc Y1SAVE + bne @L3 + inc Y1SAVE+1 + +@L3: lda Y1SAVE + sta Y1 + lda Y1SAVE+1 + sta Y1+1 + + lda X1SAVE + sta X1 + lda X1SAVE+1 + sta X1+1 + + lda X2SAVE + sta X2 + lda X2SAVE+1 + sta X2+1 + jmp @L1 + +@L4: rts + + +; ------------------------------------------------------------------------ +; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y +; direction is passend in X/Y, the text direction is passed in A. +; +; Must set an error code: NO +; + +TEXTSTYLE: + stx TEXTMAGX + sty TEXTMAGY + sta TEXTDIR + rts + + +; ------------------------------------------------------------------------ +; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the +; current text style. The text to output is given as a zero terminated +; string with address in ptr3. +; +; Must set an error code: NO +; + +OUTTEXT: + rts + +; ------------------------------------------------------------------------ +; Calculate all variables to plot the pixel at X1/Y1. + +CALC: lda Y1 + sta TEMP2 + and #7 + tay + lda Y1+1 + lsr ; Neg is possible + ror TEMP2 + lsr + ror TEMP2 + lsr + ror TEMP2 + + lda #00 + sta POINT + lda TEMP2 + cmp #$80 + ror + ror POINT + cmp #$80 + ror + ror POINT ; Row * 64 + adc TEMP2 ; + Row * 256 + clc + adc #>VBASE ; + Bitmap base + sta POINT+1 + + lda X1 + tax + and #$F8 + clc + adc POINT ; +(X AND #$F8) + sta POINT + lda X1+1 + adc POINT+1 + sta POINT+1 + txa + and #7 + tax + rts diff --git a/libsrc/plus4/tgi_stat_stddrv.s b/libsrc/plus4/tgi_stat_stddrv.s new file mode 100644 index 000000000..dc918eb8b --- /dev/null +++ b/libsrc/plus4/tgi_stat_stddrv.s @@ -0,0 +1,14 @@ +; +; Address of the static standard tgi driver +; +; Oliver Schmidt, 2012-11-01 +; +; const void tgi_static_stddrv[]; +; + + .export _tgi_static_stddrv + .import _ted_hi_tgi + +.rodata + +_tgi_static_stddrv := _ted_hi_tgi diff --git a/libsrc/plus4/tgi_stddrv.s b/libsrc/plus4/tgi_stddrv.s new file mode 100644 index 000000000..eac16905d --- /dev/null +++ b/libsrc/plus4/tgi_stddrv.s @@ -0,0 +1,13 @@ +; +; Name of the standard tgi driver +; +; Oliver Schmidt, 2011-05-02 +; +; const char tgi_stddrv[]; +; + + .export _tgi_stddrv + +.rodata + +_tgi_stddrv: .asciiz "ted-hi.tgi" diff --git a/samples/Makefile b/samples/Makefile index 194bd3244..9c9d4bcf6 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -109,6 +109,7 @@ DISK_apple2 = samples.dsk DISK_apple2enh = samples.dsk DISK_atari = samples.atr DISK_atarixl = samples.atr +DISK_plus4 = samples.d64 # -------------------------------------------------------------------------- # System-dependent settings @@ -156,6 +157,8 @@ LDFLAGS_tgidemo_atarixl = --start-addr 0x4000 .o: ifeq ($(SYS),vic20) $(LD) $(LDFLAGS_$(@F)_$(SYS)) $(LDFLAGS) -o $@ -C vic20-32k.cfg -m $@.map $^ $(SYS).lib +else ifeq ($(SYS),plus4) + $(LD) $(LDFLAGS_$(@F)_$(SYS)) $(LDFLAGS) -o $@ -C plus4-hires.cfg -m $@.map $^ $(SYS).lib else $(LD) $(LDFLAGS_$(@F)_$(SYS)) $(LDFLAGS) -o $@ -t $(SYS) -m $@.map $^ $(SYS).lib endif @@ -168,6 +171,11 @@ DIRLIST = tutorial geos atari2600 atari5200 apple2 gamate lynx supervision sym1 # -------------------------------------------------------------------------- # Lists of executables +EXELIST_agat = \ + ascii \ + checkversion \ + hello \ + sieve EXELIST_apple2 = \ ascii \ @@ -331,9 +339,11 @@ EXELIST_plus4 = \ enumdevdir \ gunzip65 \ hello \ + mandelbrot \ terminal \ tinyshell \ - sieve + sieve \ + tgidemo EXELIST_sim6502 = \ checkversion \ @@ -400,6 +410,7 @@ all: # -------------------------------------------------------------------------- # List of every supported platform TARGETS := \ + agat \ apple2 \ apple2enh \ atari \ @@ -455,7 +466,15 @@ multdemo: multidemo.o ovrldemo: overlaydemo.o $(LD) $(LDFLAGS) -o $@ -C $(SYS)-overlay.cfg -m $@.map $^ $(SYS).lib -OVERLAYLIST := $(foreach I,1 2 3,multdemo.$I ovrldemo.$I) +OVERLAYLIST := + +ifneq ($(filter ovrldemo,$(EXELIST_$(SYS))),) +OVERLAYLIST += $(foreach I,1 2 3,ovrldemo.$I) +endif + +ifneq ($(filter multdemo,$(EXELIST_$(SYS))),) +OVERLAYLIST += $(foreach I,1 2 3,multdemo.$I) +endif # -------------------------------------------------------------------------- # TGI programs on the VIC-20 need a special ld65 configuration file. diff --git a/samples/diodemo.c b/samples/diodemo.c index 3e52f2fa9..46656246d 100644 --- a/samples/diodemo.c +++ b/samples/diodemo.c @@ -30,6 +30,7 @@ +#define DYN_BOX_DRAW #include <stddef.h> #include <stdlib.h> #include <limits.h> diff --git a/samples/hello.c b/samples/hello.c index 255dccd00..2eac0d8bb 100644 --- a/samples/hello.c +++ b/samples/hello.c @@ -7,6 +7,7 @@ +#define DYN_BOX_DRAW #include <stdlib.h> #include <string.h> #include <conio.h> diff --git a/samples/sieve.c b/samples/sieve.c index 7c3b9cd75..5ffc97b62 100644 --- a/samples/sieve.c +++ b/samples/sieve.c @@ -12,7 +12,7 @@ /* Workaround missing clock stuff */ -#ifdef __APPLE2__ +#if defined(__APPLE2__) || defined(__AGAT__) # define clock() 0 # define CLOCKS_PER_SEC 1 #endif diff --git a/samples/tgidemo.c b/samples/tgidemo.c index f193a1b83..cdb4c3ad9 100644 --- a/samples/tgidemo.c +++ b/samples/tgidemo.c @@ -12,8 +12,10 @@ # define DYN_DRV 1 #endif -#define COLOR_BACK TGI_COLOR_BLACK -#define COLOR_FORE TGI_COLOR_WHITE + +/* Color values passed to TGI functions are indices into the default palette. */ +#define COLOR_BACK 0 +#define COLOR_FORE 1 /*****************************************************************************/ @@ -65,17 +67,39 @@ static void DoWarning (void) #endif +/* + * Note that everywhere else in the TGI API, colors are referred to via an index + * to the current palette. + * + * TGI_COLOR_ values can be used (ONLY!) for setting the palette, using them + * with other TGI functions only works by chance, on some targets. + */ +static void DoPalette (int n) +{ + static const unsigned char Palette[4][2] = { +/* FIXME: add some ifdefs with proper values for targets that need it */ +#if !defined(__APPLE2__) + { TGI_COLOR_BLACK, TGI_COLOR_BLUE }, + { TGI_COLOR_WHITE, TGI_COLOR_BLACK }, + { TGI_COLOR_RED, TGI_COLOR_BLACK }, +#else + { TGI_COLOR_WHITE, TGI_COLOR_BLACK }, + { TGI_COLOR_BLACK, TGI_COLOR_WHITE }, + { TGI_COLOR_WHITE, TGI_COLOR_BLACK }, +#endif + }; + tgi_setpalette (Palette[n]); +} + static void DoCircles (void) { - static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLUE }; unsigned char I; unsigned char Color = COLOR_BACK; const unsigned X = MaxX / 2; const unsigned Y = MaxY / 2; const unsigned Limit = (X < Y) ? Y : X; - tgi_setpalette (Palette); tgi_setcolor (COLOR_FORE); tgi_clear (); tgi_line (0, 0, MaxX, MaxY); @@ -87,7 +111,9 @@ static void DoCircles (void) tgi_ellipse (X, Y, I, tgi_imulround (I, AspectRatio)); } } - + while (kbhit ()) { + cgetc (); + } cgetc (); } @@ -95,11 +121,9 @@ static void DoCircles (void) static void DoCheckerboard (void) { - static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLACK }; unsigned X, Y; unsigned char Color = COLOR_BACK; - tgi_setpalette (Palette); tgi_clear (); while (1) { @@ -123,13 +147,11 @@ static void DoCheckerboard (void) static void DoDiagram (void) { - static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLACK }; int XOrigin, YOrigin; int Amp; int X, Y; unsigned I; - tgi_setpalette (Palette); tgi_setcolor (COLOR_FORE); tgi_clear (); @@ -160,6 +182,9 @@ static void DoDiagram (void) tgi_lineto (XOrigin + X, YOrigin + Y); } + while (kbhit ()) { + cgetc (); + } cgetc (); } @@ -167,11 +192,9 @@ static void DoDiagram (void) static void DoLines (void) { - static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_BLACK }; unsigned X; const unsigned Min = (MaxX < MaxY) ? MaxX : MaxY; - tgi_setpalette (Palette); tgi_setcolor (COLOR_FORE); tgi_clear (); @@ -182,6 +205,9 @@ static void DoLines (void) tgi_line (Min, Min, Min-X, 0); } + while (kbhit ()) { + cgetc (); + } cgetc (); } @@ -216,10 +242,11 @@ int main (void) Border = bordercolor (COLOR_BLACK); /* Do graphics stuff */ - DoCircles (); - DoCheckerboard (); - DoDiagram (); - DoLines (); + + /* use default palette */ DoCircles (); + DoPalette (0); DoCheckerboard (); + DoPalette (1); DoDiagram (); + DoPalette (2); DoLines (); #if DYN_DRV /* Unload the driver */ diff --git a/src/Makefile b/src/Makefile index 8d335d52c..99caf7450 100644 --- a/src/Makefile +++ b/src/Makefile @@ -178,4 +178,19 @@ $(eval $(call OBJS_template,common)) $(foreach prog,$(PROGS),$(eval $(call PROG_template,$(prog)))) + +.PHONY: dbginfo dbgsh test + +test: dbginfo dbgsh + +$(eval $(call OBJS_template,dbginfo)) + +dbginfo: $(dbginfo_OBJS) + +../wrk/dbgsh$(EXE_SUFFIX): $(dbginfo_OBJS) ../wrk/common/common.a + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +dbgsh: ../wrk/dbgsh$(EXE_SUFFIX) + + -include $(DEPS) diff --git a/src/ca65/condasm.c b/src/ca65/condasm.c index f872ec9ed..60e8ab0c1 100644 --- a/src/ca65/condasm.c +++ b/src/ca65/condasm.c @@ -394,6 +394,16 @@ void DoConditionals (void) CalcOverallIfCond (); break; + case TOK_IFP02X: + D = AllocIf (".IFP02X", 1); + NextTok (); + if (IfCond) { + SetIfCond (D, GetCPU() == CPU_6502X); + } + ExpectSep (); + CalcOverallIfCond (); + break; + case TOK_IFP4510: D = AllocIf (".IFP4510", 1); NextTok (); @@ -485,6 +495,7 @@ int CheckConditionals (void) case TOK_IFNDEF: case TOK_IFNREF: case TOK_IFP02: + case TOK_IFP02X: case TOK_IFP4510: case TOK_IFP816: case TOK_IFPC02: diff --git a/src/ca65/instr.c b/src/ca65/instr.c index da6bd6e44..c7a68006c 100644 --- a/src/ca65/instr.c +++ b/src/ca65/instr.c @@ -169,8 +169,10 @@ static const struct { unsigned Count; InsDesc Ins[56]; } InsTab6502 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab6502.Ins) / sizeof (InsTab6502.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A26C, 0x60, 0, PutAll }, { "AND", 0x080A26C, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -227,6 +229,7 @@ static const struct { { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll } +/* END SORTED.SH */ } }; @@ -235,8 +238,10 @@ static const struct { unsigned Count; InsDesc Ins[75]; } InsTab6502X = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab6502X.Ins) / sizeof (InsTab6502X.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A26C, 0x60, 0, PutAll }, { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */ { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */ @@ -312,6 +317,7 @@ static const struct { { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll } +/* END SORTED.SH */ } }; @@ -324,8 +330,10 @@ static const struct { unsigned Count; InsDesc Ins[71]; } InsTab6502DTV = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab6502DTV.Ins) / sizeof (InsTab6502DTV.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A26C, 0x60, 0, PutAll }, { "ALR", 0x0800000, 0x4B, 0, PutAll }, /* X */ { "ANC", 0x0800000, 0x0B, 0, PutAll }, /* X */ @@ -397,6 +405,7 @@ static const struct { { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll } +/* END SORTED.SH */ } }; @@ -405,8 +414,10 @@ static const struct { unsigned Count; InsDesc Ins[66]; } InsTab65SC02 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab65SC02.Ins) / sizeof (InsTab65SC02.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A66C, 0x60, 0, PutAll }, { "AND", 0x080A66C, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -473,6 +484,7 @@ static const struct { { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll } +/* END SORTED.SH */ } }; @@ -481,8 +493,10 @@ static const struct { unsigned Count; InsDesc Ins[100]; } InsTab65C02 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab65C02.Ins) / sizeof (InsTab65C02.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A66C, 0x60, 0, PutAll }, { "AND", 0x080A66C, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -583,6 +597,7 @@ static const struct { { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll }, { "WAI", 0x0000001, 0xcb, 0, PutAll } +/* END SORTED.SH */ } }; @@ -591,8 +606,10 @@ static const struct { unsigned Count; InsDesc Ins[133]; } InsTab4510 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab4510.Ins) / sizeof (InsTab4510.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A66C, 0x60, 0, PutAll }, { "AND", 0x080A66C, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -726,6 +743,7 @@ static const struct { { "TYA", 0x0000001, 0x98, 0, PutAll }, { "TYS", 0x0000001, 0x2b, 0, PutAll }, { "TZA", 0x0000001, 0x6b, 0, PutAll }, +/* END SORTED.SH */ } }; @@ -734,8 +752,10 @@ static const struct { unsigned Count; InsDesc Ins[100]; } InsTab65816 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTab65816.Ins) / sizeof (InsTab65816.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x0b8f6fc, 0x60, 0, PutAll }, { "AND", 0x0b8f6fc, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -836,6 +856,7 @@ static const struct { { "WDM", 0x0800004, 0x42, 6, PutAll }, { "XBA", 0x0000001, 0xeb, 0, PutAll }, { "XCE", 0x0000001, 0xfb, 0, PutAll } +/* END SORTED.SH */ } }; @@ -844,8 +865,10 @@ static const struct { unsigned Count; InsDesc Ins[26]; } InsTabSweet16 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTabSweet16.Ins) / sizeof (InsTabSweet16.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADD", AMSW16_REG, 0xA0, 0, PutSweet16 }, { "BC", AMSW16_BRA, 0x03, 0, PutSweet16Branch }, { "BK", AMSW16_IMP, 0x0A, 0, PutSweet16 }, @@ -872,6 +895,7 @@ static const struct { { "STD", AMSW16_IND, 0x70, 0, PutSweet16 }, { "STP", AMSW16_IND, 0x90, 0, PutSweet16 }, { "SUB", AMSW16_REG, 0xB0, 0, PutSweet16 }, +/* END SORTED.SH */ } }; @@ -880,8 +904,10 @@ static const struct { unsigned Count; InsDesc Ins[135]; } InsTabHuC6280 = { + /* CAUTION: table must be sorted for bsearch */ sizeof (InsTabHuC6280.Ins) / sizeof (InsTabHuC6280.Ins[0]), { +/* BEGIN SORTED.SH */ { "ADC", 0x080A66C, 0x60, 0, PutAll }, { "AND", 0x080A66C, 0x20, 0, PutAll }, { "ASL", 0x000006e, 0x02, 1, PutAll }, @@ -1017,6 +1043,7 @@ static const struct { { "TXA", 0x0000001, 0x8a, 0, PutAll }, { "TXS", 0x0000001, 0x9a, 0, PutAll }, { "TYA", 0x0000001, 0x98, 0, PutAll } +/* END SORTED.SH */ } }; diff --git a/src/ca65/main.c b/src/ca65/main.c index f3100162a..682e9be7f 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -350,6 +350,10 @@ static void SetSys (const char* Sys) NewSymbol ("__RP6502__", 1); break; + case TGT_AGAT: + NewSymbol ("__AGAT__", 1); + break; + default: AbEnd ("Invalid target name: '%s'", Sys); diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 2ce1ae087..37dcd78da 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -1562,6 +1562,14 @@ static void DoP02 (void) +static void DoP02X (void) +/* Switch to 6502 CPU */ +{ + SetCPU (CPU_6502X); +} + + + static void DoPC02 (void) /* Switch to 65C02 CPU */ { @@ -2057,70 +2065,72 @@ struct CtrlDesc { void (*Handler) (void); /* Command handler */ }; +/* NOTE: .AND, .BITAND, .BITNOT, .BITOR, .BITXOR, .MOD, .NOT, .OR, .SHL, .SHR + and .XOR do NOT go into this table */ #define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0])) static CtrlDesc CtrlCmdTab [] = { - { ccNone, DoA16 }, - { ccNone, DoA8 }, + { ccNone, DoA16 }, /* .A16 */ + { ccNone, DoA8 }, /* .A8 */ { ccNone, DoAddr }, /* .ADDR */ { ccNone, DoUnexpected }, /* .ADDRSIZE */ - { ccNone, DoAlign }, - { ccNone, DoASCIIZ }, + { ccNone, DoAlign }, /* .ALIGN */ + { ccNone, DoASCIIZ }, /* .ASCIIZ */ { ccNone, DoUnexpected }, /* .ASIZE */ - { ccNone, DoAssert }, - { ccNone, DoAutoImport }, + { ccNone, DoAssert }, /* .ASSERT */ + { ccNone, DoAutoImport }, /* .AUTOIMPORT */ { ccNone, DoUnexpected }, /* .BANK */ { ccNone, DoUnexpected }, /* .BANKBYTE */ - { ccNone, DoBankBytes }, + { ccNone, DoBankBytes }, /* .BANKBYTES */ { ccNone, DoUnexpected }, /* .BLANK */ - { ccNone, DoBss }, - { ccNone, DoByte }, - { ccNone, DoCase }, - { ccNone, DoCharMap }, - { ccNone, DoCode }, + { ccNone, DoBss }, /* .BSS */ + { ccNone, DoByte }, /* .BYT, .BYTE */ + { ccNone, DoCase }, /* .CASE */ + { ccNone, DoCharMap }, /* .CHARMAP */ + { ccNone, DoCode }, /* .CODE */ { ccNone, DoUnexpected, }, /* .CONCAT */ - { ccNone, DoConDes }, + { ccNone, DoConDes }, /* .CONDES */ { ccNone, DoUnexpected }, /* .CONST */ - { ccNone, DoConstructor }, + { ccNone, DoConstructor }, /* .CONSTRUCTOR */ { ccNone, DoUnexpected }, /* .CPU */ - { ccNone, DoData }, - { ccNone, DoDbg, }, - { ccNone, DoDByt }, - { ccNone, DoDebugInfo }, - { ccKeepToken, DoDefine }, + { ccNone, DoData }, /* .DATA */ + { ccNone, DoDbg, }, /* .DBG */ + { ccNone, DoDByt }, /* .DBYT */ + { ccNone, DoDebugInfo }, /* .DEBUGINFO */ + { ccKeepToken, DoDefine }, /* .DEF, .DEFINE */ { ccNone, DoUnexpected }, /* .DEFINED */ { ccNone, DoUnexpected }, /* .DEFINEDMACRO */ - { ccNone, DoDelMac }, - { ccNone, DoDestructor }, - { ccNone, DoDWord }, + { ccNone, DoDelMac }, /* .DELMAC, .DELMACRO */ + { ccNone, DoDestructor }, /* .DESTRUCTOR */ + { ccNone, DoDWord }, /* .DWORD */ { ccKeepToken, DoConditionals }, /* .ELSE */ { ccKeepToken, DoConditionals }, /* .ELSEIF */ - { ccKeepToken, DoEnd }, + { ccKeepToken, DoEnd }, /* .END */ { ccNone, DoUnexpected }, /* .ENDENUM */ { ccKeepToken, DoConditionals }, /* .ENDIF */ - { ccNone, DoUnexpected }, /* .ENDMACRO */ - { ccNone, DoEndProc }, - { ccNone, DoUnexpected }, /* .ENDREPEAT */ - { ccNone, DoEndScope }, + { ccNone, DoUnexpected }, /* .ENDMAC, .ENDMACRO */ + { ccNone, DoEndProc }, /* .ENDPROC */ + { ccNone, DoUnexpected }, /* .ENDREP, .ENDREPEAT */ + { ccNone, DoEndScope }, /* .ENDSCOPE */ { ccNone, DoUnexpected }, /* .ENDSTRUCT */ { ccNone, DoUnexpected }, /* .ENDUNION */ - { ccNone, DoEnum }, - { ccNone, DoError }, - { ccNone, DoExitMacro }, - { ccNone, DoExport }, - { ccNone, DoExportZP }, - { ccNone, DoFarAddr }, - { ccNone, DoFatal }, - { ccNone, DoFeature }, - { ccNone, DoFileOpt }, - { ccNone, DoForceImport }, + { ccNone, DoEnum }, /* .ENUM */ + { ccNone, DoError }, /* .ERROR */ + { ccNone, DoExitMacro }, /* .EXITMAC, .EXITMACRO */ + { ccNone, DoExport }, /* .EXPORT */ + { ccNone, DoExportZP }, /* .EXPORTZP */ + { ccNone, DoFarAddr }, /* .FARADDR */ + { ccNone, DoFatal }, /* .FATAL */ + { ccNone, DoFeature }, /* .FEATURE */ + { ccNone, DoFileOpt }, /* .FOPT, .FILEOPT */ + { ccNone, DoForceImport }, /* .FORCEIMPORT */ { ccNone, DoUnexpected }, /* .FORCEWORD */ - { ccNone, DoGlobal }, - { ccNone, DoGlobalZP }, + { ccNone, DoGlobal }, /* .GLOBAL */ + { ccNone, DoGlobalZP }, /* .GLOBALZP */ { ccNone, DoUnexpected }, /* .HIBYTE */ - { ccNone, DoHiBytes }, + { ccNone, DoHiBytes }, /* .HIBYTES */ { ccNone, DoUnexpected }, /* .HIWORD */ - { ccNone, DoI16 }, - { ccNone, DoI8 }, + { ccNone, DoI16 }, /* .I16 */ + { ccNone, DoI8 }, /* .I8 */ { ccNone, DoUnexpected }, /* .IDENT */ { ccKeepToken, DoConditionals }, /* .IF */ { ccKeepToken, DoConditionals }, /* .IFBLANK */ @@ -2131,81 +2141,83 @@ static CtrlDesc CtrlCmdTab [] = { { ccKeepToken, DoConditionals }, /* .IFNDEF */ { ccKeepToken, DoConditionals }, /* .IFNREF */ { ccKeepToken, DoConditionals }, /* .IFP02 */ + { ccKeepToken, DoConditionals }, /* .IFP02X */ { ccKeepToken, DoConditionals }, /* .IFP4510 */ { ccKeepToken, DoConditionals }, /* .IFP816 */ { ccKeepToken, DoConditionals }, /* .IFPC02 */ { ccKeepToken, DoConditionals }, /* .IFPDTV */ { ccKeepToken, DoConditionals }, /* .IFPSC02 */ { ccKeepToken, DoConditionals }, /* .IFREF */ - { ccNone, DoImport }, - { ccNone, DoImportZP }, - { ccNone, DoIncBin }, - { ccNone, DoInclude }, - { ccNone, DoInterruptor }, + { ccNone, DoImport }, /* .IMPORT */ + { ccNone, DoImportZP }, /* .IMPORTZP */ + { ccNone, DoIncBin }, /* .INCBIN */ + { ccNone, DoInclude }, /* .INCLUDE */ + { ccNone, DoInterruptor }, /* .INTERRUPTPOR */ { ccNone, DoUnexpected }, /* .ISIZE */ { ccNone, DoUnexpected }, /* .ISMNEMONIC */ { ccNone, DoInvalid }, /* .LEFT */ - { ccNone, DoLineCont }, - { ccNone, DoList }, - { ccNone, DoListBytes }, - { ccNone, DoLiteral }, + { ccNone, DoLineCont }, /* .LINECONT */ + { ccNone, DoList }, /* .LIST */ + { ccNone, DoListBytes }, /* .LISTBYTES */ + { ccNone, DoLiteral }, /* .LITERAL */ { ccNone, DoUnexpected }, /* .LOBYTE */ - { ccNone, DoLoBytes }, + { ccNone, DoLoBytes }, /* .LOBYTES */ { ccNone, DoUnexpected }, /* .LOCAL */ - { ccNone, DoLocalChar }, + { ccNone, DoLocalChar }, /* .LOCALCHAR */ { ccNone, DoUnexpected }, /* .LOWORD */ - { ccNone, DoMacPack }, - { ccNone, DoMacro }, + { ccNone, DoMacPack }, /* .MACPACK */ + { ccNone, DoMacro }, /* .MAC, .MACRO */ { ccNone, DoUnexpected }, /* .MATCH */ { ccNone, DoUnexpected }, /* .MAX */ { ccNone, DoInvalid }, /* .MID */ { ccNone, DoUnexpected }, /* .MIN */ - { ccNone, DoNull }, - { ccNone, DoOrg }, - { ccNone, DoOut }, - { ccNone, DoP02 }, - { ccNone, DoP4510 }, - { ccNone, DoP816 }, - { ccNone, DoPageLength }, + { ccNone, DoNull }, /* .NULL */ + { ccNone, DoOrg }, /* .ORG */ + { ccNone, DoOut }, /* .OUT */ + { ccNone, DoP02 }, /* .P02 */ + { ccNone, DoP02X }, /* .P02X */ + { ccNone, DoP4510 }, /* .P4510 */ + { ccNone, DoP816 }, /* .P816 */ + { ccNone, DoPageLength }, /* .PAGELEN, .PAGELENGTH */ { ccNone, DoUnexpected }, /* .PARAMCOUNT */ - { ccNone, DoPC02 }, - { ccNone, DoPDTV }, - { ccNone, DoPopCharmap }, - { ccNone, DoPopCPU }, - { ccNone, DoPopSeg }, - { ccNone, DoProc }, - { ccNone, DoPSC02 }, - { ccNone, DoPushCharmap }, - { ccNone, DoPushCPU }, - { ccNone, DoPushSeg }, - { ccNone, DoUnexpected }, /* .REFERENCED */ - { ccNone, DoReferTo }, /* .REFERTO */ - { ccNone, DoReloc }, - { ccNone, DoRepeat }, - { ccNone, DoRes }, + { ccNone, DoPC02 }, /* .PSC02 */ + { ccNone, DoPDTV }, /* .PDTV */ + { ccNone, DoPopCharmap }, /* .POPCHARMAP */ + { ccNone, DoPopCPU }, /* .POPCPU */ + { ccNone, DoPopSeg }, /* .POPSEG */ + { ccNone, DoProc }, /* .PROC */ + { ccNone, DoPSC02 }, /* .PSC02 */ + { ccNone, DoPushCharmap }, /* .PUSHCHARMAP */ + { ccNone, DoPushCPU }, /* .PUSHCPU */ + { ccNone, DoPushSeg }, /* .PUSHSEG */ + { ccNone, DoUnexpected }, /* .REF, .REFERENCED */ + { ccNone, DoReferTo }, /* .REFTO, .REFERTO */ + { ccNone, DoReloc }, /* .RELOC */ + { ccNone, DoRepeat }, /* .REPEAT */ + { ccNone, DoRes }, /* .RES */ { ccNone, DoInvalid }, /* .RIGHT */ - { ccNone, DoROData }, - { ccNone, DoScope }, - { ccNone, DoSegment }, + { ccNone, DoROData }, /* .RODATA */ + { ccNone, DoScope }, /* .SCOPE */ + { ccNone, DoSegment }, /* .SEGMENT */ { ccNone, DoUnexpected }, /* .SET */ - { ccNone, DoSetCPU }, + { ccNone, DoSetCPU }, /* .SETCPU */ { ccNone, DoUnexpected }, /* .SIZEOF */ - { ccNone, DoSmart }, + { ccNone, DoSmart }, /* .SMART */ { ccNone, DoUnexpected }, /* .SPRINTF */ { ccNone, DoUnexpected }, /* .STRAT */ { ccNone, DoUnexpected }, /* .STRING */ { ccNone, DoUnexpected }, /* .STRLEN */ - { ccNone, DoStruct }, - { ccNone, DoTag }, + { ccNone, DoStruct }, /* .STRUCT */ + { ccNone, DoTag }, /* .TAG */ { ccNone, DoUnexpected }, /* .TCOUNT */ { ccNone, DoUnexpected }, /* .TIME */ - { ccKeepToken, DoUnDef }, - { ccNone, DoUnion }, + { ccKeepToken, DoUnDef }, /* .UNDEF, .UNDEFINE */ + { ccNone, DoUnion }, /* .UNION */ { ccNone, DoUnexpected }, /* .VERSION */ - { ccNone, DoWarning }, - { ccNone, DoWord }, + { ccNone, DoWarning }, /* .WARNING */ + { ccNone, DoWord }, /* .WORD */ { ccNone, DoUnexpected }, /* .XMATCH */ - { ccNone, DoZeropage }, + { ccNone, DoZeropage }, /* .ZEROPAGE */ }; diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index da9883e52..157702897 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -131,10 +131,12 @@ static int C = 0; /* Current input character */ int ForcedEnd = 0; /* List of dot keywords with the corresponding tokens */ +/* CAUTION: table must be sorted for bsearch */ struct DotKeyword { const char* Key; /* MUST be first field */ token_t Tok; } DotKeywords [] = { +/* BEGIN SORTED.SH */ { ".A16", TOK_A16 }, { ".A8", TOK_A8 }, { ".ADDR", TOK_ADDR }, @@ -219,6 +221,7 @@ struct DotKeyword { { ".IFNDEF", TOK_IFNDEF }, { ".IFNREF", TOK_IFNREF }, { ".IFP02", TOK_IFP02 }, + { ".IFP02X", TOK_IFP02X }, { ".IFP4510", TOK_IFP4510 }, { ".IFP816", TOK_IFP816 }, { ".IFPC02", TOK_IFPC02 }, @@ -257,6 +260,7 @@ struct DotKeyword { { ".ORG", TOK_ORG }, { ".OUT", TOK_OUT }, { ".P02", TOK_P02 }, + { ".P02X", TOK_P02X }, { ".P4510", TOK_P4510 }, { ".P816", TOK_P816 }, { ".PAGELEN", TOK_PAGELENGTH }, @@ -306,6 +310,7 @@ struct DotKeyword { { ".XMATCH", TOK_XMATCH }, { ".XOR", TOK_BOOLXOR }, { ".ZEROPAGE", TOK_ZEROPAGE }, +/* END SORTED.SH */ }; diff --git a/src/ca65/token.h b/src/ca65/token.h index 8f935f7a1..aeae7166a 100644 --- a/src/ca65/token.h +++ b/src/ca65/token.h @@ -193,6 +193,7 @@ typedef enum token_t { TOK_IFNDEF, TOK_IFNREF, TOK_IFP02, + TOK_IFP02X, TOK_IFP4510, TOK_IFP816, TOK_IFPC02, @@ -226,6 +227,7 @@ typedef enum token_t { TOK_ORG, TOK_OUT, TOK_P02, + TOK_P02X, TOK_P4510, TOK_P816, TOK_PAGELENGTH, diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 435794613..29f18cb78 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -90,7 +90,9 @@ struct FuncInfo { ** routines are marked to use only the A register. The remainder is ignored ** anyway. */ +/* CAUTION: table must be sorted for bsearch */ static const FuncInfo FuncInfoTable[] = { +/* BEGIN SORTED.SH */ { "addeq0sp", SLV_TOP | REG_AX, PSTATE_ALL | REG_AXY }, { "addeqysp", SLV_IND | REG_AXY, PSTATE_ALL | REG_AXY }, { "addysp", REG_SP | REG_Y, PSTATE_ALL | REG_SP }, @@ -190,12 +192,12 @@ static const FuncInfo FuncInfoTable[] = { { "ldeaxysp", SLV_IND | REG_Y, PSTATE_ALL | REG_EAXY }, { "leaa0sp", REG_SP | REG_A, PSTATE_ALL | REG_AX }, { "leaaxsp", REG_SP | REG_AX, PSTATE_ALL | REG_AX }, - { "leave00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY }, - { "leave0", REG_SP, PSTATE_ALL | REG_SP | REG_XY }, { "leave", REG_SP, PSTATE_ALL | REG_SP | REG_Y }, - { "leavey00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY }, - { "leavey0", REG_SP, PSTATE_ALL | REG_SP | REG_XY }, + { "leave0", REG_SP, PSTATE_ALL | REG_SP | REG_XY }, + { "leave00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY }, { "leavey", REG_SP | REG_Y, PSTATE_ALL | REG_SP | REG_Y }, + { "leavey0", REG_SP, PSTATE_ALL | REG_SP | REG_XY }, + { "leavey00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY }, { "lsubeq", REG_EAXY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI }, { "lsubeq0sp", SLV_TOP | REG_EAX, PSTATE_ALL | REG_EAXY }, { "lsubeq1", REG_Y | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI }, @@ -376,11 +378,14 @@ static const FuncInfo FuncInfoTable[] = { { "tosxoreax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 }, { "tsteax", REG_EAX, PSTATE_ALL | REG_Y }, { "utsteax", REG_EAX, PSTATE_ALL | REG_Y }, +/* END SORTED.SH */ }; #define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0])) /* Table with names of zero page locations used by the compiler */ +/* CAUTION: table must be sorted for bsearch */ static const ZPInfo ZPInfoTable[] = { +/* BEGIN SORTED.SH */ { 0, "ptr1", 2, REG_PTR1_LO, REG_PTR1 }, { 0, "ptr1+1", 1, REG_PTR1_HI, REG_PTR1 }, { 0, "ptr2", 2, REG_PTR2_LO, REG_PTR2 }, @@ -398,6 +403,7 @@ static const ZPInfo ZPInfoTable[] = { { 0, "tmp2", 1, REG_NONE, REG_NONE }, { 0, "tmp3", 1, REG_NONE, REG_NONE }, { 0, "tmp4", 1, REG_NONE, REG_NONE }, +/* END SORTED.SH */ }; #define ZPInfoCount (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0])) diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index a716ad431..c8d7d2ce9 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -102,6 +102,8 @@ struct OptFunc { /* A list of all the function descriptions */ +/* CAUTION: should be sorted by "name" */ +/* BEGIN DECL SORTED_CODEOPT.SH */ static OptFunc DOpt65C02BitOps = { Opt65C02BitOps, "Opt65C02BitOps", 66, 0, 0, 0, 0, 0 }; static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 100, 0, 0, 0, 0, 0 }; static OptFunc DOpt65C02Stores = { Opt65C02Stores, "Opt65C02Stores", 100, 0, 0, 0, 0, 0 }; @@ -152,18 +154,13 @@ static OptFunc DOptJumpTarget3 = { OptJumpTarget3, "OptJumpTarget3", 100, 0, static OptFunc DOptLoad1 = { OptLoad1, "OptLoad1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad2 = { OptLoad2, "OptLoad2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptLoad3 = { OptLoad3, "OptLoad3", 0, 0, 0, 0, 0, 0 }; +static OptFunc DOptLoadStoreLoad= { OptLoadStoreLoad,"OptLoadStoreLoad", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptLongAssign = { OptLongAssign, "OptLongAssign", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptLongCopy = { OptLongCopy, "OptLongCopy", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX1 = { OptNegAX1, "OptNegAX1", 165, 0, 0, 0, 0, 0 }; static OptFunc DOptNegAX2 = { OptNegAX2, "OptNegAX2", 200, 0, 0, 0, 0, 0 }; static OptFunc DOptPrecalc = { OptPrecalc, "OptPrecalc", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad1 = { OptPtrLoad1, "OptPtrLoad1", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad2 = { OptPtrLoad2, "OptPtrLoad2", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad3 = { OptPtrLoad3, "OptPtrLoad3", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad4 = { OptPtrLoad4, "OptPtrLoad4", 100, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad5 = { OptPtrLoad5, "OptPtrLoad5", 50, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 60, 0, 0, 0, 0, 0 }; -static OptFunc DOptPtrLoad7 = { OptPtrLoad7, "OptPtrLoad7", 140, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad11 = { OptPtrLoad11, "OptPtrLoad11", 92, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad12 = { OptPtrLoad12, "OptPtrLoad12", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad13 = { OptPtrLoad13, "OptPtrLoad13", 65, 0, 0, 0, 0, 0 }; @@ -173,6 +170,12 @@ static OptFunc DOptPtrLoad16 = { OptPtrLoad16, "OptPtrLoad16", 100, 0, static OptFunc DOptPtrLoad17 = { OptPtrLoad17, "OptPtrLoad17", 190, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad18 = { OptPtrLoad18, "OptPtrLoad18", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrLoad19 = { OptPtrLoad19, "OptPtrLoad19", 65, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad2 = { OptPtrLoad2, "OptPtrLoad2", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad3 = { OptPtrLoad3, "OptPtrLoad3", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad4 = { OptPtrLoad4, "OptPtrLoad4", 100, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad5 = { OptPtrLoad5, "OptPtrLoad5", 50, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 60, 0, 0, 0, 0, 0 }; +static OptFunc DOptPtrLoad7 = { OptPtrLoad7, "OptPtrLoad7", 140, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore3 = { OptPtrStore3, "OptPtrStore3", 100, 0, 0, 0, 0, 0 }; @@ -202,7 +205,6 @@ static OptFunc DOptStore3 = { OptStore3, "OptStore3", 120, 0, static OptFunc DOptStore4 = { OptStore4, "OptStore4", 50, 0, 0, 0, 0, 0 }; static OptFunc DOptStore5 = { OptStore5, "OptStore5", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0, 0 }; -static OptFunc DOptLoadStoreLoad= { OptLoadStoreLoad,"OptLoadStoreLoad", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 }; static OptFunc DOptSub3 = { OptSub3, "OptSub3", 100, 0, 0, 0, 0, 0 }; @@ -214,10 +216,13 @@ static OptFunc DOptTransfers3 = { OptTransfers3, "OptTransfers3", 65, 0, static OptFunc DOptTransfers4 = { OptTransfers4, "OptTransfers4", 65, 0, 0, 0, 0, 0 }; static OptFunc DOptUnusedLoads = { OptUnusedLoads, "OptUnusedLoads", 0, 0, 0, 0, 0, 0 }; static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0, 0 }; +/* END DECL SORTED_CODEOPT.SH */ /* Table containing all the steps in alphabetical order */ +/* CAUTION: table must be sorted for bsearch */ static OptFunc* OptFuncs[] = { +/* BEGIN SORTED_CODEOPT.SH */ &DOpt65C02BitOps, &DOpt65C02Ind, &DOpt65C02Stores, @@ -268,6 +273,7 @@ static OptFunc* OptFuncs[] = { &DOptLoad1, &DOptLoad2, &DOptLoad3, + &DOptLoadStoreLoad, &DOptLongAssign, &DOptLongCopy, &DOptNegAX1, @@ -318,7 +324,6 @@ static OptFunc* OptFuncs[] = { &DOptStore4, &DOptStore5, &DOptStoreLoad, - &DOptLoadStoreLoad, &DOptSub1, &DOptSub2, &DOptSub3, @@ -330,6 +335,7 @@ static OptFunc* OptFuncs[] = { &DOptTransfers4, &DOptUnusedLoads, &DOptUnusedStores, +/* END SORTED_CODEOPT.SH */ }; #define OPTFUNC_COUNT (sizeof(OptFuncs) / sizeof(OptFuncs[0])) diff --git a/src/cc65/codeoptutil.c b/src/cc65/codeoptutil.c index 43b1dee22..7547ef5ba 100644 --- a/src/cc65/codeoptutil.c +++ b/src/cc65/codeoptutil.c @@ -1225,6 +1225,12 @@ static int CmpHarmless (const void* Key, const void* Entry) } +/* CAUTION: table must be sorted for bsearch */ +static const char* const Tab[] = { +/* BEGIN SORTED.SH */ + "_abs", +/* END SORTED.SH */ +}; int HarmlessCall (const CodeEntry* E, int PushedBytes) /* Check if this is a call to a harmless subroutine that will not interrupt @@ -1252,10 +1258,6 @@ int HarmlessCall (const CodeEntry* E, int PushedBytes) } return 1; } else { - static const char* const Tab[] = { - "_abs", - }; - void* R = bsearch (E->Arg, Tab, sizeof (Tab) / sizeof (Tab[0]), diff --git a/src/cc65/compile.c b/src/cc65/compile.c index e08a829e6..9083891aa 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -496,6 +496,14 @@ void Compile (const char* FileName) while (PreprocessNextLine ()) { /* Nothing */ } + /* Output macros if requested by the user */ + if (DumpPredefMacros) { + OutputPredefMacros (); + } + if (DumpUserMacros) { + OutputUserMacros (); + } + /* Close the output file */ CloseOutputFile (); diff --git a/src/cc65/coptstop.c b/src/cc65/coptstop.c index 402f16b97..e5d686d1a 100644 --- a/src/cc65/coptstop.c +++ b/src/cc65/coptstop.c @@ -1464,7 +1464,9 @@ static unsigned Opt_a_tosxor (StackOpData* D) /* The first column of these two tables must be sorted in lexical order */ +/* CAUTION: table must be sorted for bsearch */ static const OptFuncDesc FuncTable[] = { +/* BEGIN SORTED.SH */ { "___bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN }, { "staspidx", Opt_staspidx, REG_NONE, OP_NONE }, { "staxspidx", Opt_staxspidx, REG_AX, OP_NONE }, @@ -1485,9 +1487,12 @@ static const OptFuncDesc FuncTable[] = { { "tosuleax", Opt_tosuleax, REG_NONE, OP_RHS_REMOVE_DIRECT | OP_RHS_LOAD_DIRECT }, { "tosultax", Opt_tosultax, REG_NONE, OP_RHS_REMOVE_DIRECT | OP_RHS_LOAD_DIRECT }, { "tosxorax", Opt_tosxorax, REG_NONE, OP_NONE }, +/* END SORTED.SH */ }; +/* CAUTION: table must be sorted for bsearch */ static const OptFuncDesc FuncRegATable[] = { +/* BEGIN SORTED.SH */ { "tosandax", Opt_a_tosand, REG_NONE, OP_RHS_REMOVE_DIRECT | OP_RHS_LOAD_DIRECT }, { "toseqax", Opt_a_toseq, REG_NONE, OP_NONE }, { "tosgeax", Opt_a_tosuge, REG_NONE, OP_NONE }, @@ -1503,6 +1508,7 @@ static const OptFuncDesc FuncRegATable[] = { { "tosuleax", Opt_a_tosule, REG_NONE, OP_NONE }, { "tosultax", Opt_a_tosult, REG_NONE, OP_NONE }, { "tosxorax", Opt_a_tosxor, REG_NONE, OP_RHS_REMOVE_DIRECT | OP_RHS_LOAD_DIRECT }, +/* END SORTED.SH */ }; #define FUNC_COUNT(Table) (sizeof(Table) / sizeof(Table[0])) diff --git a/src/cc65/error.c b/src/cc65/error.c index db0debf8c..ae2d6f27d 100644 --- a/src/cc65/error.c +++ b/src/cc65/error.c @@ -39,6 +39,7 @@ /* common */ #include "coll.h" +#include "debugflag.h" #include "print.h" #include "strbuf.h" @@ -183,11 +184,15 @@ static unsigned GetDiagnosticLineNum (void) -void Fatal (const char* Format, ...) +void Fatal_ (const char *file, int line, const char* Format, ...) /* Print a message about a fatal error and die */ { va_list ap; + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + fprintf (stderr, "%s:%u: Fatal: ", GetDiagnosticFileName (), GetDiagnosticLineNum ()); va_start (ap, Format); @@ -203,11 +208,15 @@ void Fatal (const char* Format, ...) -void Internal (const char* Format, ...) +void Internal_ (const char *file, int line, const char* Format, ...) /* Print a message about an internal compiler error and die */ { va_list ap; + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + fprintf (stderr, "%s:%u: Internal compiler error:\n", GetDiagnosticFileName (), GetDiagnosticLineNum ()); @@ -270,10 +279,15 @@ static void IntError (errcat_t EC, LineInfo* LI, const char* Msg, va_list ap) -void LIError (errcat_t EC, LineInfo* LI, const char* Format, ...) +void LIError_ (const char *file, int line, errcat_t EC, LineInfo* LI, const char* Format, ...) /* Print an error message with the line info given explicitly */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntError (EC, LI, Format, ap); va_end (ap); @@ -281,10 +295,15 @@ void LIError (errcat_t EC, LineInfo* LI, const char* Format, ...) -void Error (const char* Format, ...) +void Error_ (const char *file, int line, const char* Format, ...) /* Print an error message */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntError (EC_PARSER, GetDiagnosticLI (), Format, ap); va_end (ap); @@ -292,10 +311,15 @@ void Error (const char* Format, ...) -void PPError (const char* Format, ...) +void PPError_ (const char *file, int line, const char* Format, ...) /* Print an error message. For use within the preprocessor */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntError (EC_PP, GetCurLineInfo (), Format, ap); va_end (ap); @@ -346,10 +370,15 @@ static void IntWarning (errcat_t EC, LineInfo* LI, const char* Msg, va_list ap) -void LIWarning (errcat_t EC, LineInfo* LI, const char* Format, ...) +void LIWarning_ (const char *file, int line, errcat_t EC, LineInfo* LI, const char* Format, ...) /* Print a warning message with the line info given explicitly */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntWarning (EC, LI, Format, ap); va_end (ap); @@ -357,10 +386,15 @@ void LIWarning (errcat_t EC, LineInfo* LI, const char* Format, ...) -void Warning (const char* Format, ...) +void Warning_ (const char *file, int line, const char* Format, ...) /* Print a warning message */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntWarning (EC_PARSER, GetDiagnosticLI (), Format, ap); va_end (ap); @@ -368,10 +402,15 @@ void Warning (const char* Format, ...) -void PPWarning (const char* Format, ...) +void PPWarning_ (const char *file, int line, const char* Format, ...) /* Print a warning message. For use within the preprocessor */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntWarning (EC_PP, GetCurLineInfo (), Format, ap); va_end (ap); @@ -436,10 +475,15 @@ static void IntNote (const LineInfo* LI, const char* Msg, va_list ap) -void LINote (const LineInfo* LI, const char* Format, ...) +void LINote_ (const char *file, int line, const LineInfo* LI, const char* Format, ...) /* Print a note message with the line info given explicitly */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntNote (LI, Format, ap); va_end (ap); @@ -447,10 +491,15 @@ void LINote (const LineInfo* LI, const char* Format, ...) -void Note (const char* Format, ...) +void Note_ (const char *file, int line, const char* Format, ...) /* Print a note message */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntNote (GetDiagnosticLI (), Format, ap); va_end (ap); @@ -458,10 +507,15 @@ void Note (const char* Format, ...) -void PPNote (const char* Format, ...) +void PPNote_ (const char *file, int line, const char* Format, ...) /* Print a note message. For use within the preprocessor */ { va_list ap; + + if (Debug) { + fprintf(stderr, "[%s:%d] ", file, line); + } + va_start (ap, Format); IntNote (GetDiagnosticLI (), Format, ap); va_end (ap); diff --git a/src/cc65/error.h b/src/cc65/error.h index b3cdc49ab..0a18d51a4 100644 --- a/src/cc65/error.h +++ b/src/cc65/error.h @@ -103,28 +103,36 @@ struct StrBuf; void PrintFileInclusionInfo (const LineInfo* LI); /* Print hierarchy of file inclusion */ -void Fatal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2))); +void Fatal_ (const char *file, int line, const char* Format, ...) attribute ((noreturn, format (printf, 3, 4))); +#define Fatal(...) Fatal_(__FILE__, __LINE__, __VA_ARGS__) /* Print a message about a fatal error and die */ -void Internal (const char* Format, ...) attribute ((noreturn, format (printf, 1, 2))); +void Internal_ (const char *file, int line, const char* Format, ...) attribute ((noreturn, format (printf, 3, 4))); +#define Internal(...) Internal_(__FILE__, __LINE__, __VA_ARGS__) /* Print a message about an internal compiler error and die */ -void Error (const char* Format, ...) attribute ((format (printf, 1, 2))); +void Error_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define Error(...) Error_(__FILE__, __LINE__, __VA_ARGS__) /* Print an error message */ -void LIError (errcat_t EC, LineInfo* LI, const char* Format, ...) attribute ((format (printf, 3, 4))); +void LIError_ (const char *file, int line, errcat_t EC, LineInfo* LI, const char* Format, ...) attribute ((format (printf, 5, 6))); +#define LIError(...) LIError_(__FILE__, __LINE__, __VA_ARGS__) /* Print an error message with the line info given explicitly */ -void PPError (const char* Format, ...) attribute ((format (printf, 1, 2))); +void PPError_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define PPError(...) PPError_(__FILE__, __LINE__, __VA_ARGS__) /* Print an error message. For use within the preprocessor */ -void Warning (const char* Format, ...) attribute ((format (printf, 1, 2))); +void Warning_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define Warning(...) Warning_(__FILE__, __LINE__, __VA_ARGS__) /* Print a warning message */ -void LIWarning (errcat_t EC, LineInfo* LI, const char* Format, ...) attribute ((format (printf, 3, 4))); +void LIWarning_ (const char *file, int line, errcat_t EC, LineInfo* LI, const char* Format, ...) attribute ((format (printf, 5, 6))); +#define LIWarning(...) LIWarning_(__FILE__, __LINE__, __VA_ARGS__) /* Print a warning message with the line info given explicitly */ -void PPWarning (const char* Format, ...) attribute ((format (printf, 1, 2))); +void PPWarning_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define PPWarning(...) PPWarning_(__FILE__, __LINE__, __VA_ARGS__) /* Print a warning message. For use within the preprocessor */ void UnreachableCodeWarning (void); @@ -140,13 +148,16 @@ IntStack* FindWarning (const char* Name); void ListWarnings (FILE* F); /* Print a list of warning types/names to the given file */ -void Note (const char* Format, ...) attribute ((format (printf, 1, 2))); +void Note_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define Note(...) Note_(__FILE__, __LINE__, __VA_ARGS__) /* Print a note message */ -void LINote (const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 2, 3))); +void LINote_ (const char *file, int line, const LineInfo* LI, const char* Format, ...) attribute ((format (printf, 4, 5))); +#define LINote(...) LINote_(__FILE__, __LINE__, __VA_ARGS__) /* Print a note message with the line info given explicitly */ -void PPNote (const char* Format, ...) attribute ((format (printf, 1, 2))); +void PPNote_ (const char *file, int line, const char* Format, ...) attribute ((format (printf, 3, 4))); +#define PPNote(...) PPNote_(__FILE__, __LINE__, __VA_ARGS__) /* Print a note message. For use within the preprocessor */ unsigned GetTotalErrors (void); diff --git a/src/cc65/global.c b/src/cc65/global.c index b2c3ef0a0..64278df77 100644 --- a/src/cc65/global.c +++ b/src/cc65/global.c @@ -44,12 +44,14 @@ unsigned char AddSource = 0; /* Add source lines as comments */ +unsigned char AllowNewComments = 0; /* Allow new style comments in C89 mode */ unsigned char AutoCDecl = 0; /* Make functions default to __cdecl__ */ unsigned char DebugInfo = 0; /* Add debug info to the obj */ +unsigned char DumpPredefMacros = 0; /* Output predefined macros */ +unsigned char DumpUserMacros = 0; /* Output user macros */ unsigned char PreprocessOnly = 0; /* Just preprocess the input */ unsigned char DebugOptOutput = 0; /* Output debug stuff */ unsigned RegisterSpace = 6; /* Space available for register vars */ -unsigned AllowNewComments = 0; /* Allow new style comments in C89 mode */ /* Stackable options */ IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */ diff --git a/src/cc65/global.h b/src/cc65/global.h index ba7105130..c781f6de4 100644 --- a/src/cc65/global.h +++ b/src/cc65/global.h @@ -52,12 +52,14 @@ /* Options */ extern unsigned char AddSource; /* Add source lines as comments */ +extern unsigned char AllowNewComments; /* Allow new style comments in C89 mode */ extern unsigned char AutoCDecl; /* Make functions default to __cdecl__ */ extern unsigned char DebugInfo; /* Add debug info to the obj */ +extern unsigned char DumpPredefMacros; /* Output predefined macros */ +extern unsigned char DumpUserMacros; /* Output user macros */ extern unsigned char PreprocessOnly; /* Just preprocess the input */ extern unsigned char DebugOptOutput; /* Output debug stuff */ extern unsigned RegisterSpace; /* Space available for register vars */ -extern unsigned AllowNewComments; /* Allow new style comments in C89 mode */ /* Stackable options */ extern IntStack WritableStrings; /* Literal strings are r/w */ diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c index 3bfae0811..2817403c1 100644 --- a/src/cc65/macrotab.c +++ b/src/cc65/macrotab.c @@ -1,4 +1,4 @@ -/*****************************************************************************/ + /* */ /* macrotab.h */ /* */ @@ -42,6 +42,7 @@ /* cc65 */ #include "error.h" +#include "output.h" #include "preproc.h" #include "macrotab.h" @@ -60,6 +61,70 @@ static Macro* MacroTab[MACRO_TAB_SIZE]; /* The undefined macros list head */ static Macro* UndefinedMacrosListHead; +/* Some defines for better readability when calling OutputMacros() */ +#define USER_MACROS 0 +#define PREDEF_MACROS 1 +#define NAME_ONLY 0 +#define FULL_DEFINITION 1 + + + +/*****************************************************************************/ +/* helpers */ +/*****************************************************************************/ + + + +static void OutputMacro (const Macro* M, int Full) +/* Output one macro. If Full is true, the replacement is also output. */ +{ + WriteOutput ("#define %s", M->Name); + int ParamCount = M->ParamCount; + if (M->ParamCount >= 0) { + int I; + if (M->Variadic) { + CHECK (ParamCount > 0); + --ParamCount; + } + WriteOutput ("("); + for (I = 0; I < ParamCount; ++I) { + const char* Name = CollConstAt (&M->Params, I); + WriteOutput ("%s%s", (I == 0)? "" : ",", Name); + } + if (M->Variadic) { + WriteOutput ("%s...", (ParamCount == 0)? "" : ","); + } + WriteOutput (")"); + } + WriteOutput (" "); + if (Full) { + WriteOutput ("%.*s", + SB_GetLen (&M->Replacement), + SB_GetConstBuf (&M->Replacement)); + } + WriteOutput ("\n"); +} + + + +static void OutputMacros (int Predefined, int Full) +/* Output macros to the output file depending on the flags given. */ +{ + /* Note: The Full flag is currently not used by any callers but is left in + ** place for possible future changes. + */ + unsigned I; + for (I = 0; I < MACRO_TAB_SIZE; ++I) { + const Macro* M = MacroTab [I]; + while (M) { + if ((Predefined != 0) == (M->Predefined != 0)) { + OutputMacro (M, Full); + } + M = M->Next; + } + } +} + /*****************************************************************************/ @@ -68,7 +133,7 @@ static Macro* UndefinedMacrosListHead; -Macro* NewMacro (const char* Name) +Macro* NewMacro (const char* Name, unsigned char Predefined) /* Allocate a macro structure with the given name. The structure is not ** inserted into the macro table. */ @@ -84,6 +149,7 @@ Macro* NewMacro (const char* Name) M->ParamCount = -1; /* Flag: Not a function-like macro */ InitCollection (&M->Params); SB_Init (&M->Replacement); + M->Predefined = Predefined; M->Variadic = 0; memcpy (M->Name, Name, Len+1); @@ -116,7 +182,7 @@ Macro* CloneMacro (const Macro* M) ** Use FreeMacro for that. */ { - Macro* New = NewMacro (M->Name); + Macro* New = NewMacro (M->Name, M->Predefined); unsigned I; for (I = 0; I < CollCount (&M->Params); ++I) { @@ -134,7 +200,7 @@ Macro* CloneMacro (const Macro* M) void DefineNumericMacro (const char* Name, long Val) -/* Define a macro for a numeric constant */ +/* Define a predefined macro for a numeric constant */ { char Buf[64]; @@ -148,10 +214,10 @@ void DefineNumericMacro (const char* Name, long Val) void DefineTextMacro (const char* Name, const char* Val) -/* Define a macro for a textual constant */ +/* Define a predefined macro for a textual constant */ { /* Create a new macro */ - Macro* M = NewMacro (Name); + Macro* M = NewMacro (Name, 1); /* Set the value as replacement text */ SB_CopyStr (&M->Replacement, Val); @@ -350,3 +416,19 @@ void PrintMacroStats (FILE* F) } } } + + + +void OutputPredefMacros (void) +/* Output all predefined macros to the output file */ +{ + OutputMacros (PREDEF_MACROS, FULL_DEFINITION); +} + + + +void OutputUserMacros (void) +/* Output all user defined macros to the output file */ +{ + OutputMacros (USER_MACROS, FULL_DEFINITION); +} diff --git a/src/cc65/macrotab.h b/src/cc65/macrotab.h index 52b812b2f..00fb1d55a 100644 --- a/src/cc65/macrotab.h +++ b/src/cc65/macrotab.h @@ -58,6 +58,7 @@ struct Macro { int ParamCount; /* Number of parameters, -1 = no parens */ Collection Params; /* Parameter list (char*) */ StrBuf Replacement; /* Replacement text */ + unsigned char Predefined; /* True if this is a predefined macro */ unsigned char Variadic; /* C99 variadic macro */ char Name[1]; /* Name, dynamically allocated */ }; @@ -70,7 +71,7 @@ struct Macro { -Macro* NewMacro (const char* Name); +Macro* NewMacro (const char* Name, unsigned char Predefined); /* Allocate a macro structure with the given name. The structure is not ** inserted into the macro table. */ @@ -87,10 +88,10 @@ Macro* CloneMacro (const Macro* M); */ void DefineNumericMacro (const char* Name, long Val); -/* Define a macro for a numeric constant */ +/* Define a predefined macro for a numeric constant */ void DefineTextMacro (const char* Name, const char* Val); -/* Define a macro for a textual constant */ +/* Define a predefined macro for a textual constant */ void InsertMacro (Macro* M); /* Insert the given macro into the macro table. */ @@ -132,6 +133,12 @@ int MacroCmp (const Macro* M1, const Macro* M2); void PrintMacroStats (FILE* F); /* Print macro statistics to the given text file. */ +void OutputPredefMacros (void); +/* Output all predefined macros to the output file */ + +void OutputUserMacros (void); +/* Output all user defined macros to the output file */ + /* End of macrotab.h */ diff --git a/src/cc65/main.c b/src/cc65/main.c index 47435757c..5b951dc56 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -93,6 +93,8 @@ static void Usage (void) " -V\t\t\t\tPrint the compiler version number\n" " -W [-+]warning[,...]\t\tControl warnings ('-' disables, '+' enables)\n" " -d\t\t\t\tDebug mode\n" + " -dM\t\t\t\tOutput all user macros (needs -E)\n" + " -dP\t\t\t\tOutput all predefined macros (needs -E)\n" " -g\t\t\t\tAdd debug info to object file\n" " -h\t\t\t\tHelp (this text)\n" " -j\t\t\t\tDefault characters are signed\n" @@ -307,6 +309,10 @@ static void SetSys (const char* Sys) DefineNumericMacro ("__RP6502__", 1); break; + case TGT_AGAT: + DefineNumericMacro ("__AGAT__", 1); + break; + default: AbEnd ("Unknown target system '%s'", Sys); } @@ -317,6 +323,81 @@ static void SetSys (const char* Sys) +static void DefineCpuMacros (void) +/* Define macros for the target CPU */ +{ + const char* CPUName; + + /* Note: The list of CPUs handled here must match the one checked in + ** OptCPU(). + */ + switch (CPU) { + + /* The following ones are legal CPUs as far as the assembler is + ** concerned but are ruled out earlier in the compiler, so this + ** function should never see them. + */ + case CPU_NONE: + case CPU_SWEET16: + case CPU_M740: + case CPU_4510: + case CPU_UNKNOWN: + CPUName = (CPU == CPU_UNKNOWN)? "unknown" : CPUNames[CPU]; + Internal ("Invalid CPU \"%s\"", CPUName); + break; + + case CPU_6502: + DefineNumericMacro ("__CPU_6502__", 1); + break; + + case CPU_6502X: + DefineNumericMacro ("__CPU_6502X__", 1); + break; + + case CPU_6502DTV: + DefineNumericMacro ("__CPU_6502DTV__", 1); + break; + + case CPU_65SC02: + DefineNumericMacro ("__CPU_65SC02__", 1); + break; + + case CPU_65C02: + DefineNumericMacro ("__CPU_65C02__", 1); + break; + + case CPU_65816: + DefineNumericMacro ("__CPU_65816__", 1); + break; + + case CPU_HUC6280: + DefineNumericMacro ("__CPU_HUC6280__", 1); + break; + + default: + FAIL ("Unexpected value in switch"); + break; + } + + /* Define the macros for instruction sets. We only include the ones for + ** the available CPUs. + */ + DefineNumericMacro ("__CPU_ISET_6502__", CPU_ISET_6502); + DefineNumericMacro ("__CPU_ISET_6502X__", CPU_ISET_6502X); + DefineNumericMacro ("__CPU_ISET_6502DTV__", CPU_ISET_6502DTV); + DefineNumericMacro ("__CPU_ISET_65SC02__", CPU_ISET_65SC02); + DefineNumericMacro ("__CPU_ISET_65C02__", CPU_ISET_65C02); + DefineNumericMacro ("__CPU_ISET_65816__", CPU_ISET_65816); + DefineNumericMacro ("__CPU_ISET_HUC6280__", CPU_ISET_HUC6280); + + /* Now define the macro that contains the bit set with the available + ** cpu instructions. + */ + DefineNumericMacro ("__CPU__", CPUIsets[CPU]); +} + + + static void FileNameOption (const char* Opt, const char* Arg, StrBuf* Name) /* Handle an option that remembers a file name for later */ { @@ -477,7 +558,9 @@ static void OptCreateFullDep (const char* Opt attribute ((unused)), static void OptCPU (const char* Opt, const char* Arg) /* Handle the --cpu option */ { - /* Find the CPU from the given name */ + /* Find the CPU from the given name. We do only accept a certain number + ** of CPUs. If the list is changed, be sure to adjust SetCpuMacros(). + */ CPU = FindCPU (Arg); if (CPU != CPU_6502 && CPU != CPU_6502X && CPU != CPU_65SC02 && CPU != CPU_65C02 && CPU != CPU_65816 && CPU != CPU_HUC6280 && @@ -945,7 +1028,25 @@ int main (int argc, char* argv[]) break; case 'd': - OptDebug (Arg, 0); + P = Arg + 2; + if (*P == '\0') { + OptDebug (Arg, 0); + } else { + while (*P) { + switch (*P) { + case 'M': + DumpUserMacros = 1; + break; + case 'P': + DumpPredefMacros = 1; + break; + default: + UnknownOption (Arg); + break; + } + ++P; + } + } break; case 'h': @@ -1057,13 +1158,20 @@ int main (int argc, char* argv[]) AbEnd ("No input files"); } + /* The options to output macros can only be used with -E */ + if ((DumpPredefMacros || DumpUserMacros) && !PreprocessOnly) { + AbEnd ("Preprocessor macro output can only be used together with -E"); + } + /* Add the default include search paths. */ FinishIncludePaths (); /* Create the output file name if it was not explicitly given */ MakeDefaultOutputName (InputFile); - /* If no CPU given, use the default CPU for the target */ + /* If no CPU given, use the default CPU for the target. Define macros that + ** allow to query the CPU. + */ if (CPU == CPU_UNKNOWN) { if (Target != TGT_UNKNOWN) { CPU = GetTargetProperties (Target)->DefaultCPU; @@ -1071,6 +1179,7 @@ int main (int argc, char* argv[]) CPU = CPU_6502; } } + DefineCpuMacros (); /* If no memory model was given, use the default */ if (MemoryModel == MMODEL_UNKNOWN) { diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index aeea0297b..49363769e 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -55,9 +55,12 @@ /* Opcode description table */ +/* CAUTION: table must be sorted by mnemonic for bsearch */ const OPCDesc OPCTable[OP65_COUNT] = { /* 65XX opcodes */ + +/* BEGIN SORTED_OPCODES.SH */ { OP65_ADC, /* opcode */ "adc", /* mnemonic */ 0, /* size */ @@ -586,6 +589,7 @@ const OPCDesc OPCTable[OP65_COUNT] = { REG_Y, /* use */ REG_A | PSTATE_ZN /* chg */ }, +/* END SORTED_OPCODES.SH */ }; diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index ee71b42d8..49754fbe8 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -89,10 +89,12 @@ typedef enum { } pragma_t; /* Pragma table */ +/* CAUTION: table must be sorted for bsearch */ static const struct Pragma { const char* Key; /* Keyword */ pragma_t Tok; /* Token */ } Pragmas[] = { +/* BEGIN SORTED.SH */ { "align", PRAGMA_ALIGN }, { "allow-eager-inline", PRAGMA_ALLOW_EAGER_INLINE }, { "allow_eager_inline", PRAGMA_ALLOW_EAGER_INLINE }, @@ -127,6 +129,7 @@ static const struct Pragma { { "writable-strings", PRAGMA_WRITABLE_STRINGS }, { "writable_strings", PRAGMA_WRITABLE_STRINGS }, { "zpsym", PRAGMA_ZPSYM }, +/* END SORTED.SH */ }; #define PRAGMA_COUNT (sizeof (Pragmas) / sizeof (Pragmas[0])) @@ -433,12 +436,7 @@ static void ApplySegNamePragma (pragma_t Token, int PushPop, const char* Name, u SetSegAddrSize (Name, AddrSize); } - /* BSS variables are output at the end of the compilation. Don't - ** bother to change their segment, now. - */ - if (Seg != SEG_BSS) { - g_segname (Seg); - } + g_segname (Seg); } diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 5cdec3142..65db5ea57 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -216,10 +216,12 @@ typedef enum { /* Preprocessor directive tokens mapping table */ +/* CAUTION: table must be sorted for bsearch */ static const struct PPDType { const char* Tok; /* Token */ ppdirective_t Type; /* Type */ } PPDTypes[] = { +/* BEGIN SORTED.SH */ { "define", PPD_DEFINE }, { "elif", PPD_ELIF }, { "else", PPD_ELSE }, @@ -233,6 +235,7 @@ static const struct PPDType { { "pragma", PPD_PRAGMA }, { "undef", PPD_UNDEF }, { "warning", PPD_WARNING }, +/* END SORTED.SH */ }; /* Number of preprocessor directive types */ @@ -2572,7 +2575,7 @@ static void DoDefine (void) CheckForBadIdent (Ident, Std, 0); /* Create a new macro definition */ - M = NewMacro (Ident); + M = NewMacro (Ident, 0); /* Check if this is a function-like macro */ if (CurC == '(') { diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index f0ff664fd..dda857f07 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -87,11 +87,13 @@ enum { }; /* Token table */ +/* CAUTION: table must be sorted for bsearch */ static const struct Keyword { char* Key; /* Keyword name */ unsigned char Tok; /* The token */ unsigned char Std; /* Token supported in which standards? */ } Keywords [] = { +/* BEGIN SORTED.SH */ { "_Pragma", TOK_PRAGMA, TT_C89 | TT_C99 | TT_CC65 }, /* !! */ { "_Static_assert", TOK_STATIC_ASSERT, TT_CC65 }, /* C11 */ { "__AX__", TOK_AX, TT_C89 | TT_C99 | TT_CC65 }, @@ -145,6 +147,7 @@ static const struct Keyword { { "void", TOK_VOID, TT_C89 | TT_C99 | TT_CC65 }, { "volatile", TOK_VOLATILE, TT_C89 | TT_C99 | TT_CC65 }, { "while", TOK_WHILE, TT_C89 | TT_C99 | TT_CC65 }, +/* END SORTED.SH */ }; #define KEY_COUNT (sizeof (Keywords) / sizeof (Keywords [0])) diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 2889a176e..3f33cdcce 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -78,19 +78,20 @@ static void StdFunc_strlen (FuncDesc*, ExprDesc*); -/* Table with all known functions and their handlers. Must be sorted -** alphabetically! +/* Table with all known functions and their handlers. +** CAUTION: table must be alphabetically sorted for bsearch */ static struct StdFuncDesc { const char* Name; void (*Handler) (FuncDesc*, ExprDesc*); } StdFuncs[] = { +/* BEGIN SORTED.SH */ { "memcpy", StdFunc_memcpy }, { "memset", StdFunc_memset }, { "strcmp", StdFunc_strcmp }, { "strcpy", StdFunc_strcpy }, { "strlen", StdFunc_strlen }, - +/* END SORTED.SH */ }; #define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs[0])) diff --git a/src/cl65/main.c b/src/cl65/main.c index 42126e6d7..528e64e56 100644 --- a/src/cl65/main.c +++ b/src/cl65/main.c @@ -122,6 +122,11 @@ static int DoAssemble = 1; /* The name of the output file, NULL if none given */ static const char* OutputName = 0; +/* The path part of the output file, NULL if none given +** or the OutputName is just a filename with no path +** information. */ +static char *OutputDirectory = 0; + /* The name of the linker configuration file if given */ static const char* LinkerConfig = 0; @@ -555,7 +560,7 @@ static void AssembleFile (const char* File, const char* TmpFile, unsigned ArgCou if (TmpFile) { ObjName = MakeFilename (TmpFile, ".o"); } else { - ObjName = MakeTmpFilename (".o"); + ObjName = MakeTmpFilename (OutputDirectory, File, ".o"); } CmdSetOutput (&CA65, ObjName); CmdAddFile (&LD65, ObjName); @@ -684,7 +689,7 @@ static void Compile (const char* File) if (DoAssemble) { /* set a temporary output file name */ - TmpFile = MakeTmpFilename(".s"); + TmpFile = MakeTmpFilename(OutputDirectory, File, ".s"); CmdSetOutput (&CC65, TmpFile); } @@ -729,7 +734,7 @@ static void CompileRes (const char* File) ** BEFORE adding the file */ if (DoAssemble && DoLink) { - AsmName = MakeTmpFilename(".s"); + AsmName = MakeTmpFilename(OutputDirectory, File, ".s"); CmdSetAsmOutput(&GRC, AsmName); } @@ -1623,6 +1628,7 @@ int main (int argc, char* argv []) case 'o': /* Name the output file */ OutputName = GetArg (&I, 2); + OutputDirectory = GetFileDirectory(OutputName); break; case 'r': @@ -1713,6 +1719,9 @@ int main (int argc, char* argv []) } RemoveTempFiles (); + if (OutputDirectory != NULL) { + xfree(OutputDirectory); + } /* Return an apropriate exit code */ return EXIT_SUCCESS; diff --git a/src/common/filetype.c b/src/common/filetype.c index ae8b636dc..074f8800a 100644 --- a/src/common/filetype.c +++ b/src/common/filetype.c @@ -48,8 +48,10 @@ +/* CAUTION: table must be sorted for bsearch */ static const FileId TypeTable[] = { /* Upper case stuff for obsolete operating systems */ +/* BEGIN SORTED.SH */ { "A", FILETYPE_LIB }, { "A65", FILETYPE_ASM }, { "ASM", FILETYPE_ASM }, @@ -65,7 +67,6 @@ static const FileId TypeTable[] = { { "S", FILETYPE_ASM }, { "SER", FILETYPE_O65 }, { "TGI", FILETYPE_O65 }, - { "a", FILETYPE_LIB }, { "a65", FILETYPE_ASM }, { "asm", FILETYPE_ASM }, @@ -81,6 +82,7 @@ static const FileId TypeTable[] = { { "s", FILETYPE_ASM }, { "ser", FILETYPE_O65 }, { "tgi", FILETYPE_O65 }, +/* END SORTED.SH */ }; #define FILETYPE_COUNT (sizeof (TypeTable) / sizeof (TypeTable[0])) diff --git a/src/common/fname.c b/src/common/fname.c index e67470b33..10d38f38a 100644 --- a/src/common/fname.c +++ b/src/common/fname.c @@ -33,8 +33,17 @@ +#include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <time.h> + +#if defined(_MSC_VER) +# include <process.h> +#else +# include <unistd.h> +#endif #include "xmalloc.h" #include "fname.h" @@ -93,7 +102,28 @@ const char* FindName (const char* Path) return Path + Len; } +char *GetFileDirectory (const char* File) +/* Return a copy of the path part of a File, or NULL if there is none. */ +{ + char *Out, *P; + if (File == NULL) { + return NULL; + } + + Out = xmalloc (strlen (File) + 1); + strcpy(Out, File); + + P = (char *)FindName (Out); + if (P == Out) { + /* This is a simple filename. */ + xfree (Out); + return NULL; + } + *P = '\0'; + + return Out; +} char* MakeFilename (const char* Origin, const char* Ext) /* Make a new file name from Origin and Ext. If Origin has an extension, it @@ -119,35 +149,29 @@ char* MakeFilename (const char* Origin, const char* Ext) -char* MakeTmpFilename (const char* Ext) -/* Make a new temporary file name from Ext. tmpnam(3) is called -** and Ext is appended to generate the filename. +char* MakeTmpFilename (const char *Directory, const char *Origin, const char* Ext) +/* Make a new temporary file name from Origin and Ext. ** The result is placed in a malloc'ed buffer and returned. */ { char* Out; - char Buffer[L_tmpnam * 2]; /* a lazy way to ensure we have space for Ext */ + size_t Len = 0; + static unsigned int Counter = 0; - /* - ** gcc emits the following warning here: - ** - ** warning: the use of `tmpnam' is dangerous, better use `mkstemp' - ** - ** however, mkstemp actually opens a file, which we do not want. - ** tmpfile() is unsuitable for the same reason. - ** - ** we could write our own version, but then we would have to struggle - ** with supporting multiple build environments. - ** - ** tmpnam(3) is safe here, because ca65 / cc65 / ld65 will simply clobber - ** an existing file, or exit if with an error if they are unable to. - ** - ** gcc will also complain, if you don't use the return value from tmpnam(3) - */ - strcat(tmpnam(Buffer), Ext); + /* Allocate enough for the directory, ... */ + if (Directory != NULL) { + Len = strlen (Directory); + } - Out = xmalloc (strlen (Buffer) + 1); - strcpy (Out, Buffer); + /* ... plus the the original name, the maximum length of the PID, the + * maximum length of the counter, the extension, and the terminator. + */ + Len += strlen (Origin) + (strlen (".2147483648") * 2) + strlen (Ext) + 1; + Out = xmalloc (Len); + + snprintf (Out, Len, "%s%s.%u.%u%s", (Directory != NULL ? Directory : ""), + FindName(Origin), getpid(), Counter, Ext); + Counter++; return Out; } diff --git a/src/common/fname.h b/src/common/fname.h index 852c4ae56..ede34152d 100644 --- a/src/common/fname.h +++ b/src/common/fname.h @@ -52,6 +52,9 @@ const char* FindName (const char* Path); ** the file, the function returns Path as name. */ +char *GetFileDirectory (const char* File); +/* Return a copy of the path part of a File, or NULL if there is none. */ + char* MakeFilename (const char* Origin, const char* Ext); /* Make a new file name from Origin and Ext. If Origin has an extension, it ** is removed and Ext is appended. If Origin has no extension, Ext is simply @@ -59,9 +62,10 @@ char* MakeFilename (const char* Origin, const char* Ext); ** The function may be used to create "foo.o" from "foo.s". */ -char* MakeTmpFilename (const char* Ext); -/* Make a new temporary file name from Ext. tmpnam(3) is called -** and Ext is appended to generate the filename. +char* MakeTmpFilename (const char *Directory, const char *Origin, const char* Ext); +/* Make a new temporary file name from Directory, Origin, and Ext. +** A temporary path is generated from the Directory, +** the Origin filename, the compiler's PID and the Extension. ** The result is placed in a malloc'ed buffer and returned. */ diff --git a/src/common/target.c b/src/common/target.c index b50478e16..1544c215b 100644 --- a/src/common/target.c +++ b/src/common/target.c @@ -129,7 +129,25 @@ static const unsigned char CTPET[256] = { 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, }; - +/* Translation table KOI8-R -> Agat-9 */ +static unsigned char CTAgat[256] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0xA0, + 0x1B,0x5C,0x10,0x12,0x1D,0x1F,0x13,0x1C,0x11,0x1E,0x14,0xA0,0x02,0x5F,0xA0,0xA0, + 0xA0,0xA0,0xA0,0xA0,0xA0,0x9E,0x04,0xA0,0x3C,0x3E,0xA0,0xA0,0x30,0x32,0xA0,0x2F, + 0xA0,0xA0,0xA0,0x0F,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0, + 0xA0,0xA0,0xA0,0x9F,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0xA0, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, +}; /* One entry in the target map */ typedef struct TargetEntry TargetEntry; @@ -138,10 +156,13 @@ struct TargetEntry { target_t Id; /* Target ID */ }; -/* Table that maps target names to IDs. Sorted alphabetically for bsearch(). +/* Table that maps target names to IDs. ** Allows multiple entries for one target ID (target name aliases). +** CAUTION: must be alphabetically for bsearch(). */ static const TargetEntry TargetMap[] = { +/* BEGIN SORTED.SH */ + { "agat", TGT_AGAT }, { "apple2", TGT_APPLE2 }, { "apple2enh", TGT_APPLE2ENH }, { "atari", TGT_ATARI }, @@ -180,6 +201,7 @@ static const TargetEntry TargetMap[] = { { "sym1", TGT_SYM1 }, { "telestrat", TGT_TELESTRAT }, { "vic20", TGT_VIC20 }, +/* END SORTED.SH */ }; #define MAP_ENTRY_COUNT (sizeof (TargetMap) / sizeof (TargetMap[0])) @@ -223,6 +245,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = { { "sym1", CPU_6502, BINFMT_BINARY, CTNone }, { "kim1", CPU_6502, BINFMT_BINARY, CTNone }, { "rp6502", CPU_65C02, BINFMT_BINARY, CTNone }, + { "agat", CPU_6502, BINFMT_BINARY, CTAgat }, }; /* Target system */ diff --git a/src/common/target.h b/src/common/target.h index 730b8211e..d6c9fc35b 100644 --- a/src/common/target.h +++ b/src/common/target.h @@ -89,6 +89,7 @@ typedef enum { TGT_SYM1, TGT_KIM1, TGT_RP6502, + TGT_AGAT, TGT_COUNT /* Number of target systems */ } target_t; diff --git a/src/dbginfo/dbginfo.c b/src/dbginfo/dbginfo.c index 1f693e513..896043cb6 100644 --- a/src/dbginfo/dbginfo.c +++ b/src/dbginfo/dbginfo.c @@ -2523,6 +2523,7 @@ static void NextChar (InputData* D) +/* CAUTION: table must be sorted for bsearch */ static void NextToken (InputData* D) /* Read the next token from the input stream */ { @@ -2530,6 +2531,7 @@ static void NextToken (InputData* D) const char Keyword[12]; Token Tok; } KeywordTable[] = { +/* BEGIN SORTED.SH */ { "abs", TOK_ABSOLUTE }, { "addrsize", TOK_ADDRSIZE }, { "auto", TOK_AUTO }, @@ -2578,6 +2580,7 @@ static void NextToken (InputData* D) { "var", TOK_VAR }, { "version", TOK_VERSION }, { "zp", TOK_ZEROPAGE }, +/* END SORTED.SH */ }; diff --git a/src/sp65/convert.c b/src/sp65/convert.c index a9047ffb0..3ffdbab7d 100644 --- a/src/sp65/convert.c +++ b/src/sp65/convert.c @@ -61,14 +61,17 @@ struct ConverterMapEntry { StrBuf* (*ConvertFunc) (const Bitmap*, const Collection*); }; -/* Converter table, alphabetically sorted */ +/* Converter table */ +/* CAUTION: table must be alphabetically sorted for bsearch */ static const ConverterMapEntry ConverterMap[] = { +/* BEGIN SORTED.SH */ { "geos-bitmap", GenGeosBitmap }, { "geos-icon", GenGeosIcon }, { "koala", GenKoala }, { "lynx-sprite", GenLynxSprite }, { "raw", GenRaw }, { "vic2-sprite", GenVic2Sprite }, +/* END SORTED.SH */ }; diff --git a/src/sp65/input.c b/src/sp65/input.c index f1df247ae..ac3aeaf99 100644 --- a/src/sp65/input.c +++ b/src/sp65/input.c @@ -69,12 +69,14 @@ static InputFormatDesc InputFormatTable[ifCount] = { { ReadPCXFile }, }; -/* Table that maps extensions to input formats. Must be sorted alphabetically */ +/* Table that maps extensions to input formats. */ +/* CAUTION: table must be alphabetically sorted for bsearch */ static const FileId FormatTable[] = { /* Upper case stuff for obsolete operating systems */ +/* BEGIN SORTED.SH */ { "PCX", ifPCX }, - { "pcx", ifPCX }, +/* END SORTED.SH */ }; diff --git a/src/sp65/output.c b/src/sp65/output.c index c12d1f612..0c8fa59a7 100644 --- a/src/sp65/output.c +++ b/src/sp65/output.c @@ -78,22 +78,24 @@ static OutputFormatDesc OutputFormatTable[ofCount] = { { WriteCFile }, }; -/* Table that maps extensions to Output formats. Must be sorted alphabetically */ +/* Table that maps extensions to Output formats. */ +/* CAUTION: table must be alphabetically sorted for bsearch */ static const FileId FormatTable[] = { /* Upper case stuff for obsolete operating systems */ +/* BEGIN SORTED.SH */ { "A", ofAsm }, { "ASM", ofAsm }, { "BIN", ofBin }, { "C", ofC }, { "INC", ofAsm }, { "S", ofAsm }, - { "a", ofAsm }, { "asm", ofAsm }, { "bin", ofBin }, { "c", ofC }, { "inc", ofAsm }, { "s", ofAsm }, +/* END SORTED.SH */ }; diff --git a/src/sp65/palconv.c b/src/sp65/palconv.c index e92f3c22e..42adb1b33 100644 --- a/src/sp65/palconv.c +++ b/src/sp65/palconv.c @@ -56,9 +56,12 @@ struct PaletteMapEntry { StrBuf* (*PaletteFunc) (const Bitmap*, const Collection*); }; -/* Converter table, alphabetically sorted */ +/* Converter table */ +/* CAUTION: table must be alphabetically sorted for bsearch */ static const PaletteMapEntry PaletteMap[] = { +/* BEGIN SORTED.SH */ { "lynx-palette", GenLynxPalette }, +/* END SORTED.SH */ }; diff --git a/test/asm/cpudetect/6502x-cpudetect.ref b/test/asm/cpudetect/6502x-cpudetect.ref index 3434ecbea..9e7abe573 100644 Binary files a/test/asm/cpudetect/6502x-cpudetect.ref and b/test/asm/cpudetect/6502x-cpudetect.ref differ diff --git a/test/asm/cpudetect/cpudetect.s b/test/asm/cpudetect/cpudetect.s index 7b2363b7f..6ee07ae3c 100644 --- a/test/asm/cpudetect/cpudetect.s +++ b/test/asm/cpudetect/cpudetect.s @@ -8,6 +8,10 @@ lda #$ea .endif +.ifp02x + lax #$ea +.endif + .ifpsc02 jmp ($1234,x) .endif @@ -72,3 +76,13 @@ .byte 0,"CPU_ISET_6502DTV" .endif + +; step 3: switch through all supported cpus to verify the pseudo-op is there + +.p02 +.p02X +.psc02 +.pc02 +.p816 +.p4510 +.pdtv diff --git a/test/standard/null.c b/test/standard/null.c new file mode 100644 index 000000000..cd4bd0a44 --- /dev/null +++ b/test/standard/null.c @@ -0,0 +1,162 @@ + + +/* test headers which should define NULL */ + +#include <locale.h> +#ifndef NULL +#error "NULL should be defined in locale.h" +#endif +#undef NULL + +#include <stdlib.h> +#ifndef NULL +#error "NULL should be defined in stdlib.h" +#endif +#undef NULL + +#include <string.h> +#ifndef NULL +#error "NULL should be defined in string.h" +#endif +#undef NULL + +#include <stddef.h> +#ifndef NULL +#error "NULL should be defined in stddef.h" +#endif +#undef NULL + +#include <stdio.h> +#ifndef NULL +#error "NULL should be defined in stdio.h" +#endif +#undef NULL + +#include <time.h> +#ifndef NULL +#error "NULL should be defined in time.h" +#endif +#undef NULL + +/* does not exist in cc65 (yet) +#include <wchar.h> +#ifndef NULL +#error "NULL should be defined in wchar.h" +#endif */ +#undef NULL + + +/* test headers which should NOT define NULL */ + +#include <assert.h> +#ifdef NULL +#error "NULL should NOT be defined in assert.h" +#undef NULL +#endif + +/* does not exist in cc65 (yet) +#include <complex.h> +#ifdef NULL +#error "NULL should NOT be defined in complex.h" +#undef NULL +#endif */ + +#include <ctype.h> +#ifdef NULL +#error "NULL should NOT be defined in ctype.h" +#undef NULL +#endif + +#include <errno.h> +#ifdef NULL +#error "NULL should NOT be defined in errno.h" +#undef NULL +#endif + +/* does not exist in cc65 (yet) +#include <fenv.h> +#ifdef NULL +#error "NULL should NOT be defined in fenv.h" +#undef NULL +#endif */ + +/* does not exist in cc65 (yet) +#include <float.h> +#ifdef NULL +#error "NULL should NOT be defined in float.h" +#undef NULL +#endif */ + +#include <inttypes.h> +#ifdef NULL +#error "NULL should NOT be defined in inttypes.h" +#undef NULL +#endif + +#include <iso646.h> +#ifdef NULL +#error "NULL should NOT be defined in iso646.h" +#undef NULL +#endif + +#include <limits.h> +#ifdef NULL +#error "NULL should NOT be defined in limits.h" +#undef NULL +#endif + +/* does not exist in cc65 (yet) +#include <math.h> +#ifdef NULL +#error "NULL should NOT be defined in math.h" +#undef NULL +#endif */ + +#include <setjmp.h> +#ifdef NULL +#error "NULL should NOT be defined in setjmp.h" +#undef NULL +#endif + +#include <signal.h> +#ifdef NULL +#error "NULL should NOT be defined in signal.h" +#undef NULL +#endif + +#include <stdarg.h> +#ifdef NULL +#error "NULL should NOT be defined in stdarg.h" +#undef NULL +#endif + +#include <stdbool.h> +#ifdef NULL +#error "NULL should NOT be defined in stdbool.h" +#undef NULL +#endif + +#include <stdint.h> +#ifdef NULL +#error "NULL should NOT be defined in stdint.h" +#undef NULL +#endif + +/* does not exist in cc65 (yet) +#include <tgmath.h> +#ifdef NULL +#error "NULL should NOT be defined in tgmath.h" +#undef NULL +#endif */ + +/* does not exist in cc65 (yet) +#include <wctype.h> +#ifdef NULL +#error "NULL should NOT be defined in wctype.h" +#undef NULL +#endif */ + +int main(void) +{ + return 0; +} diff --git a/test/todo/bug2172_invalid_code.c b/test/todo/bug2172_invalid_code.c new file mode 100644 index 000000000..74522c029 --- /dev/null +++ b/test/todo/bug2172_invalid_code.c @@ -0,0 +1,56 @@ + +// bug #2172 - Invalid code generated for switch statement + +#include <stdlib.h> +#include <stdio.h> + +// cc65 -o bug2172.s -Cl -Oirs -T -t c64 bug2172.c +int func(int expr) +{ + switch (expr) { + int i; + case 0: + i = 17; + return i; + default: + i = 16; + return i; + } +} + +int err = 0; + +int main(void) +{ + int i = 0; + int n = 42; + for (i = -3; i < 0; i++) { + n = func(i); + if ((i < -3) || (i >= 0)) { + goto stackerr; + } + printf("i:%d expect:16 got:%d\n", i, n); + if (n != 16) { + err++; + } + } + n = func(0); + printf("i:%d expect:17 got:%d\n", 0, n); + if (n != 17) { + err++; + } + for (i = 1; i < 4; i++) { + n = func(i); + if ((i < 1) || (i >= 4)) { + goto stackerr; + } + printf("i:%d expect:16 got:%d\n", i, n); + if (n != 16) { + err++; + } + } + return err; +stackerr: + fputs("stack messed up?\n", stdout); + return -1; +} diff --git a/test/todo/bug2172b_invalid_code.c b/test/todo/bug2172b_invalid_code.c new file mode 100644 index 000000000..13d983123 --- /dev/null +++ b/test/todo/bug2172b_invalid_code.c @@ -0,0 +1,51 @@ + +#include <stdlib.h> +#include <stdio.h> + +/* Just some arbitrary code, more fun with goto */ +int func(int m) +{ + long x = -42; /* sp: -4 */ + switch (x) { + /* return 0; // C99 only */ + int i = 42; /* sp: -6 */ +L0: + --i; +default: + if (i != 0) { + long j = 13; /* sp: -10 */ + goto L1; +L1: +case 0x7FFF01: + m--; +case 0x7EFF0001: +case 0x7FFF0001: + i++; + } /* sp: -6 */ +case 0x7FFF00: +case 0x7FFF0000: + break; + goto L0; + { + int skipped = 42; /* sp: -8 */ +case 0x7EFF00: +case 0x7EFF0000: + ++skipped; + } /* sp: -6 */ + } /* sp: -4 */ + + return m; +} + +int err = 0; + +int main(void) +{ + int n = 42; + n = func(7); + if (n != 7) { + err++; + } + printf("n:%d\n", n); + return err; +} diff --git a/test/val/bug2151.c b/test/val/bug2151.c index 25f145506..1277961ef 100644 --- a/test/val/bug2151.c +++ b/test/val/bug2151.c @@ -47,10 +47,11 @@ _Pragma _Pragma ( #pragma bss-name("BSS") { extern int y; -#pragma bss-name("BSS2") +#pragma bss-name("BSS") // used to be BSS2, but fix for #2608 means + // that now causes ld65 to fail, so we use BSS instead static #pragma zpsym ("y") - int x; // TODO: currently in "BSS", but supposed to be in "BSS2"? + int x; x = 0; if (memcmp(str, "aBC", 3)) diff --git a/test/val/bug2608.c b/test/val/bug2608.c new file mode 100644 index 000000000..c0685d28c --- /dev/null +++ b/test/val/bug2608.c @@ -0,0 +1,40 @@ + +/* bug #2608: "zp_bss" is placed in BSS and NOT placed in ZEROPAGE as expected. */ + +#include <stdlib.h> +#include <stdio.h> + +int err = 0; + +int is_zeropage(void *p) +{ + if (/*(p >= ((void*)0)) &&*/ + (p <= ((void*)0xff))) { + return 1; + } + return 0; +} + +void foo(void) { +#pragma bss-name(push,"ZEROPAGE") +#pragma data-name(push,"ZEROPAGE") + static int zp_data = 5; + static char zp_bss; +#pragma bss-name(pop) +#pragma data-name(pop) + printf("zp_data at 0x%04x (%szp)\n", &zp_data, is_zeropage(&zp_data) ? "" : "NOT "); + printf("zp_bss at 0x%04x (%szp)\n", &zp_bss, is_zeropage(&zp_bss) ? "" : "NOT "); + if (!is_zeropage(&zp_data)) { + err++; + } + if (!is_zeropage(&zp_bss)) { + err++; + } +} + +int main(void) +{ + foo(); + printf("errors: %d\n", err); + return err; +}