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. + +

-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; +}