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
+
+,
+
+
+
+An overview over the Agat-7 and Agat-9 and theirs interfaces to the cc65 C
+compiler.
+
+
+
+
+
+
+
+Overview
+
+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).
+
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.
+
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.
+
+Binary format
+
+The standard binary file format generated by the linker for the Agat target is
+an AppleSingle file to be compatible with AppleCommander .
+The default load address is $1903.
+
+
+
+Platform-specific header files
+
+Programs containing Agat-specific code may use the Usefull info
+
+Emulation
+
+
+- Oleg Odintsov's Agat Emulator -
+- MAME -
+
+
+Links
+
+- Most informative source on Agat (in russian) -
+- Wikipedia -
+- Controversial article on Agat from
.
+The author reviewed custom-build mockup Agat bearing little relation to even the early Agat systems.
+
+
+
+License
+
+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:
+
+- 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.
+
- Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
- This notice may not be removed or altered from any source
+ distribution.
+
+
+
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.
- LC address: $D000, LC size: $3000
+ LC address: $D000, LC size: $2FFC
For plain vanilla DOS 3.3 which doesn't make use of the Language Card at all.
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.
- LC address: $D000, LC size: $3000
+ LC address: $D000, LC size: $2FFC
For plain vanilla DOS 3.3 which doesn't make use of the Language Card at all.
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: , command).
+.IFP02X
+
+ Conditional assembly: Check if the assembler is currently in 6502X mode
+ (see command).
+
+
.IFP4510
Conditional assembly: Check if the assembler is currently in 4510 mode
@@ -3621,6 +3627,16 @@ See: ,
+.P02X
+
+ Enable the 6502X instruction set, disable 65SC02, 65C02 and 65816
+ instructions.
+
+ See: , , and
+
+
+
.P4510
Enable the 4510 instruction set. This is a superset of the 65C02 and
@@ -4016,11 +4032,13 @@ See: , ,
,
+ ,
,
,
,
,
,
+ ,
,
,
,
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.
+
+
+ -dM
+
+ When used with -E, will output #define 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 / by using
+
+ -dP
+
+ When used with -E, will output #define directives for all the macros
+ defined by the compiler itself. This does not include any user defined macros.
+
+ Note: Can be combined with / by using
+ --debug-tables name
Writes symbol table information to a file, which includes details on structs, unions
@@ -1154,6 +1178,96 @@ The compiler defines several macros at startup:
+
+ __CPU__
+
+ 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).
+
+
+ #if (__CPU__ & __CPU_ISET_65SC02__)
+
+
+ This is much simpler and more future proof than checking for specific CPUs.
+
+ The compiler defines a set of constants named /
+ command line option.
+
+ __CPU_6502__
+
+ This macro is defined if the code is compiled for a 6502 CPU.
+
+ __CPU_6502X__
+
+ This macro is defined if the code is compiled for a 6502 CPU with invalid
+ opcodes.
+
+ __CPU_6502DTV__
+
+ This macro is defined if the code is compiled for a DTV CPU.
+
+ __CPU_65SC02__
+
+ This macro is defined if the code is compiled for a 65SC02 CPU.
+
+ __CPU_65C02__
+
+ This macro is defined if the code is compiled for a 65C02 CPU.
+
+ __CPU_65816__
+
+ This macro is defined if the code is compiled for a 65816 CPU.
+
+ __CPU_HUC6280__
+
+ This macro is defined if the code is compiled for a HUC6280 CPU.
+
+ __CPU_ISET_6502__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 6502 CPU.
+
+ __CPU_ISET_6502X__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 6502X CPU.
+
+ __CPU_ISET_6502DTV__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 6502DTV CPU.
+
+ __CPU_ISET_65SC02__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 65SC02 CPU.
+
+ __CPU_ISET_65C02__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 65C02 CPU.
+
+ __CPU_ISET_65816__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the 65816 CPU.
+
+ __CPU_ISET_HUC6280__
+
+ This macro expands to a numeric constant that can be used to check the
+ / macro for the instruction set
+ of the HUC6280 CPU.
+
__CX16__
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 @@
+
+ Topics specific to the Agat machines.
+
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
Graphics drivers
-No graphics drivers are currently available for the Plus/4.
+
+
+ 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
Extended memory drivers
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
#elif defined(__APPLE2__)
# include
+#elif defined(__AGAT__)
+# include
#elif defined(__ATARI__)
# include
#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
+ 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
+ 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_LENGTH, ID11_OFFSET, ID11_LENGTH, __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
+ sta ROM_RST
+ stx ROM_RST+1
+
+ lda #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
+ lda #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
+ 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
+ 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
+ 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=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
#include
#include
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
#include
#include
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
#include
+#include
#include
+#include
+
+#if defined(_MSC_VER)
+# include
+#else
+# include
+#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
+#ifndef NULL
+#error "NULL should be defined in locale.h"
+#endif
+#undef NULL
+
+#include
+#ifndef NULL
+#error "NULL should be defined in stdlib.h"
+#endif
+#undef NULL
+
+#include
+#ifndef NULL
+#error "NULL should be defined in string.h"
+#endif
+#undef NULL
+
+#include
+#ifndef NULL
+#error "NULL should be defined in stddef.h"
+#endif
+#undef NULL
+
+#include
+#ifndef NULL
+#error "NULL should be defined in stdio.h"
+#endif
+#undef NULL
+
+#include
+#ifndef NULL
+#error "NULL should be defined in time.h"
+#endif
+#undef NULL
+
+/* does not exist in cc65 (yet)
+#include
+#ifndef NULL
+#error "NULL should be defined in wchar.h"
+#endif */
+#undef NULL
+
+
+/* test headers which should NOT define NULL */
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in assert.h"
+#undef NULL
+#endif
+
+/* does not exist in cc65 (yet)
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in complex.h"
+#undef NULL
+#endif */
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in ctype.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in errno.h"
+#undef NULL
+#endif
+
+/* does not exist in cc65 (yet)
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in fenv.h"
+#undef NULL
+#endif */
+
+/* does not exist in cc65 (yet)
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in float.h"
+#undef NULL
+#endif */
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in inttypes.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in iso646.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in limits.h"
+#undef NULL
+#endif
+
+/* does not exist in cc65 (yet)
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in math.h"
+#undef NULL
+#endif */
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in setjmp.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in signal.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in stdarg.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in stdbool.h"
+#undef NULL
+#endif
+
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in stdint.h"
+#undef NULL
+#endif
+
+/* does not exist in cc65 (yet)
+#include
+#ifdef NULL
+#error "NULL should NOT be defined in tgmath.h"
+#undef NULL
+#endif */
+
+/* does not exist in cc65 (yet)
+#include
+#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
+#include
+
+// 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
+#include
+
+/* 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
+#include
+
+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;
+}