diff --git a/.github/checks/sorted.sh b/.github/checks/sorted.sh
index 0a4a90db7..4f53b0484 100755
--- a/.github/checks/sorted.sh
+++ b/.github/checks/sorted.sh
@@ -13,8 +13,8 @@ function checkarray_quoted_name
START="\\/\\* BEGIN SORTED.SH \\*\\/"
END="\\/\\* END SORTED.SH \\*\\/"
- awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {print count,"##",$0}' "$CHECK_FILE" | \
- sed -e 's:\(.*\) ##.*\"\(.*\)\".*:\1##\2:g' > .a.tmp
+ 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"
diff --git a/.github/checks/sorted_codeopt.sh b/.github/checks/sorted_codeopt.sh
index e90e32b4a..c78662b9d 100755
--- a/.github/checks/sorted_codeopt.sh
+++ b/.github/checks/sorted_codeopt.sh
@@ -13,7 +13,7 @@ function checkarray
START="\\/\\* BEGIN DECL SORTED_CODEOPT.SH \\*\\/"
END="\\/\\* END DECL SORTED_CODEOPT.SH \\*\\/"
- awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {print count,"##",$0}' "$CHECK_FILE" | \
+ 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
@@ -33,7 +33,7 @@ function checkarray
START="\\/\\* BEGIN SORTED_CODEOPT.SH \\*\\/"
END="\\/\\* END SORTED_CODEOPT.SH \\*\\/"
- awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {print count,"##",$0}' "$CHECK_FILE" | \
+ 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
diff --git a/.github/checks/sorted_opcodes.sh b/.github/checks/sorted_opcodes.sh
index b18b841c8..3e45ea752 100755
--- a/.github/checks/sorted_opcodes.sh
+++ b/.github/checks/sorted_opcodes.sh
@@ -13,10 +13,10 @@ function checkarray_quoted_name
START="\\/\\* BEGIN SORTED_OPCODES.SH \\*\\/"
END="\\/\\* END SORTED_OPCODES.SH \\*\\/"
- awk '/'"$START"'/{flag=1; count++; next} /'"$END"'/{flag=0;} flag {print count,"##",$0}' "$CHECK_FILE" | \
+ 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
+ sed -e 's:\(.*\)##.*\"\(.*\)\".*:\1##\2:g' > .a.tmp
if [[ -z $(grep '[^[:space:]]' .a.tmp) ]] ; then
echo "error: "$1" table is empty"
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/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/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 ba4355f9f..8452d9102 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 55b84ed5c..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
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/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/libsrc/apple2/crt0.s b/libsrc/apple2/crt0.s
index 005ed6466..47ac70a7e 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 85bdcac8e..a8a5b8e63 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 c_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 c_sp
stx c_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 295b6883d..d9bda45d4 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -99,6 +99,7 @@ DISK_apple2 = samples.dsk
DISK_apple2enh = samples.dsk
DISK_atari = samples.atr
DISK_atarixl = samples.atr
+DISK_plus4 = samples.d64
# --------------------------------------------------------------------------
# System-dependent settings
@@ -146,6 +147,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
@@ -326,9 +329,11 @@ EXELIST_plus4 = \
enumdevdir \
gunzip65 \
hello \
+ mandelbrot \
terminal \
tinyshell \
- sieve
+ sieve \
+ tgidemo
EXELIST_sim6502 = \
checkversion \
@@ -451,7 +456,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/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/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/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 94c84d897..157702897 100644
--- a/src/ca65/scanner.c
+++ b/src/ca65/scanner.c
@@ -221,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 },
@@ -259,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 },
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/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/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 53b106abd..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"
@@ -1026,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':
@@ -1138,6 +1158,11 @@ 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 ();
diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c
index 96fa565f2..65db5ea57 100644
--- a/src/cc65/preproc.c
+++ b/src/cc65/preproc.c
@@ -2575,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/common/fname.c b/src/common/fname.c
index 7c52869e2..10d38f38a 100644
--- a/src/common/fname.c
+++ b/src/common/fname.c
@@ -169,7 +169,7 @@ char* MakeTmpFilename (const char *Directory, const char *Origin, const char* Ex
Len += strlen (Origin) + (strlen (".2147483648") * 2) + strlen (Ext) + 1;
Out = xmalloc (Len);
- snprintf (Out, Len, "%s%s.%u%u%s", (Directory != NULL ? Directory : ""),
+ snprintf (Out, Len, "%s%s.%u.%u%s", (Directory != NULL ? Directory : ""),
FindName(Origin), getpid(), Counter, Ext);
Counter++;
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;
+}