language:
- c
install:
+ - sudo apt-get update
- sudo apt-get install linuxdoc-tools linuxdoc-tools-info binutils-mingw-w64-i686 gcc-mingw-w64-i686 sshpass
script:
- make bin USER_CFLAGS=-Werror
- make lib QUIET=1
+ - make -C test
- make -C src clean
- make bin USER_CFLAGS=-Werror CROSS_COMPILE=i686-w64-mingw32-
- make doc zip
-This is the original cc65 compiler copyright:
-
- -*- Mode: Text -*-
-
- This is the copyright notice for RA65, LINK65, LIBR65, and other
- Atari 8-bit programs. Said programs are Copyright 1989, by John R.
- Dunning. All rights reserved, with the following exceptions:
-
- Anyone may copy or redistribute these programs, provided that:
-
- 1: You don't charge anything for the copy. It is permissable to
- charge a nominal fee for media, etc.
-
- 2: All source code and documentation for the programs is made
- available as part of the distribution.
-
- 3: This copyright notice is preserved verbatim, and included in
- the distribution.
-
- You are allowed to modify these programs, and redistribute the
- modified versions, provided that the modifications are clearly noted.
-
- There is NO WARRANTY with this software, it comes as is, and is
- distributed in the hope that it may be useful.
-
- This copyright notice applies to any program which contains
- this text, or the refers to this file.
-
- This copyright notice is based on the one published by the Free
- Software Foundation, sometimes known as the GNU project. The idea
- is the same as theirs, ie the software is free, and is intended to
- stay that way. Everybody has the right to copy, modify, and re-
- distribute this software. Nobody has the right to prevent anyone
- else from copying, modifying or redistributing it.
-
-In acknowledgment of this copyright, I (Ullrich von Bassewitz) will place
-my own changes to the compiler under the same copyright.
-
-The library and the binary utils are a complete rewrite done by me and
-covered by the following license:
-
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
SF_USER = oliverschmidt
SF_HOST = frs.sourceforge.net
-SF_FILE = /home/frs/project/cc65/cc65-snapshot-win64.zip
+SF_FILE = /home/frs/project/cc65/cc65-snapshot-win32.zip
SCPFLAGS = -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -q
-[documentation](http://cc65.github.io/doc)
+[Windows Snapshot](http://sourceforge.net/projects/cc65/files/cc65-snapshot-win32.zip)
-[wiki](http://github.com/cc65/wiki/wiki)
+[Documentation](http://cc65.github.io/doc)
-[![build status](http://travis-ci.org/cc65/cc65.png)](http://travis-ci.org/cc65/cc65/builds)
+[Wiki](http://github.com/cc65/wiki/wiki)
+
+[![Build Status](https://api.travis-ci.org/cc65/cc65.svg?branch=master)](https://travis-ci.org/cc65/cc65/builds)
cc65 is a complete cross development package for 65(C)02 systems, including
a powerful macro assembler, a C compiler, linker, librarian and several
- CBM 510 (aka P500)
- the 600/700 family
- newer PET machines (not 2001).
-- the Apple ][+ and successors.
+- the Apple ]\[+ and successors.
- the Atari 8 bit machines.
- the Atari 5200 console.
- GEOS for the C64, C128 and Apple //e.
+- the NEC PC-Engine (aka TurboGrafx-16).
- the Nintendo Entertainment System (NES) console.
-- the Supervision console.
+- the Watara Supervision console.
- the Oric Atmos.
- the Lynx console.
+- the Ohio Scientific Challenger 1P.
The libraries are fairly portable, so creating a version for other 6502s
shouldn't be too much work.
; ---------------------------------------------------------------------------
; Zero page, Commodore stuff
+VARTAB := $2D ; Pointer to start of BASIC variables
+MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $7A ; Pointer into BASIC source code
TIME := $A0 ; 60 HZ clock
FNAM_LEN := $B7 ; Length of filename
CURS_X := $D3 ; Cursor column
CURS_Y := $D6 ; Cursor row
CRAM_PTR := $F3 ; Pointer to current char in color RAM
+FREKZP := $FB ; Five unused bytes
BASIC_BUF := $200 ; Location of command-line
BASIC_BUF_LEN = 89 ; Maximum length of command-line
TP_FAST = $80 ; Switch Rossmoeller TurboProcess to fast mode
RAMONLY = $F8 ; (~(LORAM | HIRAM | IOEN)) & $FF
-
--- /dev/null
+;
+; PCE definitions. By Groepaz/Hitmem.
+;
+
+; FIXME: screen dimensions my change according to selected video mode
+screenrows = (224/8)
+charsperline = 61
+
+CH_HLINE = 1
+CH_VLINE = 2
+
+; huc6270 - Video Display Controller (VDC)
+
+VDC_MAWR = 0 ; Memory Address Write Register
+VDC_MARR = 1 ; Memory Address Read Register
+VDC_VWR = 2 ; VRAM Write Register (write only)
+VDC_VRR = 2 ; VRAM Read Register (read only)
+VDC_UNK03 = 3 ; (unknown)
+VDC_UNK04 = 4 ; (unknown)
+VDC_CR = 5 ; Control Register
+VDC_RCR = 6 ; Raster Counter Register
+VDC_BXR = 7 ; Background X-Scroll Register
+VDC_BYR = 8 ; Background Y-Scroll Register
+VDC_MWR = 9 ; Memory-access Width Register
+VDC_HSR = 10 ; Horizontal Sync Register
+VDC_HDR = 11 ; Horizontal Display Register
+VDC_VPR = 12 ; Vertical synchronous register
+VDC_VDW = 13 ; Vertical display register
+VDC_VCR = 14 ; Vertical display END position register
+VDC_DCR = 15 ; (DMA) Control Register
+VDC_SOUR = 16 ; (DMA) Source Register
+VDC_DESR = 17 ; (DMA) Destination Register
+VDC_LENR = 18 ; (DMA) Length Register
+VDC_SATB = 19 ; Sprite Attribute Table
+
+; VDC port
+; Note: absolute addressing mode must be used when writing to this port
+
+VDC_CTRL = $0000
+VDC_DATA_LO = $0002
+VDC_DATA_HI = $0003
+
+; huc6260 - Video Color Encoder (vce)
+
+; The DAC has a palette of 512 colours.
+; bitmap of the palette data is this: 0000000gggrrrbbb.
+; You can read and write the DAC-registers.
+
+VCE = $0400 ; base
+
+VCE_CTRL = $0400 ; write$00 to reset
+VCE_ADDR_LO = $0402 ; LSB of byte offset into palette
+VCE_ADDR_HI = $0403 ; MSB of byte offset into palette
+VCE_DATA_LO = $0404 ; LSB of 16-bit palette data
+VCE_DATA_HI = $0405 ; MSB of 16-bit palette data
+
+; programmable sound generator (PSG)
+
+PSG = $0800 ; base
+
+PSG_CHAN_SELECT = $0800
+PSG_GLOBAL_PAN = $0801
+PSG_FREQ_LO = $0802
+PSG_FREQ_HI = $0803
+PSG_CHAN_CTRL = $0804
+PSG_CHAN_PAN = $0805
+PSG_CHAN_DATA = $0806
+PSG_NOISE = $0807
+PSG_LFO_FREQ = $0808
+PSG_LFO_CTRL = $0809
+
+; timer
+
+TIMER = $0c00 ; base
+
+TIMER_COUNT = $0c00
+TIMER_CTRL = $0c01
+
+JOY_CTRL = $1000
+
+IRQ_MASK = $1402
+IRQ_STATUS = $1403
+
+CDR_MEM_DISABLE = $1803
+CDR_MEM_ENABLE = $1807
+
+; Write VDC register
+.macro VREG arg1,arg2
+ st0 #arg1
+ st1 #<(arg2)
+ st2 #>(arg2)
+.endmacro
; ---------------------------------------------------------------------------
; Zero page, Commodore stuff
+VARTAB := $2A ; Pointer to start of BASIC variables
MEMSIZE := $34 ; Size of memory installed
TXTPTR := $77 ; Pointer into BASIC source code
TIME := $8D ; 60HZ clock
; Zero page, Commodore stuff
TMPPTR := $22 ; Temporary ptr used by BASIC
+VARTAB := $2D ; Pointer to start of BASIC variables
+MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $3B ; Pointer into BASIC source code
TIME := $A3 ; 60HZ clock
FNAM_LEN := $AB ; Length of filename
; ---------------------------------------------------------------------------
; Zero page, Commodore stuff
+VARTAB := $2D ; Pointer to start of BASIC variables
+MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
TXTPTR := $7A ; Pointer into BASIC source code
TIME := $A0 ; 60HZ clock
FNAM_LEN := $B7 ; Length of filename
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
__LCSIZE__: type = weak, value = $0C00; # Rest of bank two
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
__LCSIZE__: type = weak, value = $0C00; # Rest of bank two
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
__LCSIZE__: type = weak, value = $0C00; # Rest of bank two
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
__LCSIZE__: type = weak, value = $0C00; # Rest of bank two
__STACKSIZE__: type = weak, value = $0800; # 2k stack
__LOADADDR__: type = weak, value = __STARTUP_RUN__;
- __LOADSIZE__: type = weak, value = __ZPSAVE_RUN__ - __STARTUP_RUN__ +
+ __LOADSIZE__: type = weak, value = __INITBSS_RUN__ - __STARTUP_RUN__ +
__MOVE_LAST__ - __MOVE_START__;
}
MEMORY {
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ INITBSS: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes;
INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
LC: load = MOVE, run = LC, type = ro, optional = yes;
CODE: load = ROM, type = ro, define = yes;
RODATA: load = ROM, type = ro, optional = yes;
DATA: load = ROM, run = RAM, type = rw, define = yes, optional = yes;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes, optional = yes;
CARTHDR: load = CARTID, type = ro;
ZEROPAGE: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro, optional = yes;
DATA: load = RAM, type = rw, optional = yes;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes, optional = yes;
ZEROPAGE: load = ZP, type = zp, optional = yes;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
CODE: load = RAM, type = ro, define = yes;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss, optional = yes;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = zp, optional = yes;
SYMBOLS {
- __STACKSIZE__: type = weak, value = $0800; # 2k stack
+ __TAPEHDR__: type = import;
+ __BASHDR__: type = import;
+ __PROGFLAG__: type = weak, value = $00; # $00=BASIC, $80=machine code
+ __AUTORUN__: type = weak, value = $00; # $00=only load, $C7=run
+ __STACKSIZE__: type = weak, value = $0800; # 2K stack
+ __GRAB__: type = weak, value = 0; # 0=don't grab graphics RAM, 1=grab graphics RAM
+ __RAMEND__: type = weak, value = $9800 + $1C00 * __GRAB__;
}
MEMORY {
ZP: file = "", define = yes, start = $00E2, size = $001A;
- TAPEHDR: file = %O, type = ro, start = $0000, size = $0011;
- RAM: file = %O, define = yes, start = $0500, size = $9300 - __STACKSIZE__;
+ TAPEHDR: file = %O, type = ro, start = $0000, size = $001F;
+ BASHEAD: file = %O, define = yes, start = $0501, size = $000D;
+ RAM: file = %O, define = yes, start = __BASHEAD_LAST__, size = __RAMEND__ - __RAM_START__ - __STACKSIZE__;
}
SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
TAPEHDR: load = TAPEHDR, type = ro;
+ BASHDR: load = BASHEAD, type = ro, define = yes, optional = yes;
STARTUP: load = RAM, type = ro;
LOWCODE: load = RAM, type = ro, optional = yes;
- INIT: load = RAM, type = ro, define = yes, optional = yes;
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
+ INIT: load = RAM, type = ro, define = yes, optional = yes;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss, define = yes;
+ ZPSAVE1: load = RAM, type = rw, define = yes; # ZPSAVE1, ZPSAVE2 must be together
+ ZPSAVE2: load = RAM, type = bss; # see "libsrc/atmos/crt0.s"
BSS: load = RAM, type = bss, define = yes;
- ZEROPAGE: load = ZP, type = zp;
}
FEATURES {
CONDES: type = constructor,
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
OVL1ADDR: load = OVL1ADDR, type = ro;
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
+FEATURES {
+ STARTADDRESS: default = $0801;
+}
SYMBOLS {
- __LOADADDR__: type = import;
- __EXEHDR__: type = import;
- __OVERLAYADDR__: type = import;
- __STACKSIZE__: type = weak, value = $0800; # 2k stack
- __OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay
+ __LOADADDR__: type = import;
+ __EXEHDR__: type = import;
+ __OVERLAYADDR__: type = import;
+ __STACKSIZE__: type = weak, value = $0800; # 2k stack
+ __OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay
+ __HIMEM__: type = weak, value = $D000;
+ __OVERLAYSTART__: type = export, value = __HIMEM__ - __OVERLAYSIZE__;
}
MEMORY {
- ZP: file = "", define = yes, start = $0002, size = $001A;
- LOADADDR: file = %O, start = $07FF, size = $0002;
- HEADER: file = %O, start = $0801, size = $000C;
- RAM: file = %O, define = yes, start = $080D, size = $C7F3 - __OVERLAYSIZE__ - __STACKSIZE__;
- OVL1ADDR: file = "%O.1", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL1: file = "%O.1", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL2ADDR: file = "%O.2", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL2: file = "%O.2", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL3ADDR: file = "%O.3", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL3: file = "%O.3", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL4ADDR: file = "%O.4", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL4: file = "%O.4", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL5ADDR: file = "%O.5", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL5: file = "%O.5", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL6ADDR: file = "%O.6", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL6: file = "%O.6", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL7ADDR: file = "%O.7", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL7: file = "%O.7", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL8ADDR: file = "%O.8", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL8: file = "%O.8", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
- OVL9ADDR: file = "%O.9", start = $CFFE - __OVERLAYSIZE__, size = $0002;
- OVL9: file = "%O.9", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
+ 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 = __OVERLAYSTART__ - __STACKSIZE__ - __HEADER_LAST__;
+ MOVE: file = %O, start = __INITBSS_LOAD__, size = __HIMEM__ - __BSS_RUN__;
+ INIT: file = "", start = __BSS_RUN__, size = __HIMEM__ - __BSS_RUN__;
+ OVL1ADDR: file = "%O.1", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL1: file = "%O.1", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL2ADDR: file = "%O.2", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL2: file = "%O.2", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL3ADDR: file = "%O.3", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL3: file = "%O.3", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL4ADDR: file = "%O.4", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL4: file = "%O.4", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL5ADDR: file = "%O.5", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL5: file = "%O.5", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL6ADDR: file = "%O.6", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL6: file = "%O.6", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL7ADDR: file = "%O.7", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL7: file = "%O.7", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL8ADDR: file = "%O.8", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL8: file = "%O.8", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
+ OVL9ADDR: file = "%O.9", start = __OVERLAYSTART__ - 2, size = $0002;
+ OVL9: file = "%O.9", start = __OVERLAYSTART__, size = __OVERLAYSIZE__;
}
SEGMENTS {
- LOADADDR: load = LOADADDR, type = ro;
- EXEHDR: load = HEADER, type = ro;
- STARTUP: load = RAM, type = ro;
- LOWCODE: load = RAM, type = ro, optional = yes;
- INIT: load = RAM, type = ro, define = yes, optional = yes;
- CODE: load = RAM, type = ro;
- RODATA: load = RAM, type = ro;
- DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
- BSS: load = RAM, type = bss, define = yes;
- ZEROPAGE: load = ZP, type = zp;
- OVL1ADDR: load = OVL1ADDR, type = ro;
- OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes;
- OVL2ADDR: load = OVL2ADDR, type = ro;
- OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes;
- OVL3ADDR: load = OVL3ADDR, type = ro;
- OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes;
- OVL4ADDR: load = OVL4ADDR, type = ro;
- OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes;
- OVL5ADDR: load = OVL5ADDR, type = ro;
- OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes;
- OVL6ADDR: load = OVL6ADDR, type = ro;
- OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes;
- OVL7ADDR: load = OVL7ADDR, type = ro;
- OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes;
- OVL8ADDR: load = OVL8ADDR, type = ro;
- OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes;
- OVL9ADDR: load = OVL9ADDR, type = ro;
- OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes;
+ 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;
+ RODATA: load = MAIN, type = ro;
+ DATA: load = MAIN, type = rw;
+ INITBSS: load = MAIN, type = bss, define = yes;
+ BSS: load = MAIN, type = bss, define = yes;
+ INIT: load = MOVE, run = INIT, type = ro, define = yes;
+ OVL1ADDR: load = OVL1ADDR, type = ro;
+ OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes;
+ OVL2ADDR: load = OVL2ADDR, type = ro;
+ OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes;
+ OVL3ADDR: load = OVL3ADDR, type = ro;
+ OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes;
+ OVL4ADDR: load = OVL4ADDR, type = ro;
+ OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes;
+ OVL5ADDR: load = OVL5ADDR, type = ro;
+ OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes;
+ OVL6ADDR: load = OVL6ADDR, type = ro;
+ OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes;
+ OVL7ADDR: load = OVL7ADDR, type = ro;
+ OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes;
+ OVL8ADDR: load = OVL8ADDR, type = ro;
+ OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes;
+ OVL9ADDR: load = OVL9ADDR, type = ro;
+ OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes;
}
FEATURES {
CONDES: type = constructor,
+FEATURES {
+ STARTADDRESS: default = $0801;
+}
SYMBOLS {
__LOADADDR__: type = import;
__EXEHDR__: type = import;
__STACKSIZE__: type = weak, value = $0800; # 2k stack
+ __HIMEM__: type = weak, value = $D000;
}
MEMORY {
- ZP: file = "", define = yes, start = $0002, size = $001A;
- LOADADDR: file = %O, start = $07FF, size = $0002;
- HEADER: file = %O, start = $0801, size = $000C;
- RAM: file = %O, define = yes, start = $080D, size = $C7F3 - __STACKSIZE__;
+ 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 = __HIMEM__ - __STACKSIZE__ - __HEADER_LAST__;
+ MOVE: file = %O, start = __INITBSS_LOAD__, size = __HIMEM__ - __BSS_RUN__;
+ INIT: file = "", start = __BSS_RUN__, size = __HIMEM__ - __BSS_RUN__;
}
SEGMENTS {
- LOADADDR: load = LOADADDR, type = ro;
- EXEHDR: load = HEADER, type = ro;
- STARTUP: load = RAM, type = ro;
- LOWCODE: load = RAM, type = ro, optional = yes;
- INIT: load = RAM, type = ro, define = yes, optional = yes;
- CODE: load = RAM, type = ro;
- RODATA: load = RAM, type = ro;
- DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
- BSS: load = RAM, type = bss, define = yes;
- ZEROPAGE: load = ZP, type = zp;
+ 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;
+ RODATA: load = MAIN, type = ro;
+ DATA: load = MAIN, type = rw;
+ INITBSS: load = MAIN, type = bss, define = yes;
+ BSS: load = MAIN, type = bss, define = yes;
+ INIT: load = MOVE, run = INIT, type = ro, define = yes;
}
FEATURES {
CONDES: type = constructor,
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = rw, define = yes;
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
EXTZP: load = ZP, type = rw, define = yes;
--- /dev/null
+FEATURES {
+ STARTADDRESS: default = $0200;
+}
+SYMBOLS {
+# If you want ld65 to output a loadable-format file by default, then uncomment
+# the next line. (Then, "-u __BOOT__" wouldn't be needed on the command line.)
+# __BOOT__: type = import;
+ __STACKSIZE__: type = weak, value = $0400; # 1 kB stack
+ __HIMEM__: type = weak, value = $8000; # 32 kB RAM
+}
+MEMORY {
+ # for size of ZP, see runtime/zeropage.s and c1p/extzp.s
+ ZP: file = "", define = yes, start = $0002, size = $001A + $0006;
+ HEAD: file = %O, start = $0000, size = $00B6;
+ RAM: file = %O, define = yes, start = %S, size = __HIMEM__ - __STACKSIZE__ - %S;
+}
+SEGMENTS {
+ BOOT: load = HEAD, type = ro, optional = yes;
+ INIT: load = RAM, type = ro, define = yes, optional = yes;
+ CODE: load = RAM, type = rw;
+ RODATA: load = RAM, type = rw;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ ZEROPAGE: load = ZP, type = zp;
+}
--- /dev/null
+FEATURES {
+ STARTADDRESS: default = $0200;
+}
+SYMBOLS {
+# If you want ld65 to output a loadable-format file by default, then uncomment
+# the next line. (Then, "-u __BOOT__" wouldn't be needed on the command line.)
+# __BOOT__: type = import;
+ __STACKSIZE__: type = weak, value = $0400; # 1 kB stack
+ __HIMEM__: type = weak, value = $8000; # 32 kB RAM
+}
+MEMORY {
+ # for size of ZP, see runtime/zeropage.s and c1p/extzp.s
+ ZP: file = "", define = yes, start = $0002, size = $001A + $0020;
+ HEAD: file = %O, start = $0000, size = $00B6;
+ RAM: file = %O, define = yes, start = %S, size = __HIMEM__ - __STACKSIZE__ - %S;
+}
+SEGMENTS {
+ BOOT: load = HEAD, type = ro, optional = yes;
+ STARTUP: load = RAM, type = ro;
+ LOWCODE: load = RAM, type = ro, optional = yes;
+ INIT: load = RAM, type = ro, define = yes, optional = yes;
+ CODE: load = RAM, type = rw;
+ RODATA: load = RAM, type = rw;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ ZEROPAGE: load = ZP, type = zp;
+ EXTZP: load = ZP, type = zp, define = yes, optional = yes;
+}
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = INIT;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+}
--- /dev/null
+# linker config to produce simple NEC PC-Engine cartridge (.pce)
+
+SYMBOLS {
+ __STACKSIZE__: type = weak, value = $0300; # 3 pages stack
+}
+
+MEMORY {
+ # FIXME: is this correct? the first 3? bytes cant be used?
+ ZP: start = $03, size = $fd, type = rw, define = yes;
+
+ # reset-bank and hardware vectors
+ ROM0: start = $e000, size = $1ff6, file = %O ,fill = yes, define = yes;
+ ROMV: start = $fff6, size = $a, file = %O,fill = yes;
+
+ # first RAM page (also contains stack and zeropage)
+ RAM: start = $2200, size = $1e00, define = yes;
+}
+
+SEGMENTS {
+ STARTUP: load = ROM0, type = ro, define = yes;
+ INIT: load = ROM0, type = ro, define = yes, optional = yes;
+ CODE: load = ROM0, type = ro, define = yes;
+ RODATA: load = ROM0, type = ro, define = yes;
+ DATA: load = ROM0, run= RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+ VECTORS: load = ROMV, type = rw, define = yes;
+ ZEROPAGE: load = ZP, type = zp, define = yes;
+ EXTZP: load = ZP, type = zp, define = yes, optional = yes;
+ APPZP: load = ZP, type = zp, define = yes, optional = yes;
+}
+
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = INIT;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+ CONDES: type = interruptor,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__,
+ segment = RODATA,
+ import = __CALLIRQ__;
+}
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw;
- ZPSAVE: load = RAM, type = bss;
+ INITBSS: load = RAM, type = bss;
BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp;
}
CMD_EXE = 1
endif
-.PHONY: all mostlyclean clean install zip doc html info gh-pages
+.PHONY: all mostlyclean clean install zip doc html info
.SUFFIXES:
<url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:polluks@sdf.lonestar.org" name="Stefan A. Haubenthal">,<newline>
<url url="mailto:greg.king5@verizon.net" name="Greg King">
-<date>2014-03-27
+<date>2015-01-09
<abstract>
An overview over the Atmos runtime system as it is implemented for the cc65 C
information.
+
<sect>Binary format<p>
The standard binary output format generated by the linker for the Atmos target
-is a machine language program with a 17 byte tape header including a cc65 tag.
-The standard load and autostart address is $500.
+is a machine language program with a one-line BASIC stub that jumps to the
+machine-language part through <tt/CALL/. It has one sacrificial byte attached
+to the end (a bug in the Oric ROM means that BASIC can put a variable on top
+of the last byte that was loaded). It has a 24-byte tape header. A file can
+be CLOADed as a BASIC program, and started by typing <tt/RUN/. The standard
+load address is $501.
+
<sect>Memory layout<p>
-In the standard setup, cc65 generated programs use the memory from
-$500 to $9800, so nearly 37K of memory (including the stack) is
+In the standard setup, cc65-generated programs use the memory from
+$0501 to $9800; so, nearly 37K of memory (including the stack) is
available. ROM calls are possible without further precautions.
+If your program needs more memory, and it won't use TGI graphics, then you can
+use the ld65 command-line option, <tt/-D __GRAB__=1/, when building the
+program, to include the graphics screen RAM. Then, nearly 44K of memory
+($0501 to $B400) is available.
+
Special locations:
<descrip>
<tag/Stack/
- The C runtime stack is located at $97FF and growing downwards.
+ The C runtime stack is located at $97FF (or $B3FF), and grows
+ downwards.
<tag/Heap/
- The C heap is located at the end of the program and grows towards the C
+ The C heap is located at the end of the program, and grows towards the C
runtime stack.
</descrip><p>
<descrip>
<tag><tt/VIA/</tag>
- Access to the VIA (versatile interface adapter) chip is available via the
+ Access to the VIA (Versatile Interface Adapter) chip is available via the
<tt/VIA/ variable. The structure behind this variable is explained in <tt/_6522.h/.
</descrip><p>
<sect1>Graphics drivers<p>
-The default drivers, <tt/tgi_stddrv (tgi_static_stddrv)/, point to <tt/atmos-240-200-2.tgi (atmos_240_200_2_tgi)/.
+The default drivers, <tt/tgi_stddrv (tgi_static_stddrv)/,
+point to <tt/atmos-240-200-2.tgi (atmos_240_200_2_tgi)/.
<descrip>
<sect1>Disk I/O<p>
-The existing library for the Atmos doesn't implement C file
-I/O. There are hacks for the <tt/read()/ and <tt/write()/ routines in
-place, which will make functions work that read from and write to <tt/stdout/
-(like <tt/printf()/). However, those functions have some shortcomings which
-won't be fixed, because they're going to be replaced anyway.
+The existing library for the Atmos doesn't implement C file I/O. There are
+hacks for the <tt/read()/ and <tt/write()/ routines in place, which will make
+functions work that read from <tt/stdin/ and write to <tt/stdout/ and
+<tt/stderr/ (such as <tt/printf()/). However, those functions have some
+shortcomings which won't be fixed, because they're going to be replaced
+anyway.
-To be more concrete, the limitation means that you cannot use any of the
+To be more concrete, that limitation means that you cannot use any of the
following functions (and a few others):
<itemize>
<sect1>Function keys<p>
-These are defined to be FUNCT + number key.
+They are defined to be FUNCT + a number key.
+
+
+<sect1>Capitals lock<p>
+
+The keyboard's "CAPS Lock" mode is turned off while the program is running.
+The previous mode (usually, CAPS Lock turned on [because Oric BASIC keywords
+must be UPPER-case]) is restored when the program stops.
<sect1>Passing arguments to the program<p>
supported directly by BASIC, the following syntax was chosen:
<tscreen><verb>
- CALL#500:REM ARG1 " ARG2 IS QUOTED" ARG3 "" ARG5
+ RUN:REM arg1 " ARG2 IS QUOTED" ARG3 "" ARG5
</verb></tscreen>
<enum>
+<item>You must turn <tt/CAPS/ lock off (tap CTRL-T) when you want to type
+ lower-case arguments (but, <tt/RUN/ and <tt/REM/ must be UPPER-case).
<item>Arguments are separated by spaces.
<item>Arguments may be quoted.
<item>Leading and trailing spaces around an argument are ignored. Spaces within
</enum>
+<sect1>Automatic starting<p>
+
+Usually, a cc65-built program just will sit quietly in memory, after it is
+CLOADed. It waits for you to start it (by typing BASIC's <tt/RUN/ command).
+But, if you want to create a program that will start running immediately after
+it is loaded, then you can use the linker command-line option
+<tt/-D __AUTORUN__=$C7/.
+
+
<sect1>Interrupts<p>
The runtime for the Atmos uses routines marked as <tt/.INTERRUPTOR/ for
Please note that in this case a changed start address doesn't make sense,
since the program must be loaded to the BASIC start address.
+<sect>Extras<p>
+
+<sect1>80 Columns conio driver<p>
+
+The C64 package comes with an alternative software driven 80 columns
+module <tt/c64-soft80.o/ which uses the memory under I/O between $d000
+and $ffff.
+
+In memory constrained situations the memory from $400 to $7FF
+can be made available to a program by calling <tt/_heapadd ((void *) 0x0400, 0x0400);/
+at the beginning of <tt/main()/. Doing so is beneficial even if the program
+doesn't use the the heap explicitly because loading a driver uses the heap implicitly.
+
+Using <tt/c64-soft80.o/ is as simple as placing it on the linker command
+line like this:
+
+<tscreen><verb>
+cl65 -t c64 myprog.c c64-soft80.o
+</verb></tscreen>
+
+Note that the soft80 conio driver is incompatible with the
+<tt/c64-ram.emd (c64_ram_emd)/ extended memory driver and the
+ <tt/c64-hi.tgi (c64_hi_tgi)/ graphics driver.
+
+<sect2>80 Columns conio driver (monochrome)<p>
+
+In an (even more) memory constrained situation, a size optimized version of the
+software driven 80 columns module may be used, which only supports one common
+text color for the whole screen.
+
+<tscreen><verb>
+cl65 -t c64 myprog.c c64-soft80mono.o
+</verb></tscreen>
<sect>Platform-specific header files<p>
palette of the 16 C64 colors).
</descrip><p>
+Note that the graphics drivers are incompatible with the
+<tt/c64-ram.emd (c64_ram_emd)/ extended memory driver and the
+ <tt/c64-soft80.o/ software 80 columns conio driver.
<sect1>Extended memory drivers<p>
<tag><tt/c64-ram.emd (c64_ram_emd)/</tag>
A driver for the hidden RAM below the I/O area and kernal ROM. Supports 48
256 byte pages. Please note that this driver is incompatible with any of the
- graphics drivers!
+ graphics drivers, or the soft80 conio driver!
<tag><tt/c64-ramcart.emd (c64_ramcart_emd)/</tag>
A driver for the RamCart 64/128 written and contributed by Maciej Witkowiak.
<article>
<title>ca65 Users Guide
-<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
-<date>2014-04-24
+<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
+<url url="mailto:greg.king5@verizon.net" name="Greg King">
+<date>2015-11-17
<abstract>
-ca65 is a powerful macro assembler for the 6502, 65C02 and 65816 CPUs. It is
+ca65 is a powerful macro assembler for the 6502, 65C02, and 65816 CPUs. It is
used as a companion assembler for the cc65 crosscompiler, but it may also be
used as a standalone product.
</abstract>
<sect1>65816 mode<p>
-In 65816 mode several aliases are accepted in addition to the official
+In 65816 mode, several aliases are accepted, in addition to the official
mnemonics:
<tscreen><verb>
- BGE is an alias for BCS
- BLT is an alias for BCC
- CPA is an alias for CMP
- DEA is an alias for DEC A
- INA is an alias for INC A
- SWA is an alias for XBA
- TAD is an alias for TCD
- TAS is an alias for TCS
- TDA is an alias for TDC
- TSA is an alias for TSC
+CPA is an alias for CMP
+DEA is an alias for DEC A
+INA is an alias for INC A
+SWA is an alias for XBA
+TAD is an alias for TCD
+TAS is an alias for TCS
+TDA is an alias for TDC
+TSA is an alias for TSC
</verb></tscreen>
-
<sect1>6502X mode<label id="6502X-mode"><p>
6502X mode is an extension to the normal 6502 mode. In this mode, several
assignments to <tt/*/, use <tt/<ref id=".ORG" name=".ORG">/ instead.
+<sect1><tt>.ASIZE</tt><label id=".ASIZE"><p>
+
+ Reading this pseudo variable will return the current size of the
+ Accumulator in bits.
+
+ For the 65816 instruction set .ASIZE will return either 8 or 16, depending
+ on the current size of the operand in immediate accu addressing mode.
+
+ For all other CPU instruction sets, .ASIZE will always return 8.
+
+ Example:
+
+ <tscreen><verb>
+ ; Reverse Subtract with Accumulator
+ ; A = memory - A
+ .macro rsb param
+ .if .asize = 8
+ eor #$ff
+ .else
+ eor #$ffff
+ .endif
+ sec
+ adc param
+ .endmacro
+ </verb></tscreen>
+
+ See also: <tt><ref id=".ISIZE" name=".ISIZE"></tt>
+
+
<sect1><tt>.CPU</tt><label id=".CPU"><p>
Reading this pseudo variable will give a constant integer value that
</verb></tscreen>
+<sect1><tt>.ISIZE</tt><label id=".ISIZE"><p>
+
+ Reading this pseudo variable will return the current size of the Index
+ register in bits.
+
+ For the 65816 instruction set .ISIZE will return either 8 or 16, depending
+ on the current size of the operand in immediate index addressing mode.
+
+ For all other CPU instruction sets, .ISIZE will always return 8.
+
+ See also: <tt><ref id=".ASIZE" name=".ASIZE"></tt>
+
+
<sect1><tt>.PARAMCOUNT</tt><label id=".PARAMCOUNT"><p>
This builtin pseudo variable is only available in macros. It is replaced by
either a string or an expression.
+<sect1><tt>.ADDRSIZE</tt><label id=".ADDRSIZE"><p>
+
+ The <tt/.ADDRSIZE/ function is used to return the interal address size
+ associated with a symbol. This can be helpful in macros when knowing the address
+ size of symbol can help with custom instructions.
+
+ Example:
+
+ <tscreen><verb>
+ .macro myLDA foo
+ .if .ADDRSIZE(foo) = 1
+ ;do custom command based on zeropage addressing:
+ .byte 0A5h, foo
+ .elseif .ADDRSIZE(foo) = 2
+ ;do custom command based on absolute addressing:
+ .byte 0ADh
+ .word foo
+ .elseif .ADDRSIZE(foo) = 0
+ ; no address size defined for this symbol:
+ .out .sprintf("Error, address size unknown for symbol %s", .string(foo))
+ .endif
+ .endmacro
+ </verb></tscreen>
+
+ This command is new and must be enabled with the <tt/.FEATURE addrsize/ command.
+
+ See: <tt><ref id=".FEATURE" name=".FEATURE"></tt>
+
+
<sect1><tt>.BANK</tt><label id=".BANK"><p>
The <tt/.BANK/ function is used to support systems with banked memory. The
</verb></tscreen>
+<sect1><tt>.DEFINEDMACRO</tt><label id=".DEFINEDMACRO"><p>
+
+ Builtin function. The function expects an identifier as argument in braces.
+ The argument is evaluated, and the function yields "true" if the identifier
+ has already been defined as the name of a macro. Otherwise the function yields
+ false. Example:
+
+ <tscreen><verb>
+ .macro add foo
+ clc
+ adc foo
+ .endmacro
+
+ .if .definedmacro(add)
+ add #$01
+ .else
+ clc
+ adc #$01
+ .endif
+ </verb></tscreen>
+
+
<sect1><tt>.DESTRUCTOR</tt><label id=".DESTRUCTOR"><p>
Export a symbol and mark it as a module destructor. This may be used
<descrip>
+ <tag><tt>addrsize</tt><label id="addrsize"></tag>
+
+ Enables the .ADDRSIZE pseudo function. This function is experimental and not enabled by default.
+
+ See also: <tt><ref id=".ADDRSIZE" name=".ADDRSIZE"></tt>
+
<tag><tt>at_in_identifiers</tt><label id="at_in_identifiers"></tag>
Accept the at character (`@') as a valid character in identifiers. The
the feature in more detail.
+<sect1><tt>.ISMNEM, .ISMNEMONIC</tt><label id=".ISMNEMONIC"><p>
+
+ Builtin function. The function expects an identifier as argument in braces.
+ The argument is evaluated, and the function yields "true" if the identifier
+ is defined as an instruction mnemonic that is recognized by the assembler.
+ Example:
+
+ <tscreen><verb>
+ .if .not .ismnemonic(ina)
+ .macro ina
+ clc
+ adc #$01
+ .endmacro
+ .endif
+ </verb></tscreen>
+
+
<sect1><tt>.LINECONT</tt><label id=".LINECONT"><p>
Switch on or off line continuations using the backslash character
atari Defines the scrcode macro.
cbm Defines the scrcode macro.
cpu Defines constants for the .CPU variable.
- generic Defines generic macros like add and sub.
- longbranch Defines conditional long jump macros.
+ generic Defines generic macroes like add, sub, and blt.
+ longbranch Defines conditional long-jump macroes.
</verb></tscreen>
Including a macro package twice, or including a macro package that
segment, that is, a named section of data. The default segment is
"CODE". There may be up to 254 different segments per object file
(and up to 65534 per executable). There are shortcut commands for
- the most common segments ("CODE", "DATA" and "BSS").
+ the most common segments ("ZEROPAGE", "CODE", "RODATA", "DATA", and "BSS").
The command is followed by a string containing the segment name (there are
some constraints for the name - as a rule of thumb use only those segment
</verb></tscreen>
See: <tt><ref id=".BSS" name=".BSS"></tt>, <tt><ref id=".CODE"
- name=".CODE"></tt>, <tt><ref id=".DATA" name=".DATA"></tt> and <tt><ref
- id=".RODATA" name=".RODATA"></tt>
+ name=".CODE"></tt>, <tt><ref id=".DATA" name=".DATA"></tt>, <tt><ref
+ id=".RODATA" name=".RODATA"></tt>, and <tt><ref id=".ZEROPAGE"
+ name=".ZEROPAGE"></tt>
<sect1><tt>.SET</tt><label id=".SET"><p>
shortcut for
<tscreen><verb>
- .segment "ZEROPAGE", zeropage
+ .segment "ZEROPAGE": zeropage
</verb></tscreen>
Because of the "zeropage" attribute, labels declared in this segment are
example:
<tscreen><verb>
- .macro asr ; Arithmetic shift right
- cmp #$80 ; Put bit 7 into carry
- ror ; Rotate right with carry
- .endmacro
+.macro asr ; Arithmetic shift right
+ cmp #$80 ; Put bit 7 into carry
+ ror ; Rotate right with carry
+.endmacro
</verb></tscreen>
The macro above consists of two real instructions, that are inserted into
by using the name, like this:
<tscreen><verb>
- lda $2010
- asr
- sta $2010
+ lda $2010
+ asr
+ sta $2010
</verb></tscreen>
When using macro parameters, macros can be even more useful:
<tscreen><verb>
- .macro inc16 addr
- clc
- lda addr
- adc #$01
- sta addr
- lda addr+1
- adc #$00
- sta addr+1
- .endmacro
+.macro inc16 addr
+ clc
+ lda addr
+ adc #<$0001
+ sta addr
+ lda addr+1
+ adc #>$0001
+ sta addr+1
+.endmacro
</verb></tscreen>
When calling the macro, you may give a parameter, and each occurrence of
parameter. So
<tscreen><verb>
- inc16 $1000
+ inc16 $1000
</verb></tscreen>
will be expanded to
<tscreen><verb>
- clc
- lda $1000
- adc #$01
- sta $1000
- lda $1000+1
- adc #$00
- sta $1000+1
+ clc
+ lda $1000
+ adc #<$0001
+ sta $1000
+ lda $1000+1
+ adc #>$0001
+ sta $1000+1
</verb></tscreen>
A macro may have more than one parameter, in this case, the parameters
Look at this example:
<tscreen><verb>
- .macro ldaxy a, x, y
- .ifnblank a
- lda #a
- .endif
- .ifnblank x
- ldx #x
- .endif
- .ifnblank y
- ldy #y
- .endif
- .endmacro
+.macro ldaxy a, x, y
+.ifnblank a
+ lda #a
+.endif
+.ifnblank x
+ ldx #x
+.endif
+.ifnblank y
+ ldy #y
+.endif
+.endmacro
</verb></tscreen>
-This macro may be called as follows:
+That macro may be called as follows:
<tscreen><verb>
- ldaxy 1, 2, 3 ; Load all three registers
+ ldaxy 1, 2, 3 ; Load all three registers
- ldaxy 1, , 3 ; Load only a and y
+ ldaxy 1, , 3 ; Load only a and y
- ldaxy , , 3 ; Load y only
+ ldaxy , , 3 ; Load y only
</verb></tscreen>
-There's another helper command for determining, which macro parameters are
-valid: <tt><ref id=".PARAMCOUNT" name=".PARAMCOUNT"></tt> This command is
-replaced by the parameter count given, <em/including/ intermediate empty macro
+There's another helper command for determining which macro parameters are
+valid: <tt><ref id=".PARAMCOUNT" name=".PARAMCOUNT"></tt>. That command is
+replaced by the parameter count given, <em/including/ explicitly empty
parameters:
<tscreen><verb>
- ldaxy 1 ; .PARAMCOUNT = 1
- ldaxy 1,,3 ; .PARAMCOUNT = 3
- ldaxy 1,2 ; .PARAMCOUNT = 2
- ldaxy 1, ; .PARAMCOUNT = 2
- ldaxy 1,2,3 ; .PARAMCOUNT = 3
+ ldaxy 1 ; .PARAMCOUNT = 1
+ ldaxy 1,,3 ; .PARAMCOUNT = 3
+ ldaxy 1,2 ; .PARAMCOUNT = 2
+ ldaxy 1, ; .PARAMCOUNT = 2
+ ldaxy 1,2,3 ; .PARAMCOUNT = 3
</verb></tscreen>
Macro parameters may optionally be enclosed into curly braces. This allows the
case of a macro parameter).
<tscreen><verb>
- .macro foo arg1, arg2
- ...
- .endmacro
+.macro foo arg1, arg2
+ ...
+.endmacro
- foo ($00,x) ; Two parameters passed
- foo {($00,x)} ; One parameter passed
+ foo ($00,x) ; Two parameters passed
+ foo {($00,x)} ; One parameter passed
</verb></tscreen>
In the first case, the macro is called with two parameters: '<tt/($00/'
-and 'x)'. The comma is not passed to the macro, since it is part of the
+and '<tt/x)/'. The comma is not passed to the macro, because it is part of the
calling sequence, not the parameters.
-In the second case, '($00,x)' is passed to the macro, this time
+In the second case, '<tt/($00,x)/' is passed to the macro; this time,
including the comma.
functions will allow you to do exactly this:
<tscreen><verb>
- .macro ldax arg
- .if (.match (.left (1, {arg}), #))
- ; immediate mode
- lda #<(.right (.tcount ({arg})-1, {arg}))
- ldx #>(.right (.tcount ({arg})-1, {arg}))
- .else
- ; assume absolute or zero page
- lda arg
- ldx 1+(arg)
- .endif
- .endmacro
+.macro ldax arg
+ .if (.match (.left (1, {arg}), #))
+ ; immediate mode
+ lda #<(.right (.tcount ({arg})-1, {arg}))
+ ldx #>(.right (.tcount ({arg})-1, {arg}))
+ .else
+ ; assume absolute or zero page
+ lda arg
+ ldx 1+(arg)
+ .endif
+.endmacro
</verb></tscreen>
Using the <tt/<ref id=".MATCH" name=".MATCH">/ function, the macro is able to
The macro can be used as
<tscreen><verb>
- foo: .word $5678
- ...
- ldax #$1234 ; X=$12, A=$34
- ...
- ldax foo ; X=$56, A=$78
+foo: .word $5678
+...
+ ldax #$1234 ; X=$12, A=$34
+...
+ ldax foo ; X=$56, A=$78
</verb></tscreen>
Macros may be used recursively:
<tscreen><verb>
- .macro push r1, r2, r3
- lda r1
- pha
- .if .paramcount > 1
- push r2, r3
- .endif
- .endmacro
+.macro push r1, r2, r3
+ lda r1
+ pha
+.ifnblank r2
+ push r2, r3
+.endif
+.endmacro
</verb></tscreen>
-There's also a special macro to help writing recursive macros: <tt><ref
-id=".EXITMACRO" name=".EXITMACRO"></tt> This command will stop macro expansion
-immediately:
+There's also a special macro command to help with writing recursive macros:
+<tt><ref id=".EXITMACRO" name=".EXITMACRO"></tt>. That command will stop macro
+expansion immediately:
<tscreen><verb>
- .macro push r1, r2, r3, r4, r5, r6, r7
- .ifblank r1
- ; First parameter is empty
- .exitmacro
- .else
- lda r1
- pha
- .endif
- push r2, r3, r4, r5, r6, r7
- .endmacro
+.macro push r1, r2, r3, r4, r5, r6, r7
+.ifblank r1
+ ; First parameter is empty
+ .exitmacro
+.else
+ lda r1
+ pha
+.endif
+ push r2, r3, r4, r5, r6, r7
+.endmacro
</verb></tscreen>
-When expanding this macro, the expansion will push all given parameters
+When expanding that macro, the expansion will push all given parameters
until an empty one is encountered. The macro may be called like this:
<tscreen><verb>
- push $20, $21, $32 ; Push 3 ZP locations
- push $21 ; Push one ZP location
+ push $20, $21, $32 ; Push 3 ZP locations
+ push $21 ; Push one ZP location
</verb></tscreen>
Have a look at the inc16 macro above. Here is it again:
<tscreen><verb>
- .macro inc16 addr
- clc
- lda addr
- adc #$01
- sta addr
- lda addr+1
- adc #$00
- sta addr+1
- .endmacro
+.macro inc16 addr
+ clc
+ lda addr
+ adc #<$0001
+ sta addr
+ lda addr+1
+ adc #>$0001
+ sta addr+1
+.endmacro
</verb></tscreen>
If you have a closer look at the code, you will notice, that it could be
written more efficiently, like this:
<tscreen><verb>
- .macro inc16 addr
- inc addr
- bne Skip
- inc addr+1
- Skip:
- .endmacro
+.macro inc16 addr
+ inc addr
+ bne Skip
+ inc addr+1
+Skip:
+.endmacro
</verb></tscreen>
But imagine what happens, if you use this macro twice? Since the label "Skip"
expansion. So we can solve the problem above by using <tt/.LOCAL/:
<tscreen><verb>
- .macro inc16 addr
- .local Skip ; Make Skip a local symbol
- inc addr
- bne Skip
- inc addr+1
- Skip: ; Not visible outside
- .endmacro
+.macro inc16 addr
+ .local Skip ; Make Skip a local symbol
+ inc addr
+ bne Skip
+ inc addr+1
+Skip: ; Not visible outside
+.endmacro
</verb></tscreen>
Another solution is of course to start a new lexical block inside the macro
that hides any labels:
<tscreen><verb>
- .macro inc16 addr
- .proc
- inc addr
- bne Skip
- inc addr+1
- Skip:
- .endproc
- .endmacro
+.macro inc16 addr
+.proc
+ inc addr
+ bne Skip
+ inc addr+1
+Skip:
+.endproc
+.endmacro
</verb></tscreen>
be omitted.
<item> Since <tt><ref id=".DEFINE" name=".DEFINE"></tt> style macros may not
- contain end-of-line tokens, there are things that cannot be done. They
+ contain end-of-line tokens, there are things that cannot be done. They
may not contain several processor instructions for example. So, while
some things may be done with both macro types, each type has special
usages. The types complement each other.
following <tt/.DEFINE/:
<tscreen><verb>
- .define EQU =
+.define EQU =
- foo EQU $1234 ; This is accepted now
+foo EQU $1234 ; This is accepted now
</verb></tscreen>
You may use the directive to define string constants used elsewhere:
<tscreen><verb>
- ; Define the version number
- .define VERSION "12.3a"
+; Define the version number
+.define VERSION "12.3a"
- ; ... and use it
- .asciiz VERSION
+ ; ... and use it
+ .asciiz VERSION
</verb></tscreen>
Macros with parameters may also be useful:
<tscreen><verb>
- .define DEBUG(message) .out message
+.define DEBUG(message) .out message
- DEBUG "Assembling include file #3"
+ DEBUG "Assembling include file #3"
</verb></tscreen>
Note that, while formal parameters have to be placed in braces, this is
don't like that, use classic macros instead:
<tscreen><verb>
- .macro DEBUG message
- .out message
- .endmacro
+.macro DEBUG message
+ .out message
+.endmacro
</verb></tscreen>
-(This is an example where a problem can be solved with both macro types).
+(That is an example where a problem can be solved with both macro types).
<sect1>Characters in macros<p>
<sect1>Deleting macros<p>
Macros can be deleted. This will not work if the macro that should be deleted
-is currently expanded as in the following non working example:
+is currently expanded as in the following non-working example:
<tscreen><verb>
- .macro notworking
- .delmacro notworking
- .endmacro
+.macro notworking
+ .delmacro notworking
+.endmacro
notworking ; Will not work
</verb></tscreen>
id=".UNDEFINE" name=".UNDEFINE"></tt> must be used. Example:
<tscreen><verb>
- .define value 1
- .macro mac
- .byte 2
- .endmacro
+.define value 1
+.macro mac
+ .byte 2
+.endmacro
- .byte value ; Emit one byte with value 1
- mac ; Emit another byte with value 2
+ .byte value ; Emit one byte with value 1
+ mac ; Emit another byte with value 2
- .undefine value
- .delmacro mac
+.undefine value
+.delmacro mac
- .byte value ; Error: Unknown identifier
- mac ; Error: Missing ":"
+ .byte value ; Error: Unknown identifier
+ mac ; Error: Missing ":"
</verb></tscreen>
A separate command for <tt>.DEFINE</tt> style macros was necessary, because
different commands increases flexibility.
+
<sect>Macro packages<label id="macropackages"><p>
Using the <tt><ref id=".MACPACK" name=".MACPACK"></tt> directive, predefined
<sect1><tt>.MACPACK generic</tt><p>
-This macro package defines macros that are useful in almost any program.
-Currently defined macros are:
+This macro package defines macroes that are useful in almost any program.
+Currently defined macroes are:
<tscreen><verb>
- .macro add Arg
+ .macro add Arg ; add without carry
clc
adc Arg
.endmacro
- .macro sub Arg
+ .macro sub Arg ; subtract without borrow
sec
sbc Arg
.endmacro
- .macro bge Arg
+ .macro bge Arg ; branch on greater-than or equal
bcs Arg
.endmacro
- .macro blt Arg
+ .macro blt Arg ; branch on less-than
bcc Arg
.endmacro
- .macro bgt Arg
+ .macro bgt Arg ; branch on greater-than
.local L
beq L
bcs Arg
L:
.endmacro
- .macro ble Arg
+ .macro ble Arg ; branch on less-than or equal
beq Arg
bcc Arg
.endmacro
- .macro bnz Arg
+ .macro bnz Arg ; branch on not zero
bne Arg
.endmacro
- .macro bze Arg
+ .macro bze Arg ; branch on zero
beq Arg
.endmacro
-
</verb></tscreen>
instruction is supported, which is the case for the 65SC02, 65C02 and 65816
CPUs (the latter two are upwards compatible to the 65SC02).
-
+
<sect1><tt>.MACPACK module</tt><p>
This macro package defines a macro named <tt/module_header/. It takes an
<item><tt/__LUNIX__/ - Target system is <tt/lunix/
<item><tt/__LYNX__/ - Target system is <tt/lynx/
<item><tt/__NES__/ - Target system is <tt/nes/
+<item><tt/__OSIC1P__/ - Target system is <tt/osic1p/
<item><tt/__PET__/ - Target system is <tt/pet/
<item><tt/__PLUS4__/ - Target system is <tt/plus4/
<item><tt/__SIM6502__/ - Target system is <tt/sim6502/
</article>
-
-
-
<article>
<title>cc65 Users Guide
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
-<date>2000-09-03, 2001-10-02, 2005-08-01
+<date>2015-05-26
<abstract>
cc65 is a C compiler for 6502 targets. It supports several 6502 based home
Long options:
--add-source Include source as comment
+ --all-cdecl Make functions default to __cdecl__
--bss-name seg Set the name of the BSS segment
--check-stack Generate stack overflow checks
--code-name seg Set the name of the CODE segment
<descrip>
+ <tag><tt>--all-cdecl</tt></tag>
+
+ Tells the compiler that functions which aren't declared explicitly with
+ either the <tt/__cdecl__/ or <tt/__fastcall__/ calling conventions should
+ have the cdecl convention. (Normally, functions that aren't variadic are
+ fast-called.)
+
+
<label id="option-bss-name">
<tag><tt>--bss-name seg</tt></tag>
<item>lunix
<item>lynx
<item>nes
+ <item>osic1p
<item>pet (all CBM PET systems except the 2001)
<item>plus4
<item>sim6502
be passed as parameters by value. However, struct assignment *is*
possible.
<p>
-<item> Part of the C library is available only with fastcall calling
- conventions (see below). It means that you must not mix pointers to
- those functions with pointers to user-written, not-fastcall functions.
+<item> Most of the C library is available with only the fastcall calling
+ convention (<ref id="extension-fastcall" name="see below">). It means
+ that you must not mix pointers to those functions with pointers to
+ user-written, cdecl functions (the calling conventions are incompatible).
<p>
<item> The <tt/volatile/ keyword doesn't have an effect. This is not as bad
as it sounds, since the 6502 has so few registers that it isn't
<ref id="inline-asm" name="see there">.
<p>
-<item> There is a special calling convention named "fastcall".
- The syntax for a function declaration using fastcall is
+<label id="extension-fastcall">
+<item> The normal calling convention -- for non-variadic functions -- is
+ named "fastcall". The syntax for a function declaration that
+ <em/explicitly/ uses fastcall is
<tscreen><verb>
<return type> fastcall <function name> (<parameter list>)
</verb></tscreen>
or
<tscreen><verb>
- <return type> __fastcall__ <function name> (<parameter list>)
+ <return type> __fastcall__ <function name> (<parameter list>)
</verb></tscreen>
- An example would be
+ An example is
<tscreen><verb>
- void __fastcall__ f (unsigned char c)
+ void __fastcall__ f (unsigned char c)
</verb></tscreen>
The first form of the fastcall keyword is in the user namespace and can
therefore be disabled with the <tt><ref id="option--standard"
name="--standard"></tt> command line option.
- For functions declared as <tt/fastcall/, the rightmost parameter is not
+ For functions that are <tt/fastcall/, the rightmost parameter is not
pushed on the stack but left in the primary register when the function
- is called. This will reduce the cost when calling assembler functions
- significantly, especially when the function itself is rather small.
+ is called. That significantly reduces the cost of calling those functions.
+ <newline><newline>
<p>
+<item> There is another calling convention named "cdecl". Variadic functions
+ (their prototypes have an ellipsis [<tt/.../]) always use that
+ convention. The syntax for a function declaration using cdecl is
+
+ <tscreen><verb>
+ <return type> cdecl <function name> (<parameter list>)
+ </verb></tscreen>
+ or
+ <tscreen><verb>
+ <return type> __cdecl__ <function name> (<parameter list>)
+ </verb></tscreen>
+ An example is
+ <tscreen><verb>
+ int* __cdecl__ f (unsigned char c)
+ </verb></tscreen>
+
+ The first form of the cdecl keyword is in the user namespace;
+ and therefore, can be disabled with the <tt/<ref id="option--standard"
+ name="--standard">/ command-line option.
+
+ For functions that are <tt/cdecl/, the rightmost parameter is pushed
+ onto the stack before the function is called. That increases the cost
+ of calling those functions, especially when they are called from many
+ places.<newline><newline>
+ <p>
+
<item> There are two pseudo variables named <tt/__AX__/ and <tt/__EAX__/.
Both refer to the primary register that is used by the compiler to
evaluate expressions or return function results. <tt/__AX__/ is of
Is defined if the compiler was called with the <tt/-Os/ command line option.
+ <tag><tt>__OSIC1P__</tt></tag>
+
+ This macro is defined if the target is the Ohio Scientific Challenger 1P
+ (-t osic1p).
+
<tag><tt>__PET__</tt></tag>
This macro is defined if the target is the PET family of computers (-t pet).
--- /dev/null
+<!doctype linuxdoc system> <!-- -*- text-mode -*- -->
+
+<article>
+<title>chrcvt Users Guide
+<author><url url="mailto:polluks@sdf.lonestar.org" name="Stefan A. Haubenthal">
+<date>2013-02-10
+
+<abstract>
+chrcvt is the vector font converter. It is able to convert a foreign font into
+the native format.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+
+<sect>Overview<p>
+
+chrcvt is a vector font converter. It is able to convert a "BGI Stroked
+Font" to a compact TGI native vector font. See the function <url
+url="funcref.html#tgi_load_vectorfont" name="tgi_load_vectorfont"> for usage.
+
+
+
+<sect>Usage<p>
+
+The chrcvt utility converts the font of one Borland file to its cc65 equivalent.
+
+
+<sect1>Command line option overview<p>
+
+The program may be called as follows:
+
+<tscreen><verb>
+---------------------------------------------------------------------------
+Usage: chrcvt [options] file [options] [file]
+Short options:
+ -h Help (this text)
+ -v Be more verbose
+ -V Print the version number and exit
+
+Long options:
+ --help Help (this text)
+ --verbose Be more verbose
+ --version Print the version number and exit
+---------------------------------------------------------------------------
+</verb></tscreen>
+
+
+<sect1>Command line options in detail<p>
+
+Here is a description of all the command line options:
+
+<descrip>
+
+ <tag><tt>-v, --verbose</tt></tag>
+
+ Increase the converter verbosity.
+
+
+ <tag><tt>-h, --help</tt></tag>
+
+ Print the short option summary shown above.
+
+
+ <tag><tt>-V, --version</tt></tag>
+
+ Print the version number of the utility. When submitting a bug report,
+ please include the operating system you're using, and the compiler
+ version.
+</descrip>
+
+
+<sect>Input and output<p>
+
+The converter will read one CHR file per invocation and write the font
+in TCH format to a new file.
+
+Example output for the command
+<tscreen><verb>
+chrcvt --verbose LITT.CHR
+</verb></tscreen>
+<tscreen><verb>
+BGI Stroked Font V1.1 - Aug 12, 1991
+Copyright (c) 1987,1988 Borland International
+</verb></tscreen>
+
+
+
+<sect>Copyright<p>
+
+chrcvt is (C) Copyright 2009, Ullrich von Bassewitz. For usage of the
+binaries and/or sources the following conditions apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+<enum>
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
+</enum>
+
+</article>
<article>
<title>Defining a Custom cc65 Target
<author>Bruce Reidenbach
-<date>2010-02-22
+<date>2015-03-13
<abstract>
This section provides step-by-step instructions on how to use the cc65
to determine how to pass the C arguments to the assembly language
routine. The cc65 toolset allows the user to specify whether the data
is passed to a subroutine via the stack or by the processor registers by
-using the <tt>__fastcall__</tt> function declaration (note that there
-are two underscore characters in front of and two behind the
-<tt>fastcall</tt> declaration). When <tt>__fastcall__</tt> is
-specified, the rightmost argument in the function call is passed to the
+using the <tt/__fastcall__/ and <tt/__cdecl__/ function qualifiers (note that
+there are two underscore characters in front of and two behind each
+qualifier). <tt/__fastcall__/ is the default. When <tt/__cdecl__/ <em/isn't/
+specified, and the function isn't variadic (i.e., its prototype doesn't have
+an ellipsis), the rightmost argument in the function call is passed to the
subroutine using the 6502 registers instead of the stack. Note that if
there is only one argument in the function call, the execution overhead
required by the stack interface routines is completely avoided.
-Without <tt>__fastcall__</tt>, the argument is loaded in the A and X
+With <tt/__cdecl__</tt>, the last argument is loaded into the A and X
registers and then pushed onto the stack via a call to <tt>pushax</tt>.
The first thing the subroutine does is retrieve the argument from the
stack via a call to <tt>ldax0sp</tt>, which copies the values into the A
jmp incsp2 ; Pop A and X from the stack (includes return)
</verb></tscreen>
-If <tt>__fastcall__</tt> is specified, the argument is loaded into the A
+If <tt/__cdecl__/ isn't specified, then the argument is loaded into the A
and X registers as before, but the subroutine is then called
immediately. The subroutine does not need to retrieve the argument
since the value is already available in the A and X registers.
<article>
<title>da65 Users Guide
-<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
-<date>2003-08-08
+<author>
+<url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
+<url url="mailto:greg.king5@verizon.net" name="Greg King">
+<date>2014-11-23
<abstract>
-da65 is a 6502/65C02 disassembler that is able to read user supplied
-information about its input data for better results. The output is ready for
+da65 is a 6502/65C02 disassembler that is able to read user-supplied
+information about its input data, for better results. The output is ready for
feeding into ca65, the macro assembler supplied with the cc65 C compiler.
</abstract>
macro assembler.
Besides generating output for ca65, one of the design goals was that the user
-is able to feed additional information about the code into the disassembler
+is able to feed additional information about the code into the disassembler,
for improved results. This information may include the location and size of
tables, and their format.
<tag><tt>--cpu type</tt></tag>
Set the CPU type. The option takes a parameter, which may be one of
+ <itemize>
+ <item>6502
+ <item>6502x
+ <item>65sc02
+ <item>65c02
+ <item>huc6280
+ </itemize>
- 6502, 6502x, 65sc02, 65c02, huc6280
-
- 6502x is the NMOS 6502 with illegal opcodes. huc6280 is the CPU of the PC
- engine. Support for the 65816 is currently not available.
+ 6502x is for the NMOS 6502 with unofficial opcodes. huc6280 is the CPU of
+ the PC engine. Support for the 65816 currently is not available.
<label id="option--formfeeds">
<tag><tt>-g, --debug-info</tt></tag>
This option adds the <tt/.DEBUGINFO/ command to the output file, so the
- assembler will generate debug information when reassembling the generated
+ assembler will generate debug information when re-assembling the generated
output.
The disassembler works by creating an attribute map for the whole address
space ($0000 - $FFFF). Initially, all attributes are cleared. Then, an
external info file (if given) is read. Disassembly is done in several passes.
-In all passes with the exception of the last one, information about the
+In all passes, with the exception of the last one, information about the
disassembled code is gathered and added to the symbol and attribute maps. The
last pass generates output using the information from the maps.
depends on the type of the attribute. String attributes are places in double
quotes, numeric attributes may be specified as decimal numbers or hexadecimal
with a leading dollar sign. There are also attributes where the attribute
-value is a keyword, in this case the keyword is given as is (without quotes or
+value is a keyword; in this case, the keyword is given as-is (without quotes or
anything). Each attribute is terminated by a semicolon.
<tscreen><verb>
- group-name { attribute1 attribute-value; attribute2 attribute-value; }
+ group-name { attribute1 attribute-value; attribute2 attribute-value; }
</verb></tscreen>
<sect1>Comments<p>
-Comments start with a hash mark (<tt/#/) and extend from the position of
+Comments start with a hash mark (<tt/#/); and, extend from the position of
the mark to the end of the current line. Hash marks inside of strings will
-of course <em/not/ start a comment.
+<em/not/ start a comment, of course.
<sect1>Specifying global options<label id="global-options"><p>
<tag><tt>END</tt></tag>
Followed by a numerical value. Specifies the end address of the segment. The
- end address is last the address that is part of the segment.
+ end address is the last address that is a part of the segment.
<tag><tt>NAME</tt></tag>
The attribute is followed by a string value which gives the name of the
segment.
</descrip>
-All attributes are mandatory. Segments may not overlap. Since there is no
-explicit "end this segment" pseudo op, the disassembler cannot notify the
-assembler that one segment has ended. This may lead to errors if you don't
-define your segments carefully. As a rule of thumb, if you're using segments,
-your should define segments for all disassembled code.
+All attributes are mandatory. Segments must not overlap. The disassembler will
+change back to the (default) <tt/.code/ segment after the end of each defined
+segment. That might not be what you want. As a rule of thumb, if you're using
+segments, you should define segments for all disassembled code.
<sect1>Specifying Assembler Includes<label id="infofile-asminc"><p>
symbol assignments in assembler syntax:
<tscreen><verb>
- Name = value
- Name := value
+ Name = value
+ Name := value
</verb></tscreen>
The usual conventions apply for symbol names. Values may be specified as hex
};
# One segment for the whole stuff
- SEGMENT { START $E000; END $FFFF; NAME kernal; };
+ SEGMENT { START $E000; END $FFFF; NAME "kernal"; };
- RANGE { START $E612; END $E631; TYPE Code; };
- RANGE { START $E632; END $E640; TYPE ByteTable; };
- RANGE { START $EA51; END $EA84; TYPE RtsTable; };
- RANGE { START $EC6C; END $ECAB; TYPE RtsTable; };
- RANGE { START $ED08; END $ED11; TYPE AddrTable; };
+ RANGE { START $E612; END $E631; TYPE Code; };
+ RANGE { START $E632; END $E640; TYPE ByteTable; };
+ RANGE { START $EA51; END $EA84; TYPE RtsTable; };
+ RANGE { START $EC6C; END $ECAB; TYPE RtsTable; };
+ RANGE { START $ED08; END $ED11; TYPE AddrTable; };
- # Zero page variables
- LABEL { NAME "fnadr"; ADDR $90; SIZE 3; };
- LABEL { NAME "sal"; ADDR $93; };
- LABEL { NAME "sah"; ADDR $94; };
- LABEL { NAME "sas"; ADDR $95; };
+ # Zero-page variables
+ LABEL { NAME "fnadr"; ADDR $90; SIZE 3; };
+ LABEL { NAME "sal"; ADDR $93; };
+ LABEL { NAME "sah"; ADDR $94; };
+ LABEL { NAME "sas"; ADDR $95; };
# Stack
- LABEL { NAME "stack"; ADDR $100; SIZE 255; };
+ LABEL { NAME "stack"; ADDR $100; SIZE 255; };
# Indirect vectors
- LABEL { NAME "cinv"; ADDR $300; SIZE 2; }; # IRQ
- LABEL { NAME "cbinv"; ADDR $302; SIZE 2; }; # BRK
- LABEL { NAME "nminv"; ADDR $304; SIZE 2; }; # NMI
+ LABEL { NAME "cinv"; ADDR $300; SIZE 2; }; # IRQ
+ LABEL { NAME "cbinv"; ADDR $302; SIZE 2; }; # BRK
+ LABEL { NAME "nminv"; ADDR $304; SIZE 2; }; # NMI
# Jump table at end of kernal ROM
- LABEL { NAME "kscrorg"; ADDR $FFED; };
- LABEL { NAME "kplot"; ADDR $FFF0; };
- LABEL { NAME "kiobase"; ADDR $FFF3; };
- LABEL { NAME "kgbye"; ADDR $FFF6; };
+ LABEL { NAME "kscrorg"; ADDR $FFED; };
+ LABEL { NAME "kplot"; ADDR $FFF0; };
+ LABEL { NAME "kiobase"; ADDR $FFF3; };
+ LABEL { NAME "kgbye"; ADDR $FFF6; };
# Hardware vectors
- LABEL { NAME "hanmi"; ADDR $FFFA; };
- LABEL { NAME "hares"; ADDR $FFFC; };
- LABEL { NAME "hairq"; ADDR $FFFE; };
+ LABEL { NAME "hanmi"; ADDR $FFFA; };
+ LABEL { NAME "hares"; ADDR $FFFC; };
+ LABEL { NAME "hairq"; ADDR $FFFE; };
</verb></tscreen>
-
-
<sect>Copyright<p>
-da65 (and all cc65 binutils) are (C) Copyright 1998-2007 Ullrich von
-Bassewitz. For usage of the binaries and/or sources the following
+da65 (and all cc65 binutils) is (C) Copyright 1998-2011, Ullrich von
+Bassewitz. For usage of the binaries and/or sources, the following
conditions do apply:
This software is provided 'as-is', without any expressed or implied
freely, subject to the following restrictions:
<enum>
-<item> The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-<item> Altered source versions must be plainly marked as such, and must not
- be misrepresented as being the original software.
-<item> This notice may not be removed or altered from any source
- distribution.
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
</enum>
</article>
-
-
-
-
<article>
<title>cc65 function reference
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
-<date>2014-05-26
+<date>2015-07-21
<abstract>
cc65 is a C compiler for 6502 based systems. This function reference describes
<tag/Declaration/Describes the needed header files and declaration of the
function.
<tag/Description/Description of the function.
-<tag/Limits/Limits.
+<tag/Notes/Notes on the function.
<tag/Availability/The availability of the function.
<tag/See also/Other related functions.
<tag/Example/A piece of actual code using the function.
<tag/Description/The function is called with the type of a directory entry
taken from a <tt/struct dirent/ and returns true if the entry designates
a directory.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
</itemize>
<tag/Availability/cc65
<tag/Description/The function is called with the type of a directory entry
taken from a <tt/struct dirent/ and returns true if the entry designates
a disk label.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
</itemize>
<tag/Availability/cc65
<tag/Description/The function is called with the type of a directory entry
taken from a <tt/struct dirent/ and returns true if the entry designates
a link.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
</itemize>
<tag/Availability/cc65
<tag/Description/The function is called with the type of a directory entry
taken from a <tt/struct dirent/ and returns true if the entry designates
a regular file.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>A "regular file" means anything with data in it. This might still mean
that special processing is needed, when accessing the file. Relative files of
<tag/Header/<tt/<ref id="stdlib.h" name="stdlib.h">/
<tag/Declaration/<tt/void __fastcall__ _heapadd (void* mem, size_t size);/
<tag/Description/The function adds a block of raw memory to the heap.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The minimum blocksize that can be added is 6 bytes; the function will
ignore smaller blocks.
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Description/The function returns the size of a block that must have
previously been allocated by <tt/<ref id="malloc" name="malloc">/, <tt/<ref
id="calloc" name="calloc">/ or <tt/<ref id="realloc" name="realloc">/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>Passing a pointer to a block that was is not the result of one of the
allocation functions, or that has been free'd will give unpredicable results.
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
</itemize>
<tag/Availability/cc65
<tag/See also/
<descrip>
<tag/Function/Return the total available space on the heap.
<tag/Header/<tt/<ref id="stdlib.h" name="stdlib.h">/
-<tag/Declaration/<tt/size_t __fastcall__ _heapmemavail (void);/
+<tag/Declaration/<tt/size_t _heapmemavail (void);/
<tag/Description/The function returns the total number of bytes available on
the heap.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>This function is of less use than usually assumed, since the returned
heap space may be available but not in one block. So even if this function
says that several times more heap space is available than needed, <ref
<tt/_oserror/ are printed followed by a newline. The message output is the
same as returned by <tt/<ref id="_stroserror" name="_stroserror">/ with an
argument of <tt/_oserror/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>Since operating system specific error code are - you guessed it -
operating system specific, the value in <tt/_oserror/ and the message that is
printed depends on the cc65 target.
<tag/Description/The function initializes the random number generator with
a seed derived from fast changing hardware events, so the seed itself can be
considered random to a certain degree.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The randomness of the seed depends on the machine hardware.
</itemize>
<tag/Availability/cc65
<tag/Declaration/<tt/const char* __fastcall__ _stroserror (unsigned char errcode);/
<tag/Description/<tt/_stroserror/ will return a string describing the given
operating system specific error code.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Since operating system specific error code are - you guessed it -
operating system specific, the parameter and the string returned depend on the
cc65 target.
<tag/Description/<tt/_swap/ will swap (exchange) the contents of the two memory
areas pointed to by <tt/p/ and <tt/q/. Both memory areas are assumed to be
<tt/size/ bytes in size.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The memory areas may not overlap, otherwise the results are undefined.
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
registers and the CPU flags are set to the values given in the <tt/regs/
structure. On return from the subroutine, the new values of the registers and
flags are stored back overwriting the old values.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Bits 4 and 5 of the flags value in the <tt/regs/ structure are ignored
when calling the subroutine (they are unchanged from their current values).
<item>The function is only available as fastcall function, so it may only be
<tag/Declaration/<tt/void BRK (void);/
<tag/Description/The function will insert a 6502 BRK instruction into the code
which may be used to trigger a debugger.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>The inserted instruction may lead to unexpected results if no debugger
is present.
<tag/Description/The function will insert a 6502 CLI instruction into the code,
so interrupts are enabled. Enabling interrupts has no effects if they are
already enabled (the default).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>Disabling interrupts may lead to unexpected results.
</itemize>
<tag/Declaration/<tt/unsigned char PEEK (unsigned addr);/
<tag/Description/The function will read the absolute memory given by <tt/addr/
and return the value read.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>This function depends highly on the platform and environment.
</itemize>
<tag/Description/The function will read the absolute memory given by <tt/addr/
and return the value read. The byte read from the higher address is the high
byte of the return value.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>This function depends highly on the platform and environment.
<item>The order in which the two bytes are read is unspecified and may
<tag/Declaration/<tt/void POKE (unsigned addr, unsigned char val);/
<tag/Description/The function writes the value <tt/val/ to the absolute
memory address given by <tt/addr/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>This function depends highly on the platform and environment.
<item>Careless use will cause the program to act strange or may crash the
<tag/Description/The function writes the value <tt/val/ to the absolute
memory address given by <tt/addr/. The low byte of <tt/val/ is written to
the <tt/addr/, the high byte is written to <tt/addr+1/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>This function depends highly on the platform and environment.
<item>Careless use will cause the program to act strange or may crash the
<tag/Description/The function will insert a 6502 SEI instruction into the code,
so interrupts are disabled. Note that non maskable interrupts cannot be
disabled.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
<item>Disabling interrupts may lead to unexpected results.
</itemize>
<tag/Declaration/<tt/int __fastcall__ abs (int v);/
<tag/Description/<tt/abs/ returns the absolute value of the argument passed to
the function.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The return value is undefined if <tt/INT_MIN/ is passed to the function.
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
<tag/Description/<tt/assert/ is a macro that expands to a <tt/id/
statement. If the condition evaluates t zero (false), assert prints a message
on stderr and aborts the program.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
</itemize>
<tag/Availability/ISO 9899
terminates, they are called in LIFO order (the last function registered is
called first). <tt/atexit/ returns zero on success and a nonzero value on
failure.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>A maximum of 5 exit functions can be registered.
<item>There is no way to unregister an exit function.
<item>The function is only available as fastcall function, so it may only be
<tag/Header/<tt/<ref id="atmos.h" name="atmos.h">/
<tag/Declaration/<tt/void __fastcall__ atmos_load(const char* name);/
<tag/Description/<tt/atmos_load/ reads a memory block from tape.
+<tag/Notes/<itemize>
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
+</itemize>
<tag/Availability/cc65
<tag/See also/
<ref id="atmos_save" name="atmos_save">
<tag/Header/<tt/<ref id="atmos.h" name="atmos.h">/
<tag/Declaration/<tt/void __fastcall__ atmos_save(const char* name, const void* start, const void* end);/
<tag/Description/<tt/atmos_save/ writes a memory block to tape.
+<tag/Notes/<itemize>
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
+</itemize>
<tag/Availability/cc65
<tag/See also/
<ref id="atmos_load" name="atmos_load">
<tag/Declaration/<tt/int __fastcall__ atoi (const char* s);/
<tag/Description/<tt/atoi/ converts the given string into an integer.
Conversion stops as soon as any invalid character is encountered.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There is no way to detect any conversion errors.
<item>The function does not check for an numerical overflow when converting.
<item>The function is only available as fastcall function, so it may only be
<tag/Declaration/<tt/long __fastcall__ atol (const char* s);/
<tag/Description/<tt/atol/ converts the given string into a long integer.
Conversion stops as soon as any invalid character is encountered.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There is no way to detect any conversion errors.
<item>The function does not check for an numerical overflow when converting.
<item>The function is only available as fastcall function, so it may only be
<tag/Description/The function will set a new background color and return the
old (current) one. The background color is valid for the whole text output
area of the screen, not just for new text.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Background colors are system dependent. The function may have no effect
on systems where the background color cannot be changed.
<item>The function is only available as fastcall function, so it may only be
<tag/Declaration/<tt/unsigned char __fastcall__ bordercolor (unsigned char color);/
<tag/Description/The function will set a new border color. It returns the old
(current) border color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Border colors are system dependent. The function may have no effect
on systems where the border color cannot be changed.
<item>The function is only available as fastcall function, so it may only
<tag/Header/<tt/<ref id="stdlib.h" name="stdlib.h">/
<tag/Declaration/<tt/void* __fastcall__ bsearch (const void* key,
const void* base, size_t n, size_t size,
-int (*cmp) (const void*, const void*));/
+int __fastcall__ (* cmp) (const void*, const void*));/
<tag/Description/<tt/bsearch/ searches a sorted array for a member that
matches the one pointed to by <tt/key/. <tt/base/ is the address of the array,
<tt/n/ is the number of elements, <tt/size/ the size of an element and <tt/cmp/
the function used to compare the members against the key. The function returns
a pointer to the member found, or <tt/NULL/ if there was no match.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The contents of the array must be sorted in ascending order according to
the compare function given.
<item>If there are multiple members that match the key, the function will
return one of the members.
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
+<item>The function to which <tt/cmp/ points must have the <tt/fastcall/ calling
+convention.
</itemize>
<tag/Availability/ISO 9899
<tag/See also/
<tag/Declaration/<tt/void __fastcall__ bzero (void* p, size_t count);/
<tag/Description/<tt/bzero/ fills the memory area pointed to by <tt/p/ with
zero.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is non standard and therefore only available in non ANSI
mode. You should use <tt/<ref id="memset" name="memset">/ instead.
<item>The function is only available as fastcall function, so it may only
<tag/Header/<tt/<ref id="c128.h" name="c128.h">/
<tag/Declaration/<tt/void c64mode (void);/
<tag/Description/The function will cause the machine to reboot into C64 mode.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is specific to the C128.
<item>The function will not return to the caller.
</itemize>
of size <tt/size/, clears the whole block with binary zeroes and returns a
pointer to it. On error (not enough memory available), <tt/calloc/ returns
<tt/NULL/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>Clearing the memory may not have the expected effect on all platforms:
pointers in the block may not be <tt/NULL/ and floating point variables may
not be zero (0.0). In other words: The "clearing" effect of this function
gets from the current TALKer on the serial bus.
In order to receive the data, the device must have previously been
sent a command to TALK and a secondary address if it needs one.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
Device must first have been OPENed and then designated as the input channel by the CHKIN routine.
When this function is called, the next byte of data available from the device is returned.
Exception is the routine for the keyboard device (which is the default input device).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
cassette is the current device, outputting a byte will only add it to
the buffer. No actual transmission of data will occur until the
192-byte buffer is full.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
channel is a serial device, which requires a TALK command and
sometimes a secondary address, function will send them over the
serial bus.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
current character, and defers sending it until the next byte is
buffered. When the UNLISTEN command is sent, the last byte will be
sent with an End or Identify (EOI).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
the current secondary address. If the device on the channel uses the
serial bus, and therefore requires a LISTEN command and possibly a
secondary address, this information will be sent on the bus.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Description/It closes all
open files, by resetting the index into open files to
zero and restores the default I/O devices.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
<tag/Description/It is used to
close a logical file after all I/O operations involving that file have
been completed.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
device, the routine sends it an UNTALK command on the serial bus, and
if a serial device was formerly the current output device, the routine
sends it an UNLISTEN command.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
<tag/Header/<tt/<ref id="cbm.h" name="cbm.h">/
<tag/Declaration/<tt/unsigned char cbm_k_getin (void);/
<tag/Description/Function gets a character from the current input device.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
a program are set by a call to this function, they should
still remain compatible with future versions of the Commodore 64, the
KERNAL and BASIC.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
to convert it to a listen address, then transmits this data as a command on
the serial bus. The specified device will then go into listen mode, and
be ready to accept information.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
Function returns the address of the highest RAM location loaded.
Before this function can be called, the KERNAL SETLFS, and SETNAM
routines must be called.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
the device number, and the secondary address if any, the cbm_k_setlfs() function must first be called.
Likewise, in order to designate the filename, the cbm_k_setnam() function must be used first. After these two
functions are called, cbm_k_open() is then called.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
<tag/Header/<tt/<ref id="cbm.h" name="cbm.h">/
<tag/Declaration/<tt/unsigned char cbm_k_readst (void);/
<tag/Description/This function returns the current status of the I/O devices. It is usually called after new communication to an I/O device and gives information about device status, or errors that have occurred during the I/O operation.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
used before calling this function. However, a file name is not required to
SAVE to device 1 (the Datassette(TM) recorder). Any attempt to save to
other devices without using a file name results in an error. NOTE: Device 0 (the keyboard), device 2 (RS-232), and device 3 (the screen) cannot be SAVEd to. If the attempt is made, an error occurs, and the SAVE is stopped.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ cbm_k_setlfs (unsigned char LFN, unsigned char DEV, unsigned char SA);/
<tag/Description/This functions sets up the logical file by setting its number, device address,
and secondary address.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ cbm_k_setnam (const char* Name);/
<tag/Description/This function is used to set up the file name for the OPEN,
SAVE, or LOAD operations.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ cbm_k_talk (unsigned char dev);/
<tag/Description/When called, it ORs the device number with the TALK code (64, $40) and sends it on the serial
bus. This commands the device to TALK.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
function is normally used after the host computer is finished sending data
to external devices. Sending the UNLISTEN commands the listening devices
to get off the serial bus so it can be used for other purposes.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>
</itemize>
<tag/Availability/cc65
<tag/Declaration/<tt/void __fastcall__ cclear (unsigned char length);/
<tag/Description/The function clears part of a line by writing <tt/length/
spaces in the current text color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Description/The function moves the cursor to a specific position, and
will then clear part of the line by writing <tt/length/ spaces in the current
text color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
no character available, <tt/cgetc/ waits until the user presses a key. If the
cursor is enabled by use of the <tt/cursor/ function, a blinking cursor is
displayed while waiting.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>If the system supports a keyboard buffer, <tt/cgetc/ will fetch a key
from this buffer and wait only if the buffer is empty.
</itemize>
<tag/Declaration/<tt/void __fastcall__ chline (unsigned char length);/
<tag/Description/The function outputs a horizontal line with the given length
starting at the current cursor position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The character used to draw the horizontal line is system dependent.
If available, a line drawing character is used. Drawing a line that is partially
off screen leads to undefined behaviour.
<tag/Declaration/<tt/void __fastcall__ chlinexy (unsigned char x, unsigned char y, unsigned char length);/
<tag/Description/The function outputs a horizontal line with the given length
starting at a given position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The character used to draw the horizontal line is system dependent.
If available, a line drawing character is used. Drawing a line that is partially
off screen leads to undefined behaviour.
<tag/Declaration/<tt/void __fastcall__ clearerr (FILE* f);/
<tag/Description/<tt/clearerr/ clears the error and end-of-file status
indicators for the stream <tt/f/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
time used by the program. The time is returned in implementation defined
units. It can be converted to seconds by dividing by the value of the macro
<tt/CLOCKS_PER_SEC/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Since the machines, cc65 generated programs run on, cannot run multiple
processes, the function will actually return the time since some
implementation defined point in the past.
<tag/Description/The function closes the given file descriptor. It returns zero
on success and -1 on error. If an error occurs, the cause can be determined by
reading the <tt/errno/ variable.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/The function closes the given directory descriptor. It returns
zero on success and -1 on error. If an error occurs, the cause can be determined
by reading the <tt/errno/ variable.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/<tt/creat/ creates a new file and returns the file descriptor
associated with it. On error, -1 is returned and an error code is stored in
<tt/errno/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item><tt/creat/ is identical to calling <tt/<ref id="open" name="open">/ with
<tt/flags/ equal to <tt/O_WRONLY | O_CREAT | O_TRUNC/.
<item>The function is only available as fastcall function, so it may only
formatted according to the format string given. The resulting string is output
to the console. <tt/cprintf/ supports the same format specifiers as
<tt/printf/. <!-- <tt/<ref id="printf" name="printf">/. -->
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/cprintf/ distinguishes
between <tt/\r/ and <tt/\n/.
</itemize>
<tag/Declaration/<tt/void __fastcall__ cputc (char c);/
<tag/Description/Output one character to the console at the current cursor
position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/cputc/ distinguishes
between <tt/\r/ and <tt/\n/.
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);/
<tag/Description/<tt/cputcxy/ moves the cursor to the given x/y position on
the screen and outputs one character.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/cputcxy/ distinguishes
between <tt/\r/ and <tt/\n/.
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void __fastcall__ cputs (const char* s);/
<tag/Description/The function outputs the given string on the console at the
current cursor position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/cputs/ distinguishes
between <tt/\r/ and <tt/\n/.
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void __fastcall__ cputsxy (unsigned char x, unsigned char y, const char* s);/
<tag/Description/<tt/cputsxy/ moves the cursor to the given x/y position,
and outputs the string <tt/s/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/cputsxy/ distinguishes
between <tt/\r/ and <tt/\n/.
<item>The function is only available as fastcall function, so it may only
<tag/Description/If the argument to the function is non zero, a blinking cursor
will be enabled when the <tt/cgetc/ function waits for input from the keyboard.
If the argument is zero, <tt/cgetc/ will wait without a blinking cursor.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ cvline (unsigned char length);/
<tag/Description/The function outputs a vertical line with the given length
starting at the current cursor position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The character used to draw the vertical line is system dependent.
If available, a line drawing character is used. Drawing a line that is partially
off screen leads to undefined behaviour.
<tag/Declaration/<tt/void __fastcall__ cvlinexy (unsigned char x, unsigned char y, unsigned char length);/
<tag/Description/The function outputs a vertical line with the given length
starting at a given position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The character used to draw the vertical line is system dependent.
If available, a line drawing character is used. Drawing a line that is partially
off screen leads to undefined behaviour.
<tag/Declaration/<tt/div_t __fastcall__ div (int numer, int denom);/
<tag/Description/<tt/div/ divides <tt/numer/ by <tt/denom/ and returns the
quotient and remainder in a <tt/div_t/ structure.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
if <tt/<ref id="em_map" name="em_map">/, <tt/<ref id="em_use" name="em_use">/,
<tt/<ref id="em_copyfrom" name="em_copyfrom">/ or <tt/<ref id="em_copyto"
name="em_copyto">/ are called without calling <tt/em_commit/ first.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling <tt/em_commit/ does not necessarily mean that changes to the
memory window are discarded, it does just mean that the drivers is allowed
to discard it.
<tag/Description/Copy data from extended memory into linear memory. Source and
target addresses as well as the number of bytes to transfer are specified in
the <tt/em_copy/ structure that is passed as a parameter.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling <tt/em_copyfrom/ will invalidate the memory window, so if you
made any changes to the data in the window, call <tt/<ref id="em_commit"
name="em_commit">/ first, or the changes are lost.
<tag/Description/Copy data from linear into extended memory. Source and
target addresses as well as the number of bytes to transfer are specified in
the <tt/em_copy/ structure that is passed as a parameter.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling <tt/em_copyto/ will invalidate the memory window, so if you
made any changes to the data in the window, call <tt/<ref id="em_commit"
name="em_commit">/ first, or the changes are lost.
<tag/Description/The function installs an already loaded extended memory driver
and returns an error code. The function may be used to install a driver linked
statically to the program.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Not all drivers are able to detect if the supported hardware is really
present.
<item>The function is only available as fastcall function, so it may only be
<tag/Description/Load an extended memory driver into memory and initialize
it. The function returns an error code that tells if all this has been
successful.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Not all drivers are able to detect if the supported hardware is really
present.
<item>The function is only available as fastcall function, so it may only be
because you're going to overwrite it completely), it is better to call
<tt/<ref id="em_use" name="em_use">/ instead. <tt/em_use/ will not transfer the
data if it is possible to avoid that.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling <tt/em_map/ will invalidate the memory window, so if you
made any changes to the data in the window, call <tt/<ref id="em_commit"
name="em_commit">/ first, or the changes are lost.
<tag/Declaration/<tt/unsigned em_pagecount (void);/
<tag/Description/The function returns the size of the extended memory supported
by the driver in 256 byte pages.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function returns zero if no extended memory driver is loaded.
<item>The function may return zero if the supported hardware was not detected.
</itemize>
<tag/Declaration/<tt/unsigned char em_uninstall (void);/
<tag/Description/The function uninstalls an already loaded extended memory
driver but doesn't remove it from memory.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>If the driver has been loaded using <tt/<ref id="em_load_driver"
name="em_load_driver">/, <tt/<ref id="em_unload" name="em_unload">/
should be used instead of <tt/em_uninstall/ so the driver is also removed
<tag/Declaration/<tt/unsigned char em_unload (void);/
<tag/Description/The function unloads a loaded extended memory driver and
frees all memory allocated for the driver.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function does nothing if no driver is loaded.
</itemize>
<tag/Availability/cc65
<tt/<ref id="em_map" name="em_map">/, but will not transfer data into the
actual memory window in the assumption that the existing data is wrong or
will get overwritten.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling <tt/em_use/ will invalidate the memory window, so if you
made any changes to the data in the window, call <tt/<ref id="em_commit"
name="em_commit">/ first, or the changes are lost.
name="atexit">/ are called. Common values for status are <tt/EXIT_SUCCESS/ and
<tt/EXIT_FAILURE/ which are also defined in <tt/<ref id="stdlib.h"
name="stdlib.h">/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>It depends on the host machine if the program return code can be
a <tt/NULL/ pointer may be passed as second parameter.
On success, the function does not return. On failure, -1 is returned and
<tt/errno/ contains an error code.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>On most platforms, the function needs to copy a small stub loader to
<tag/Declaration/<tt/void fast (void);/
<tag/Description/The function will switch the clock of the C128 to 2MHz. This
will nearly double the speed compared to slow mode.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is specific to the C128.
<item>2MHz clock will not work in 40 column mode.
</itemize>
<tag/Declaration/<tt/int __fastcall__ feof (FILE* f);/
<tag/Description/<tt/feof/ tests the end-of-file indicator ofthe stream
<tt/f/, and returns a non zero value if it is set.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The indicator is set only after a read past the end of a file is
attempted.
<item>The function is only available as fastcall function, so it may only be
<tag/Declaration/<tt/int __fastcall__ ferror (FILE* f);/
<tag/Description/<tt/ferror/ tests the error indicator of the stream
<tt/f/, and returns a non zero value if it is set.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
<tag/Description/The <tt/fileno/ function returns the file handle used
internally by a C stream. This file handle (an integer) can be used as a
handle for the POSIX input/output functions.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
<item>Mixing C file I/O functions and POSIX file I/O functions for the same
<tt/<ref id="malloc" name="malloc">/, <tt/<ref id="calloc" name="calloc">/
or <tt/<ref id="realloc" name="realloc">/. As an exception, if the passed
pointer is <tt/NULL/, no action is performed.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>Passing an already free'd block to <tt/free/ again will cause undefined
behaviour and may crash your program.
<item>The function is only available as fastcall function, so it may only
all supported targets. If it exists, it returns a number that identifies the
operating system or machine type, the program runs on. The machine dependent
header files define constants that can be used to check the return code.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function does not exist on all platforms.
<item>The return codes are platform dependent.
</itemize>
<item><tt/CPU_65C02/
<item><tt/CPU_65816/
</itemize>
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Other, more exotic CPU types are not disinguished.
</itemize>
<tag/Availability/cc65
matches <tt/name/ and returns its value. The environment consists of a list
of strings in the form <tt/name=value/. If there is no match, <tt/getenv/
returns <tt/NULL/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>What exactly is stored in the environment depends on the machine the
program is running on.
<item>The function is only available as fastcall function, so it may only
found on the command line and <tt/EOF/ (-1) if there is no other option. An
option argument is placed in <tt/optarg/, the index of the next element on the
command line to be processed is placed in <tt/optind/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The implementation will not reorder options. A non option on the command
line will terminate option processing. All remaining arguments are not
recognized as options, even if the start with a '-' character.
<tag/Description/The function moves the text mode cursor to the specified X
position while leaving the Y position untouched. The leftmost position on the
screen has the coordinate 0.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
<item>Invalid values for the X position (out of screen coordinates) may
<tag/Description/The function moves the text mode cursor to the specified
position. The leftmost position on the screen has the X coordinate 0, the
topmost line has the Y coordinate 0.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
<item>Invalid values for any of both coordinates (out of screen positions) may
<tag/Description/The function moves the text mode cursor to the specified Y
position while leaving the X position untouched. The uppermost position on the
screen has the coordinate 0.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
<item>Invalid values for the Y position (out of screen coordinates) may lead
<tag/Description/The function returns a non zero value if the given argument
is a letter or digit. The return value is zero if the character is anything
else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Declaration/<tt/int __fastcall__ isalpha (int c);/
<tag/Description/The function returns a non zero value if the given argument
is a letter. The return value is zero if the character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Declaration/<tt/int __fastcall__ isascii (int c);/
<tag/Description/The function returns a non zero value if the given argument
is in the range 0..127 (the range of valid ASCII characters) and zero if not.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a space or tab character. The return value is zero if the character is
anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<item>When compiling without <tt/-Os/, the function is only available as
fastcall function, so it may only be used in presence of a prototype.
</itemize>
-<tag/Availability/cc65
+<tag/Availability/ISO 9899
<tag/See also/
<ref id="isalnum" name="isalnum">,
<ref id="isalpha" name="isalpha">,
<tag/Description/The function returns a non zero value if the given argument
is a control character. The return value is zero if the character is anything
else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Declaration/<tt/int __fastcall__ isdigit (int c);/
<tag/Description/The function returns a non zero value if the given argument
is a digit. The return value is zero if the character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a printable character with the exception of space. The return value is zero
if the character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a lower case letter. The return value is zero if the character is anything
else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a printable character (this includes the space character). The return value
is zero if the character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a printable character, but not a space or anything alphanumeric. The return
value is zero if the character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
anything else. The standard white space characters are: space, formfeed ('\f'),
newline ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab
('\v').
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is an upper case letter. The return value is zero if the character is anything
else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Description/The function returns a non zero value if the given argument
is a hexadecimal digit (0..9, a..f and A..F). The return value is zero if the
character is anything else.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>When compiling with <tt/-Os/ the function is actually a macro. The
inline sequence generated by the macro will not work correctly for values
outside the range 0..255. <em/Note:/ The constant <tt/EOF/ is not part of
<tag/Declaration/<tt/char* __fastcall__ itoa (int val, char* buf, int radix);/
<tag/Description/<tt/itoa/ converts the integer <tt/val/ into a string using
<tt/radix/ as the base.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There are no provisions to prevent a buffer overflow.
<item>If <tt/val/ contains <tt/INT_MIN/, the behaviour is undefined.
<item>The function is non standard, so it is not available in strict ANSI mode.
<tag/Declaration/<tt/unsigned char joy_count (void);/
<tag/Description/The function returns a the number of joysticks supported
by the current joystick driver.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>A joystick driver must be loaded using <ref id="joy_load_driver"
name="joy_load_driver"> before calling this function.
<item>The function returns the number of joysticks supported by the driver.
<tag/Description/The function installs a driver that was already loaded into
memory (or linked statically to the program). It returns an error code
(<tt/JOY_ERR_OK/ in case of success).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
<tag/Description/The function loads a driver with the given name from disk
and installs it. An error code is returned, which is <tt/JOY_ERR_OK/ if the
driver was successfully loaded and installed.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
<tag/Description/The function reads the status bits for a joystick. The number
of the joystick is passed as parameter. The result may be examined by using one
of the <tt/JOY_xxx/ macros from <ref id="joystick.h" name="joystick.h">.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>A joystick driver must be loaded using <ref id="joy_load_driver"
name="joy_load_driver"> before calling this function.
<item>The function is only available as fastcall function, so it may only be
<tag/Description/The function uninstalls the currently installed joystick
driver. It does not remove the driver from memory. The function returns an
error code, which is <tt/JOY_ERR_OK/ if the driver was successfully uninstalled.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>A joystick driver must be installed using <ref id="joy_install"
name="joy_install"> before calling this function.
</itemize>
<tag/Description/The function uninstalls the currently installed joystick
driver and removes it from memory. An error code is returned, which is
<tt/JOY_ERR_OK/ if the driver was successfully uninstalled.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>A joystick driver must be loaded using <ref id="joy_load_driver"
name="joy_load_driver"> before calling this function.
</itemize>
<tag/Declaration/<tt/unsigned char kbhit (void);/
<tag/Description/The function returns a value of zero if there is no character
waiting to be read from the keyboard. It returns non zero otherwise.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>If the system does not support a keyboard buffer (most systems
do), the function is rather useless.
</itemize>
<tag/Declaration/<tt/long __fastcall__ labs (long v);/
<tag/Description/<tt/labs/ returns the absolute value of the argument passed to
the function.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The return value is undefined if <tt/LONG_MIN/ is passed to the function.
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
<tag/Declaration/<tt/char* __fastcall__ ltoa (long val, char* buf, int radix);/
<tag/Description/<tt/itoa/ converts the long integer <tt/val/ into a string
using <tt/radix/ as the base.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There are no provisions to prevent a buffer overflow.
<item>If <tt/val/ contains <tt/LONG_MIN/, the behaviour is undefined.
<item>The function is non standard, so it is not available in strict ANSI mode.
<tag/Declaration/<tt/struct lconv* localeconv (void);/
<tag/Description/<tt/localeconv/ returns a pointer to the current locale
structure.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>cc65 supports only the "C" locale, so even after setting a new locale
using <tt/<ref id="setlocale" name="setlocale">/, the structure returned will
always be the same.
<tt/<ref id="setjmp" name="setjmp">/. Program execution continues as if the
call to <tt/<ref id="setjmp" name="setjmp">/ has just returned the value
<tt/retval/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>If the parameter <tt/retval/ is zero, the function will behave as if it
was called with a value of one.
<item>The function is only available as fastcall function, so it may only
<tag/Description/<tt/malloc/ allocates size bytes on the heap and returns a
pointer to the allocated memory block. On error (not enough memory available),
<tt/malloc/ returns <tt/NULL/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
(converted to a char) in the block of raw memory string pointed to by <tt/mem/
that is of size <tt/count/. Upon completion, the function returns a pointer to
the character found, or a null pointer if the character was not found.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
pointed to by <tt/p1/ into the memory area pointed to by <tt/p2/. It returns a value that is less than
zero if <tt/p1/ is less than <tt/p2/, zero if <tt/p1/ is the same as <tt/p2/,
and a value greater than zero if <tt/p1/ is greater than <tt/p2/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/<tt/memcpy/ copies <tt/count/ bytes from the memory area
pointed to by <tt/src/ into the memory area pointed to by <tt/dest/. It returns
<tt/dest/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The result is undefined if the memory areas do overlap. Use
<tt/<ref id="memmove" name="memmove">/ to copy overlapping memory areas.
<item>The function is only available as fastcall function, so it may only
<tag/Description/<tt/memmove/ copies <tt/count/ bytes from the memory area
pointed to by <tt/src/ into the memory area pointed to by <tt/dest/. It returns
<tt/dest/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>While <tt/memmove/ allows the memory areas to overlap, it has some
additional overhead compared to <tt/<ref id="memcpy" name="memcpy">/.
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void* __fastcall__ memset (void* p, int val, size_t count);/
<tag/Description/<tt/memset/ fills the memory area pointed to by <tt/p/ with
the value <tt/val/. The function returns <tt/p/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ mod_free (void* module);/
<tag/Description/The function will free a module loaded into memory by use of
the <tt/<ref id="mod_load" name="mod_load">/ function.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The pointer passed as parameter is the pointer to the module memory,
not the pointer to the control structure.
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
</itemize>
<tag/Availability/cc65
<tag/See also/
<descrip>
<tag/Function/Load a relocatable module.
<tag/Header/<tt/<ref id="modload.h" name="modload.h">/
-<tag/Declaration/<tt/unsigned char mod_load (struct mod_ctrl* ctrl);/
+<tag/Declaration/<tt/unsigned char __fastcall__ mod_load (struct mod_ctrl* ctrl);/
<tag/Description/The function will load a code module into memory and relocate
it. The function will return an error code. If <tt/MLOAD_OK/ is returned, the
outgoing fields in the passed <tt/mod_ctrl/ struct contain information about
<item><tt/MLOAD_ERR_FMT/ - Data format error
<item><tt/MLOAD_ERR_MEM/ - Not enough memory
</itemize>
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The <htmlurl url="ld65.html" name="ld65"> linker is needed to create
relocatable o65 modules for use with this function.
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Header/<tt/<ref id="mouse.h" name="mouse.h">/
<tag/Declaration/<tt/void __fastcall__ mouse_setbox (const struct mouse_box* box);/
<tag/Description/The function allows to set a bounding box for mouse movement.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function does not check if the mouse cursor is currently within the
given rectangle. Placing the mouse cursor within the bounding box is the
responsibility of the programmer.
<tag/Declaration/<tt/void __fastcall__ mouse_getbox (struct mouse_box* box);/
<tag/Description/The function queries the current bounding box for mouse
movement.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
code);/
<tag/Description/The function returns an error message (in english) for the
error code passed parameter.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function will return "Unknown error" for invalid error codes.
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
<tag/Declaration/<tt/void __fastcall__ mouse_info (struct mouse_info* info);/
<tag/Description/The function returns the state of the mouse buttons and the
position of the mouse in the <tt/mouse_info/ structure passed as parameter.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The <tt/mouse_info/ struct is a superset of the <tt/mouse_pos/ struct,
so if you just need the mouse position, call <tt/<ref id="mouse_pos"
name="mouse_pos">/ instead.
can live with these defaults (which are platform specific), just pass a
pointer to <tt/mouse_def_callbacks/. The function may be used to install a
driver linked statically to the program.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Not all drivers are able to detect if the supported hardware is really
present.
<item>After installing a driver, the mouse cursor is hidden.
function returns an error code. The purpose of this function is to allow
for driver specific extensions. See the documentation for a specific mouse
driver for supported ioctl calls.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Calling this function is non portable, because each driver may
implement different ioctl calls (or none at all).
<item>The function is only available as fastcall function, so it may only be
routines needed to move or hide/show the mouse pointer. Defaults for these
routines are supplied by the library, so if you can live with these defaults
(which are platform specific), just pass a pointer to <tt/mouse_def_callbacks/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The driver is loaded by name, so currently you must know the type of
mouse that should be supported. There is no autodetect capability.
<item>Not all drivers are able to detect if the supported hardware is really
<tag/Declaration/<tt/void __fastcall__ mouse_move (int x, int y);/
<tag/Description/The function updates the mouse position. If the mouse cursor
is visible, it is shown at the new position.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function does not check if the new position is within the bounding
box specified with <tt/<ref id="mouse_setbox" name="mouse_setbox">/.
<item>The function is only available as fastcall function, so it may only be
<tag/Declaration/<tt/void __fastcall__ mouse_pos (struct mouse_pos* pos);/
<tag/Description/The function returns the position of the mouse in the
<tt/mouse_pos/ structure passed as parameter.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The <tt/mouse_pos/ struct is a subset of the <tt/mouse_info/ struct,
so if you do also need the mouse buttons, call <tt/<ref id="mouse_info"
name="mouse_info">/ instead.
<tag/Declaration/<tt/unsigned char mouse_uninstall (void);/
<tag/Description/The function uninstalls an already loaded mouse driver but
don't removes it from memory.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>If the driver has been loaded using <tt/<ref id="mouse_load_driver"
name="mouse_load_driver">/, <tt/<ref id="mouse_unload" name="mouse_unload">/
should be used instead of <tt/mouse_uninstall/ so the driver is also removed
<descrip>
<tag/Function/Unload a mouse driver.
<tag/Header/<tt/<ref id="mouse.h" name="mouse.h">/
-<tag/Declaration/<tt/unsigned char __fastcall__ mouse_unload (void);/
+<tag/Declaration/<tt/unsigned char mouse_unload (void);/
<tag/Description/The function unloads a loaded mouse driver and frees all
memory allocated for the driver.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function does nothing if no driver is loaded.
</itemize>
<tag/Availability/cc65
<tag/Declaration/<tt/size_t offsetof (type, member);/
<tag/Description/<tt/offsetof/ calculates the address offset of a <tt/struct/
or <tt/union/ member.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is actually a macro.
</itemize>
<tag/Availability/ISO 9899
<tag/Description/<tt/open/ opens a file and returns the file descriptor
associated with it. On error, -1 is returned and an error code is stored in
<tt/errno/. Several flags may be passed to <tt/open/ that change the behaviour.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>POSIX specifies an additional <tt/mode/ argument that may be passed to
open, which is used as the permission mask when a new file is created. While
cc65 allows to pass this argument, it is ignored.
<tag/Description/<tt/opendir/ opens a directory and returns the direcory
descriptor associated with it. On error, NULL is returned and an error code is
stored in <tt/errno/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/unsigned char __fastcall__ peekbsys (unsigned addr);/
<tag/Description/<tt/peekbsys/ reads one byte from the given address in the
system bank (bank 15) of the CBM PET-II machines and returns it.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>This function may be a macro depending on the compiler options. The
system bank (bank 15) of the CBM PET-II machines and returns it. Following
the usual 6502 conventions, the low byte is read from <tt/addr/, and the
high byte is read from <tt/addr+1/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The order in which the two bytes are read is undefined.
a blank. Then the error message for the current contents of <tt/errno/ is
printed followed by a newline. The message output is the same as returned by
<tt/<ref id="strerror" name="strerror">/ with an argument of <tt/errno/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ pokebsys (unsigned addr, unsigned char val);/
<tag/Description/<tt/pokebsys/ writes one byte to the given address in the
system bank (bank 15) of the CBM PET-II machines.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
system bank (bank 15) of the CBM PET-II machines. Following the usual 6502
conventions, the low byte of <tt/val/ is written to <tt/addr/, and the
high byte is written to <tt/addr+1/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The order in which the two bytes are written is undefined.
<tag/Function/Sort an array.
<tag/Header/<tt/<ref id="stdlib.h" name="stdlib.h">/
<tag/Declaration/<tt/void __fastcall__ qsort (void* base, size_t count,
-size_t size, int (*compare) (const void*, const void*));/
+size_t size, int __fastcall__ (* compare) (const void*, const void*));/
<tag/Description/<tt/qsort/ sorts an array according to a given compare
function <tt/compare/. <tt/base/ is the address of the array, <tt/count/
is the number of elements, <tt/size/ the size of an element and <tt/compare/
the function used to compare the members.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>If there are multiple members with the same key, the order after calling
the function is undefined.
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
+<item>The function to which <tt/compare/ points must have the <tt/fastcall/
+calling convention.
</itemize>
<tag/Availability/ISO 9899
<tag/See also/
will be executed. If no handler has been installed, the default action for
the raised signal will be taken. The function returns zero on success,
nonzero otherwise.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/int rand (void);/
<tag/Description/The function returns a pseudo random number
between 0 and <tt/RAND_MAX/ (exclusive).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Without using <tt><ref id="srand" name="srand"></tt>, always the same
flow of numbers is generated.
<item>On startup, the function behaves as if <ref id="srand" name="srand">
and returns a pointer to it. If the end of directory is reached, or an error
occurs, NULL is returned. In case of errors, an error code is stored into
<tt/errno/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The returned pointer may point to a statically allocated instance of
behaves as if <tt/malloc/ had been called. If <tt/size/ is zero, <tt/realloc/
behaves as if <tt/free/ had been called. On error (not enough memory
available), <tt/realloc/ returns <tt/NULL/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The part of the memory block that is returned will have its contents
unchanged.
<item>This function is somewhat dangerous to use. Be careful to save the
<tag/Description/<tt/remove/ deletes the file with the given name. On success,
zero is returned. On error, -1 is returned and <tt/errno/ is set to an error
code describing the reason for the failure.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>This function is not available on all cc65 targets (depends on the
availability of file I/O).
<item>The function is only available as fastcall function, so it may only
<tag/Description/<tt/rename/ renames a file (gives it a new name). On success,
zero is returned. On error, -1 is returned and <tt/errno/ is set to an error
code describing the reason for the failure.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>This function is not available on all cc65 targets (depends on the
capabilities of the storage devices).
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void reset_brk (void);/
<tag/Description/<tt/reset_brk/ resets the break vector to the value it had
before a call to <tt/set_brk/.
-<tag/Limits/
-<itemize>
-<item>Since <tt/<ref id="set_brk" name="set_brk">/ installs an exit handler,
-it is not strictly necessary to call this function as part of the cleanup when
-the program ends.
+<tag/Notes/<itemize>
+<item>The break vector is reset on program termination, so it's not strictly
+necessary to call this function as a part of your clean-up when exitting the program.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Header/<tt/<ref id="6502.h" name="6502.h">/
<tag/Declaration/<tt/void reset_irq (void);/
<tag/Description/<tt/reset_irq/ resets the C level interrupt request vector.
-<tag/Limits/
-<itemize>
-<item>The original IRQ vector is restored on program termination even without
-calling this function.
+<tag/Notes/<itemize>
+<item>The interrupt vector is reset on program termination, so it's not strictly
+necessary to call this function as a part of your clean-up when exitting the program.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Description/If the argument is non zero, the function enables reverse
character display. If the argument is zero, reverse character display is
switched off. The old value of the setting is returned.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function may not be supported by the hardware, in which case
the call is ignored.
<item>The function is only available as fastcall function, so it may only
<tag/Declaration/<tt/void __fastcall__ rewinddir (DIR* dir);/
<tag/Description/<tt/rewinddir/ sets the position of the directory stream
pointed to by <tt/dir/ to the start of the directory.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="conio.h" name="conio.h">/
<tag/Declaration/<tt/void __fastcall__ screensize (unsigned char* x, unsigned char* y);/
<tag/Description/The function returns the dimensions of the text mode screen.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/<tt/seekdir/ sets the position of the directory stream
pointed to by <tt/dir/ to the value given in <tt/offset/, which should be a
value returned by <tt/<ref id="telldir" name="telldir">/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/Get a character from the serial port. If no characters are
available, the function will return SER_ERR_NO_DATA, so this is not a fatal
error.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/The function installs a driver that was already loaded into
memory (or linked statically to the program). It returns an error code
(<tt/SER_ERR_OK/ in case of success).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
<tag/Description/Some platforms have extra serial functions that are not
supported by standard serial driver functions. You can extend the driver to support
this extra functionality bt using ser_ioctl functions.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>These functions are not easily portable to other cc65 platforms.
<tag/Declaration/<tt/unsigned char __fastcall__ ser_load_driver (const char *name);/
<tag/Description/Load and install the driver by name.
Will just load the driver and check if loading was successful.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="serial.h" name="serial.h">/
<tag/Declaration/<tt/unsigned char __fastcall__ ser_open (const struct ser_params* params);/
<tag/Description/Open the port by setting the port parameters and enable interrupts.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/Send a character via the serial port. There is a transmit
buffer, but transmitting is not done via interrupt. The function returns
SER_ERR_OVERFLOW if there is no space left in the transmit buffer.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="serial.h" name="serial.h">/
<tag/Declaration/<tt/unsigned char __fastcall__ ser_status (unsigned char* status);/
<tag/Description/Return the serial port status.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
program code by letting the vector point to a user written C function. The
runtime library installs a small stub that saves the registers into global
variables that may be accessed (and changed) by the break handler.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The stub saves the zero page registers used by the C runtime and switches
<item>The <tt/brk_pc/ variable points to the <tt/BRK/ instruction. If you want
the continue with the interrupted code, you have to adjust <tt/brk_pc/,
otherwise the <tt/BRK/ instruction will get executed over and over again.
-<item>Since <tt/set_brk/ installs an exit handler, it is not strictly necessary
-to call <tt/<ref id="reset_brk" name="reset_brk">/ as part of the cleanup when
-the program terminates.
+<item>The break vector is reset on program termination, so it's not strictly
+necessary to call <tt/<ref id="reset_brk" name="reset_brk">/ as a part of your
+clean-up when exitting the program.
</itemize>
<tag/Availability/cc65
<tag/See also/
return the value <tt/IRQ_HANDLED/ if and only if it has verified that the current
interrupt request actually stems from that source. In all other cases it must return
the value <tt/IRQ_NOT_HANDLED/.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The stub saves the registers and zero page locations used by the C runtime
was interrupted. Be careful however not to call C library functions, and do not
enable stack checks for the handler function or any other function called from
it.
-<item>The interrupt vector is reset on function termination, so it's not
-strictly necessary to call <tt/<ref id="reset_irq" name="reset_irq">/ as part
-of the cleanup when the program terminates.
+<item>The interrupt vector is reset on program termination, so it's not strictly
+necessary to call <tt/<ref id="reset_irq" name="reset_irq">/ as a part of your
+clean-up when exitting the program.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Description/The <tt/setjmp/ function saves the current context in <tt/buf/
for subsequent use by the <tt/<ref id="longjmp" name="longjmp">/ function and
returns zero.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item><tt/setjmp/ is actually a macro as required by the ISO standard.
<tag/Header/<tt/<ref id="locale.h" name="locale.h">/
<tag/Declaration/<tt/char* __fastcall__ setlocale (int category, const char* locale);/
<tag/Description/<tt/setlocale/ sets or queries the program's locale.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>cc65 supports only the "C" locale, so calling this function to set a
signal handlers <tt/SIG_IGN/ or <tt/SIG_DFL/. The function returns the
previous value if the signal , or the special function vector SIG_ERR in
case of an error.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ sleep (unsigned seconds);/
<tag/Description/The function will return after the specified number of
seconds have elapsed.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void slow (void);/
<tag/Description/The function will switch the clock of the C128 to 1MHz. This
will halve the speed compared to fast mode.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is specific to the C128.
</itemize>
<tag/Availability/C128
<tag/Description/The function initializes the random number generator using
the given seed. On program startup, the generator behaves as if <tt/srand/ has
been called with an argument of 1.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
as parameters without case sensitivity. It returns a value that is less than
zero if <tt/s1/ is less than <tt/s2/, zero if <tt/s1/ is the same as <tt/s2/,
and a value greater than zero if <tt/s1/ is greater than <tt/s2/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function is not available in strict ANSI mode.
pointed to by s2 (including the terminating null byte) to the end of the
string pointed to by s1. The initial byte of s2 overwrites the null byte at
the end of s1.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>If copying takes place between objects that overlap, the behaviour
(converted to a char) in the string pointed to by <tt/s/. The terminating null
byte is considered to be part of the string. Upon completion, the function
returns a pointer to the byte, or a null pointer if the byte was not found.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
parameters. It returns a value that is less than zero if <tt/s1/ is less than
<tt/s2/, zero if <tt/s1/ is the same as <tt/s2/, and a value greater than zero
if <tt/s1/ is greater than <tt/s2/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
name="setlocale">/. It returns a value that is less than zero if <tt/s1/ is
less than <tt/s2/, zero if <tt/s1/ is the same as <tt/s2/, and a value greater
than zero if <tt/s1/ is greater than <tt/s2/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/The <tt/strcpy/ function copies the string pointed to by
<tt/s2/ (including the terminating null byte) into the array pointed to by
<tt/s1/. The function will always return <tt/s1/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>If copying takes place between objects that overlap, the behaviour
<tag/Description/The <tt/strcspn/ function computes and returns the length of
the substring pointed to by <tt/s/ which does <em>not</em> consist of
characters contained in the string <tt/set/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
to hold a copy of <tt/s/ including the terminating zero. If the allocation
fails, <tt/NULL/ is returned, otherwise <tt/s/ is copied into the allocated
memory block, and a pointer to the block is returned.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>It is up to the caller to free the allocated memory block.
given error code. If an invalid error code is passed, the string "Unknown
error" is returned, and <tt/errno/ is set to <tt/EINVAL/. In all other cases,
<tt/errno/ is left untouched.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>While the return type of the function is a <tt/char*/, the returned
parameters without case sensitivity. It returns a value that is less than zero
if <tt/s1/ is less than <tt/s2/, zero if <tt/s1/ is the same as <tt/s2/, and a
value greater than zero if <tt/s1/ is greater than <tt/s2/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function is not available in strict ANSI mode.
<tag/Declaration/<tt/size_t __fastcall__ strlen (const char* s);/
<tag/Description/The <tt/strlen/ function computes the number of bytes in the
string to which s points, not including the terminating null byte.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>When compiling with <tt/-Os/ (inline known standard functions), the
<tag/Declaration/<tt/char* __fastcall__ strlower (char* s);/
<tag/Description/The <tt/strlower/ function will apply the <tt/tolower/
function to each character of a string. The function will always return <tt/s/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function prototype is unavailable when compiling in strict ANSI mode.
of the string pointed to by s2 to the end of the string pointed to by s1. The
terminating null character at the end of s1 is overwritten. A terminating null
character is appended to the result, even if not all of s2 is appended to s1.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>If copying takes place between objects that overlap, the behaviour
less than zero if the first <tt/count/ characters of <tt/s1/ are less than
<tt/s2/, zero if they are identical, and a value greater than zero they are
greater.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
pointed to by <tt/s2/ is a string that is shorter than <tt/n/ bytes, null bytes are
appended to the copy in the array pointed to by <tt/s1/, until <tt/n/ bytes are
written. The function always will return <tt/s1/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is available only as a fastcall function; so, it may be used
only in the presence of a prototype.
<item>If there is no null byte in the first <tt/n/ bytes of the array pointed
pointer to the first token in the string <tt/s1/. The following calls must pass
a <tt/NULL/ pointer as <tt/s1/, in order to get the next token in the string.
Different sets of delimiters may be used for the subsequent calls to <tt/strqtok()/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is available only as a fastcall function; so, it may be used
only in the presence of a prototype.
<item><tt/strqtok()/ will modify the string <tt/s1/.
(converted to a char) in the string pointed to by <tt/s/. The terminating null
byte is considered to be part of the string. Upon completion, the function
returns a pointer to the byte, or a null pointer if the byte was not found.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/The <tt/strspn/ function computes and returns the length of
the substring pointed to by <tt/s/ which does consist only of characters
contained in the string <tt/set/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/<tt/strstr/ searches for the first occurance of the string
<tt/substr/ within <tt/str/. If found, it returns a pointer to the copy,
otherwise it returns <tt/NULL/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
The following calls must pass a <tt/NULL/ pointer as <tt/s1/, in order to get
the next token in the string. Different sets of delimiters may be used for the
subsequent calls to <tt/strtok()/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item><tt/strtok()/ will modify the string <tt/s1/.
zero, corresponding to the result of the <tt/strcoll/ function applied to the
same two original strings. No more than n characters are placed into the
resulting array pointed to by s1, including the terminating null character.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item><tt/s1/ and <tt/s2/ must not point to the same memory area, otherwise
the behaviour is undefined.
<item>If <tt/n/ is zero, <tt/s1/ may be a NULL pointer.
<tag/Declaration/<tt/char* __fastcall__ strupper (char* s);/
<tag/Description/The <tt/strupper/ function will apply the <tt/toupper/
function to each character of a string. The function will always return <tt/s/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function prototype is unavailable when compiling in strict ANSI mode.
<tag/Description/<tt/telldir/ returns the current position of a directory
stream. The return value may be used in subsequent calls to
<tt/<ref id="seekdir" name="seekdir">/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/The function will set a new text color. It returns the old
(current) text color. Text output using any <tt/conio.h/ function will use
the color set by this function.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Text colors are system dependent. The function may have no effect
on systems where the text color cannot be changed.
<item>The function is only available as fastcall function, so it may only
radii rx/ry using the current drawing color. The arc covers the angle
between sa and ea (startangle and endangle), which must be in the range
0..360.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function behaves unexpectedly or may crash if the angles are out
<tag/Declaration/<tt/void __fastcall__ tgi_bar (int x1, int y1, int x2, int y2);/
<tag/Description/The function fills a rectangle on the drawpage with the current
color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_circle (int x, int y, unsigned char radius);/
<tag/Description/The function draws a circle in the current color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ tgi_ellipse (int x, int y, unsigned char rx, unsigned char ry);/
<tag/Description/The function draws an ellipse at position x/y with radii
rx and ry, using the current drawing color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_free_vectorfont (const tgi_vectorfont* font);/
<tag/Description/Free a vector font that was previously loaded into memory.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
geometric shapes so they look correct on the display. As an example, a circle
with a radius of 100 pixels may look elliptic on some driver/display
combinations if the aspect ratio is not 1.00.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The aspect ratio is encoded in the TGI driver which assumes a "standard"
monitor for the given platform. The aspect ratio may be wrong if another
monitor is used.
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/const char* __fastcall__ tgi_geterrormsg (unsigned char code);/
<tag/Description/Get an error message describing the error.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/unsigned char __fastcall__ tgi_getpixel (int x, int y);/
<tag/Description/Get the color of a pixel from the viewpage.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_gotoxy (int x, int y);/
<tag/Description/Set graphics cursor at x, y.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void tgi_init (void);/
<tag/Description/The tgi_init function will set the default palette to the
hardware.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item><tt/tgi_init/ will not clear the screen. This allows switching between
text and graphics mode on platforms that have separate memory areas for the
screens. If you want the screen cleared, call <tt/<ref id="tgi_clear"
<tag/Description/The function installs a driver that was already loaded into
memory (or linked statically to the program). It returns an error code
(<tt/TGI_ERR_OK/ in case of success).
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
Install a vector font for use. More than one vector font can be loaded,
but only one can be active. This function is used to tell which one. Call
with a NULL pointer to uninstall the currently installed font.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only be
used in presence of a prototype.
</itemize>
<tag/Description/Some platforms have extra display hardware that is not
supported by standard tgi functions. You can extend the driver to support
this extra hardware using tgi_ioctl functions.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>These functions are not easily portable to other cc65 platforms.
<tag/Declaration/<tt/void __fastcall__ tgi_line (int x1, int y1, int x2, int y2);/
<tag/Description/Draw a line in the current drawing color.
The graphics cursor will be set to x2/y2 by this call.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ tgi_lineto (int x2, int y2);/
<tag/Description/Draw a line in the current drawing color from the graphics
cursor to the new end point. The graphics cursor will be updated to x2/y2.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/Load and install the driver by name.
Will just load the driver and check if loading was successful.
Will not switch to graphics mode.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
Load a vector font into memory and return it. In case of errors, NULL is
returned and an error is set, which can be retrieved using tgi_geterror.
To use the font, it has to be installed using tgi_install_vectorfont.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ tgi_outtext (const char* s);/
<tag/Description/Output text at the current graphics cursor position.
The graphics cursor is moved to the end of the text.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ tgi_outtextxy (int x, int y, const char* s);/
<tag/Description/Output text at the given cursor position.
The graphics cursor is moved to the end of the text.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
and radii rx/ry using the current drawing color. The pie slice covers the angle
between sa and ea (startangle and endangle), which must be in the range
0..360.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
<item>The function behaves unexpectedly or may crash if the angles are out
may be used to correct geometric shapes so they look correct on a given
display. As an example, a circle with a radius of 100 pixels may look elliptic
on some driver/display combinations if the aspect ratio is not 1.00.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The aspect ratio is encoded in the TGI driver which assumes a "standard"
monitor for the given platform. The aspect ratio may be wrong if another
monitor is used.
name="tgi_init">, so if a driver is linked statically to an application,
switching into and out of graphics mode will not restore the original aspect
ratio.
+<item>The function is available only as a fastcall function; so, it may be used
+only in the presence of a prototype.
</itemize>
<tag/Availability/cc65
<tag/See also/
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_setcolor (unsigned char color);/
<tag/Description/Set color to be used in future draw operations.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
is seen immediately as it is drawn. For double buffered games you can set the
drawpage to a different page than the viewpage. This lets you draw the next
screen in the background and when the screen is ready you display it.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/void __fastcall__ tgi_setpalette (const unsigned char* palette);/
<tag/Description/Set the palette (not available with all drivers/hardware).
Palette is a pointer to as many entries as there are colors.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_setpixel (int x, int y);/
<tag/Description/Plot a pixel on the drawpage with the current color.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
is seen immediately as it is drawn. For double buffered games you can set the
drawpage to a different page than the viewpage. This lets you draw the next
screen in the background and when the screen is ready you display it.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/unsigned __fastcall__ tgi_gettextheight (const char* s);/
<tag/Description/Calculate the height of the text in pixels according to
the current text style.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Description/
Set the scaling for text output. The scaling factors for width and height
are 8.8 fixed point values. This means that $100 = 1 $200 = 2 etc.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/void __fastcall__ tgi_settextstyle (unsigned char magx, unsigned char magy, unsigned char dir, unsigned char font);/
<tag/Description/Set the style for text output.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
<tag/Header/<tt/<ref id="tgi.h" name="tgi.h">/
<tag/Declaration/<tt/unsigned __fastcall__ tgi_gettextwidth (const char* s);/
<tag/Description/Calculate the width of the text in pixels according to the current text style.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may only
be used in presence of a prototype.
</itemize>
measured in seconds. If the pointer <tt/t/ is not <tt/NULL/, the function
result will also be stored there. If no time is available, <tt/(time_t)-1/ is
returned and <tt/errno/ is set to <tt/ENOSYS/.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
<item>Many platforms supported by cc65 do not have a realtime clock, so the
<tag/Description/Toggle between 40 and 80 column mode. The settings for the
old mode (cursor position, color and so on) are saved and restored together
with the mode.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is specific to the C128.
<item>This function is deprecated. Please use <ref id="videomode"
name="videomode"> instead!
<tag/Declaration/<tt/int __fastcall__ tolower (int c);/
<tag/Description/The function returns the given character converted to lower
case. If the given character is not a letter, it is returned unchanged.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/int __fastcall__ toupper (int c);/
<tag/Description/The function returns the given character converted to upper
case. If the given character is not a letter, it is returned unchanged.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is only available as fastcall function, so it may
only be used in presence of a prototype.
</itemize>
<tag/Declaration/<tt/char* __fastcall__ ultoa (unsigned long val, char* buf, int radix);/
<tag/Description/<tt/itoa/ converts the unsigned long integer <tt/val/ into a
string using <tt/radix/ as the base.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There are no provisions to prevent a buffer overflow.
<item>The function is non standard, so it is not available in strict ANSI mode.
You should probably use <tt/sprintf/ instead.
<tag/Description/<tt/unlink/ deletes the file with the given name. On success,
zero is returned. On error, -1 is returned and <tt/errno/ is set to an error
code describing the reason for the failure.
-<tag/Limits/
-<itemize>
+<tag/Notes/<itemize>
<item>The use of this function is discouraged. Please use <tt/<ref id="remove"
name="remove">/ instead, which is a native ANSI C function and does the same.
<item>This function is not available on all cc65 targets (depends on the
<tag/Declaration/<tt/char* __fastcall__ utoa (unsigned val, char* buf, int radix);/
<tag/Description/<tt/itoa/ converts the unsigned integer <tt/val/ into a string
using <tt/radix/ as the base.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>There are no provisions to prevent a buffer overflow.
<item>The function is non standard, so it is not available in strict ANSI mode.
You should probably use <tt/sprintf/ instead.
text where necessary and formatted according to the format string given. The
resulting string is output to the console. <tt/vcprintf/ supports the same
format specifiers as <tt/vprintf/. <!-- <tt/<ref id="vprintf" name="vprintf">/. -->
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>Like all other <tt/conio/ output functions, <tt/vcprintf/ distinguishes
between <tt/\r/ and <tt/\n/.
<item>The function is only available as fastcall function, so it may only be
<tag/Description/Switch to 40 or 80 column mode depending on the argument. If
the requested mode is already active, nothing happens. The old mode is returned
from the call.
-<tag/Limits/<itemize>
+<tag/Notes/<itemize>
<item>The function is specific to the C128 and enhanced Apple //e.
<item>This function replaces <ref id="toggle_videomode"
name="toggle_videomode">.
<tag><htmlurl url="cc65.html" name="cc65.html"></tag>
Describes the cc65 C compiler.
+ <tag><htmlurl url="chrcvt.html" name="chrcvt.html"></tag>
+ Describes the vector font converter.
+
<tag><htmlurl url="cl65.html" name="cl65.html"></tag>
Describes the cl65 compile & link utility.
<tag><htmlurl url="od65.html" name="od65.html"></tag>
Describes the od65 object-file analyzer.
+ <tag><htmlurl url="sim65.html" name="sim65.html"></tag>
+ Describes the 6502 and 65C02 simulator.
+
<tag><htmlurl url="sp65.html" name="sp65.html"></tag>
Describes the sprite and bitmap utility.
An overview over the cc65 runtime and C libraries.
<tag><htmlurl url="smc.html" name="smc.html"></tag>
- Describes Christian Krügers macro package for writing self modifying
+ Describes Christian Krüger's macro package for writing self modifying
assembler code.
<tag><url name="6502 Binary Relocation Format document"
<tag><htmlurl url="nes.html" name="nes.html"></tag>
Topics specific to the Nintendo Entertainment System.
+ <tag><htmlurl url="osi.html" name="osi.html"></tag>
+ Topics specific to the Ohio Scientific machines.
+
+ <tag><htmlurl url="pce.html" name="pce.html"></tag>
+ Topics specific to NEC PC-Engine (TurboGrafx) Console.
+
<tag><htmlurl url="pet.html" name="pet.html"></tag>
Topics specific to the Commodore PET machines.
Topics specific to the Commodore Plus/4.
<tag><htmlurl url="supervision.html" name="supervision.html"></tag>
- Topics specific to the Supervision Console.
+ Topics specific to the Watara Supervision Console.
<tag><htmlurl url="vic20.html" name="vic20.html"></tag>
Topics specific to the Commodore VIC20.
</article>
-
<author>
<url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">,<newline>
<url url="mailto:cbmnut@hushmail.com" name="CbmNut">,<newline>
-<url url="mailto:greg.king5@verizon.net" name="Greg King">
-<date>2014-4-24
+<url url="mailto:greg.king5@verizon.net" name="Greg King">,<newline>
+<url url="mailto:stephan.muehlstrasser@web.de" name="Stephan Mühlstrasser">
+<date>2015-03-07
<abstract>
How to use the cc65 C language system -- an introduction.
url="http://code.google.com/p/oriculator/">:
Emulates Oric-1 and Atmos computers, with sound, disk images,
-scanline-exact NTSC/PAL video, and movie export. Includes monitor.
-Fortunately for all SDL platforms. You will just need the emulator, all
+scanline-exact NTSC/PAL video, and movie export. Includes a monitor.
+Fortunately, for all SDL platforms. You will need just the emulator; all
ROMs are supplied.
Compile the tutorial with
</verb></tscreen>
Start the emulator, choose <bf/F1/ and <bf/Insert tape.../, and point to
-the "<bf/hello.tap/" executable. The file has an auto start header meant to
-be loaded directly from tape.
+the "<bf/hello.tap/" executable. After it has finished loading, type
+
+<tscreen><verb>
+RUN
+</verb></tscreen>
On a real Atmos, you would need a tape drive.
Turn on the computer, type
CLOAD""
</verb></tscreen>
-at the BASIC prompt.
+at the BASIC prompt. After it has finished loading, type
+
+<tscreen><verb>
+RUN
+</verb></tscreen>
The emulation, also, supports that method.
reading it.
+<sect1>Ohio Scientific Challenger 1P<p>
+The <tt/osic1p/ runtime library returns to the boot prompt when the main()
+program exits. Therefore, the C file in the tutorial must be modified
+slightly, in order to see the results on the screen. Otherwise, the program
+would print the text string, and then jump to the boot prompt, making it
+impossible to see the results of running the tutorial program.
+
+In addition to that, the <tt/osic1p/ target does not yet have support for stdio
+functions. Only the functions from the conio library are available.
+
+Therefore, modify the "<tt/hello.c/" source file, as follows:
+
+<tscreen><code>
+#include <conio.h>
+#include <stdlib.h>
+
+extern const char text[]; /* In text.s */
+
+int main (void)
+{
+ clrscr ();
+ cprintf ("%s\r\nPress <RETURN>.\r\n", text);
+ cgetc ();
+ return EXIT_SUCCESS;
+}
+</code></tscreen>
+
+Compile the tutorial with
+
+<tscreen><verb>
+cl65 -O -t osic1p -u __BOOT__ -o hello.lod hello.c text.s
+</verb></tscreen>
+
+The program is configured for a Challenger 1P computer with, at least, 32 kB
+of RAM. See the <url url="osi.html"
+name="Ohio Scientifc-specific documentation"> for instructions about how to
+compile for other RAM sizes.
+
+Plug a cassette player into your C1P computer; or, connect an RS-232 cable
+between your C1P and a PC (set the PC's serial port to 300 Bits Per Second,
+8 data bits, No parity, and 2 stop bits). (Turn on the computers.)
+
+Tap the "<bf/BREAK/" key, to display the boot prompt; then, tap the "<tt/M/"
+key, to enter the 65V PROM monitor. Tap the "<tt/L/" key. Either start the
+cassette player (with a tape of the program), or start a transfer of the
+program file "<tt/hello.lod/" from the PC. After a while, you should see the
+following text on the screen:
+
+<tscreen><verb>
+Hello world!
+Press <RETURN>.
+</verb></tscreen>
+
+(Stop the cassette player.) After hitting the RETURN key, you should see the
+boot prompt again.
+
+<sect2>WinOSI<p>
+Available at <url
+url="http://osi.marks-lab.com/#Emulator">:
+
+Emulates the Ohio Scientific Challenger computers in different configurations.
+Configure it to emulate a C1P (model 600 board) with 32 kB of RAM.
+
+Compile the tutorial with the same command that is used to make the program
+for a real machine.
+
+Start the emulator. Tap the "<tt/M/" key, to enter the 65V PROM monitor; then,
+tap the "<tt/L/" key. If you had configured WinOSI to ask for a file when it
+starts to read data from the serial port, then you will see a file dialog box;
+otherwise, you must tap your host keyboard's F10 function key. Select the file
+"<tt/hello.lod/". After a moment, you should see the following text on the
+screen:
+
+<tscreen><verb>
+Hello world!
+Press <RETURN>.
+</verb></tscreen>
+
+After hitting the RETURN key, you should see the boot prompt again.
+
+<sect2>C1Pjs<p>
+Available at <url
+url="http://www.pcjs.org/docs/c1pjs/">:
+
+Emulates the Ohio Scientific Challenger 1P computer in different configurations.
+The 32 kB RAM machine that must be used with the default compiler settings is
+<url url="http://www.pcjs.org/devices/c1p/machine/32kb/" name="here">.
+
+In addition to cc65, the <bf/srec_cat/ program from <url
+url="http://srecord.sourceforge.net/" name="the SRecord tool collection">
+must be installed. Some Linux distributions also provide srecord directly as
+an installable package.
+
+Compile the tutorial with this command line:
+
+<tscreen><verb>
+cl65 -O -t osic1p hello.c text.s
+</verb></tscreen>
+
+Convert the binary file into a text file that can be loaded via
+the Ohio Scientific 65V PROM monitor, at start address 0x200:
+
+<tscreen><verb>
+srec_cat hello -binary -offset 0x200 -o hello.c1p -Ohio_Scientific -execution-start-address=0x200
+</verb></tscreen>
+
+Open the URL that points to the 32 kB machine; and, wait until the emulator
+has been loaded. Click on the "<bf/BREAK/" button to display the boot prompt;
+then, press the "<tt/M/" key to enter the 65V PROM monitor. Click the
+"<bf/Browse.../" button; and, select the file "<tt/hello.c1p/" that was
+created as the output of the above invocation of the "<tt/srec_cat/" command.
+Press the "<bf/Load/" button. You should see the following text on the screen:
+
+<tscreen><verb>
+Hello world!
+Press <RETURN>.
+</verb></tscreen>
+
+After hitting the RETURN key, you should see the boot prompt again.
+
+
<sect1>Contributions wanted<p>
We need your help! Recommended emulators and instructions for other targets
<sect1>NES specific functions<p>
<itemize>
-<item>waitvblank
+<item>waitvblank - wait until the start of vblank
<item>get_tv
</itemize>
</descrip><p>
+The generic interface doesn't export the start and select buttons. To
+test for those, use the defines in nes.h instead of the generic masks.
+
+Example:
+<tscreen><verb>
+if (joy_read(0) & KEY_A)
+</verb></tscreen>
+
<sect1>Mouse drivers<p>
--- /dev/null
+<!doctype linuxdoc system>
+
+<article>
+
+<title>Ohio Scientific-specific information for cc65
+<author>
+<url url="mailto:stephan.muehlstrasser@web.de" name="Stephan Mühlstrasser">,<newline>
+<url url="mailto:greg.king5@verizon.net" name="Greg King">
+<date>2015-03-17
+
+<abstract>
+An overview over the Ohio Scientific runtime system as it is implemented for the cc65 C
+compiler.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview<p>
+
+This file contains an overview of the Ohio Scientific runtime system as it comes with the
+cc65 C compiler. It describes the memory layout, Ohio Scientific-specific header files,
+and any pitfalls specific to that platform.
+
+Please note that Ohio Scientific-specific functions are just mentioned here, they are
+described in detail in the separate <url url="funcref.html" name="function
+reference">. Even functions marked as "platform dependent" may be available on
+more than one platform. Please see the function reference for more
+information.
+
+<sect>Targets<p>
+
+Currently the target "osic1p" is implemented. This works for the Ohio Scientific
+Challenger 1P machine and for the Briel Superboard /// replica.
+
+<sect>Program file formats<p>
+
+<descrip>
+ <tag/Binary, then text/
+ The standard binary output format generated by the linker for the osic1p
+ target is a pure machine language program.
+
+ For uploading into a real machine over its serial port or into an emulator,
+ that program must be converted into a text file that can be understood by
+ the 65V PROM monitor. For that purpose, the <bf/srec_cat/ program from <url
+ url="http://srecord.sourceforge.net/" name="the SRecord tool collection">
+ can be used.
+
+ Care must be taken that the <tt/-offset/ and <tt/-execution-start-address/
+ options for the <bf/srec_cat/ program correspond to the start address
+ of the executable.
+
+ Example for converting an executable "hello" file that was built for the
+ default start address $0200 to an uploadable file "hello.c1p":
+
+ <tscreen><verb>
+ srec_cat hello -bin -of 0x200 -o hello.c1p -os -esa=0x200
+ </verb></tscreen>
+
+ <tag/Hybrid/
+ The linker can create an alternate format that contains two parts:
+ <enum>
+ <item>A text header that is understood by the 65V PROM monitor.
+ It is a boot loader that reads the second part.
+ <item>The default binary code that is described above.
+ </enum>
+
+ You can make the alternate format by adding the option <tt/-u __BOOT__/ to
+ <tt/cl65/'s or <tt/ld65/'s command lines.
+
+ This format doesn't need to be converted. It is smaller than the text-only
+ format. But, it cannot be loaded by <url
+ url="http://www.pcjs.org/docs/c1pjs/" name="C1Pjs">; you must use the
+ SRecord-produced text-only format with that emulator. (However, if you know
+ that you never will use C1Pjs, then you can edit the
+ <tt>cfg/osic1p*.cfg</tt> files; uncomment the lines that import <tt/__BOOT__/.
+ Then, you won't need to use <tt/-u __BOOT__/ on your command lines.)
+
+</descrip>
+
+<sect>Memory layout<p>
+
+By default programs compiled for the osic1p target are configured for 32 kB RAM.
+The RAM size can be configured via the symbol <tt/__HIMEM__/.
+
+Special locations:
+
+<descrip>
+ <tag/Program start address/
+ The default start address is $0200. The start address is configurable
+ via the linker option <tt/--start-addr/.
+
+ <tag/Stack/
+ The C runtime stack is located at the top of RAM and growing downwards.
+ The size is configurable via the symbol <tt/__STACKSIZE__/. The default
+ stack size is $0400.
+
+ <tag/Heap/
+ The C heap is located at the end of the program and grows towards the C
+ runtime stack.
+
+ <tag/Video RAM/
+ The 1 kB video RAM is located at $D000. On the monitor, only a subset
+ of the available video RAM is visible. The address of the upper left corner
+ of the visible area is $D085 and corresponds to conio cursor
+ position (0, 0).
+
+</descrip><p>
+
+Example for building a program with start address $0300, stack size
+$0200 and RAM size $2000:
+
+<tscreen><verb>
+cl65 --start-addr 0x300 -Wl -D,__HIMEM__=$2000,-D,__STACKSIZE__=$0200 -t osic1p hello.c
+</verb></tscreen>
+
+<sect>Linker configurations<p>
+
+The ld65 linker comes with a default config file "osic1p.cfg" for the Ohio Scientific
+Challenger 1P, which is implicitly used via <tt/-t osic1p/. The
+osic1p package comes with additional secondary linker config files, which are
+used via <tt/-t osic1p -C <configfile>/.
+
+<sect1>Default config file (<tt/osic1p.cfg/)<p>
+
+The default configuration is tailored to C programs.
+
+<sect1><tt/osic1p-asm.cfg/<p>
+
+This configuration is made for assembler programmers who don't need a special
+setup.
+
+To use this config file, assemble with <tt/-t osic1p/ and link with
+<tt/-C osic1p-asm.cfg/. The former will make sure that correct runtime library
+is used, while the latter supplies the actual config. When using <tt/cl65/,
+use both command line options.
+
+Sample command lines for <tt/cl65/:
+
+<tscreen><verb>
+cl65 -t osic1p -C osic1p-asm.cfg -o program source.s
+cl65 -t osic1p -C osic1p-asm.cfg -u __BOOT__ -o program.lod source.s
+</verb></tscreen>
+
+<sect>Platform-specific header files<p>
+
+Programs containing Ohio Scientific-specific code may use the <tt/osic1p.h/
+header file.
+
+<sect1>Ohio Scientific-specific functions<p>
+
+There are currently no special Ohio Scientific functions.
+
+<sect1>Hardware access<p>
+
+There is no specific support for direct hardware access.
+
+<sect>Loadable drivers<p>
+
+There are no loadable drivers available.
+
+<sect>Support for different screen layouts<p>
+
+By default the conio library uses a 24 columns by 24 lines screen layout
+for the Challenger 1P, like under BASIC. In addition to that there is support
+for other screen layouts with extra modules.
+
+There is a module <tt/screen-c1p-24x24.o/ in the OSI-specific
+cc65 runtime library that contains all conio functions that depend
+on the screen layout. No further configuration is needed for using the
+default screen layout of the Challenger 1P.
+
+For other screen layouts additional versions of the screen module are
+available. The linker finds these modules without further configuration
+if they are specified on the compiler or linker command line. The
+extra module then overrides the default module.
+
+Sample <tt/cl65/ command line to override the default screen
+module with the module <tt/osic1p-screen-s3-32x28.o/:
+
+<tscreen><verb>
+cl65 -o hello -t osic1p osic1p-screen-s3-32x28.o hello.c
+</verb></tscreen>
+
+Currently the following extra screen configuration modules are implemented:
+
+<itemize>
+<item><tt>osic1p-screen-s3-32x28.o</tt>: 32 columns by 28 lines mode
+for Briel Superboard ///</item>
+</itemize>
+
+<sect>Limitations<p>
+
+<sect1>stdio implementation<p>
+
+There is no support for stdio at the moment.
+
+<sect>Other hints<p>
+
+<sect1>Passing arguments to the program<p>
+
+There is currently no support for passing arguments to a program.
+
+<sect1>Program return code<p>
+
+The program return code currently has no effect. When the main() function
+finishes, the boot prompt is shown again.
+
+<sect>License<p>
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+<enum>
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
+</enum>
+
+</article>
+
--- /dev/null
+<!doctype linuxdoc system>
+
+<article>
+
+<title>PC-Engine (TurboGrafx) System specific information for cc65
+<author>
+<url url="mailto:groepaz@gmx.net" name="Groepaz/Hitmen">
+<date>2015-07-14
+
+<abstract>
+An overview over the PCE runtime system as it is implemented for the
+cc65 C compiler.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview<p>
+
+This file contains an overview of the PCE runtime system as it comes
+with the cc65 C compiler. It describes the memory layout, PCE specific header
+files, available drivers, and any pitfalls specific to that platform.
+
+Please note that PCE specific functions are just mentioned here, they are
+described in detail in the separate <url url="funcref.html" name="function
+reference">. Even functions marked as "platform dependent" may be available on
+more than one platform. Please see the function reference for more
+information.
+
+
+<sect>Binary format<p>
+
+The standard binary output format generated by the linker for the PCE target
+is a cartridge image with no header. It is of course possible to change this
+behaviour by using a modified startup file and linker config.
+
+<sect>Memory layout<p>
+
+cc65 generated programs with the default setup run with the I/O area and a
+CHR bank enabled, which gives a usable memory range of $8000 - $FFF3.
+All boot ROM entry points may be called directly without additional code.
+
+Special locations:
+
+<descrip>
+ <tag/Text screen and Font/
+ The text screen is located at VRAM $0000,
+ the Font is located at VRAM $2000.
+
+ <tag/Stack/
+ The C runtime stack is located in system RAM at $3FFF and growing downwards.
+
+ <tag/BSS and Data/
+
+ The BSS (uninitialized variables) and Data (initialized variables) sections are
+ placed one after the other into system RAM at $2000.
+
+ <tag/Heap/
+ The C heap is located after the end of the Data section and grows towards the C
+ runtime stack.
+
+ <tag/Code/
+ The startup code is located at $E000 in the System/Hardware bank. Further
+ code can be placed in other ROM banks, this must be done manually however.
+
+</descrip><p>
+
+
+
+<sect>Platform specific header files<p>
+
+Programs containing PCE specific code may use the <tt/pce.h/ header file.
+
+
+<sect1>PCE specific functions<p>
+
+<itemize>
+<item>waitvblank</item>
+<item>get_tv (since all PCE systems are NTSC, this always returns TV_NTSC)</item>
+</itemize>
+
+
+
+<sect1>Hardware access<p>
+
+The following pseudo variables declared in the <tt/pce.inc/ include file do
+allow access to hardware located in the address space.
+
+<descrip>
+
+ <tag><tt/PSG/</tag>
+ The <tt/PSG/ defines allow access to the PSG chip (Programmable Sound Generator).
+
+ <tag><tt/VCE/</tag>
+ The <tt/VCE/ defines allow access to the VCE chip (Video Color Encoder).
+
+ <tag><tt/VDC/</tag>
+ The <tt/VDC/ defines allow access to the VDC chip (Video Display Controller).
+
+</descrip><p>
+
+
+
+<sect>Loadable drivers<p>
+
+All drivers must be statically linked because no file I/O is available.
+The names in the parentheses denote the symbols to be used for static linking of the drivers.
+
+
+<sect1>Graphics drivers<p>
+
+No TGI graphics drivers are currently available for the PCE.
+
+
+<sect1>Extended memory drivers<p>
+
+No extended memory drivers are currently available for the PCE.
+
+
+<sect1>Joystick drivers<p>
+
+<descrip>
+
+ <tag><tt/pce-stdjoy.joy (pce_stdjoy)/</tag>
+ A joystick driver for the standard two buttons joypad is available.
+
+ Note that the japanese 6-button pad is currently not supported.
+
+</descrip><p>
+
+
+<sect1>Mouse drivers<p>
+
+No mouse drivers are currently available for the PCE.
+
+
+<sect1>RS232 device drivers<p>
+
+No serial drivers are currently available for the PCE.
+
+
+
+<sect>Limitations<p>
+
+<itemize>
+<item>interruptor support in crt0 (and cfg) is missing
+</itemize>
+
+<sect1>Disk I/O<p>
+
+The existing library for the PCE doesn't implement C file
+I/O. There are no hacks for the <tt/read()/ and <tt/write()/ routines.
+
+To be more concrete, this limitation means that you cannot use any of the
+following functions (and a few others):
+
+<itemize>
+<item>printf
+<item>fclose
+<item>fopen
+<item>fread
+<item>fprintf
+<item>fputc
+<item>fscanf
+<item>fwrite
+<item>...
+</itemize>
+
+<sect>Other hints<p>
+
+<itemize>
+<item>a good emulator to use for PC-Engine is "mednafen" (<url url="http://mednafen.fobby.net/">)
+</itemize>
+
+some useful resources on PCE coding:
+
+<itemize>
+<item><url url="http://blog.blockos.org/?tag=pc-engine">
+<item><url url="http://pcedev.blockos.org/viewforum.php?f=5">
+<item><url url="http://www.romhacking.net/?page=documents&category=&platform=4&:game=&author=&perpage=20&level=&title=&desc=&docsearch=Go">
+<item><url url="http://archaicpixels.com/Main_Page">
+
+<item><url url="http://www.magicengine.com/mkit/doc.html">
+
+<item><url url="https://github.com/uli/huc">
+<item><url url="http://www.zeograd.com/parse.php?src=hucf">
+</itemize>
+
+<sect>License<p>
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+<enum>
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
+</enum>
+
+</article>
+
+
+
--- /dev/null
+<!doctype linuxdoc system> <!-- -*- text-mode -*- -->
+
+<article>
+
+<title>sim65 Users Guide
+<author><url url="mailto:polluks@sdf.lonestar.org" name="Stefan A. Haubenthal">
+<date>2016-01-05
+
+<abstract>
+sim65 is a simulator for 6502 and 65C02 CPUs. It allows to test target
+independed code.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview<p>
+
+
+sim65 is the only solution as part of the toolchain to execute code. The
+binary needs to be compiled with <tt/--target sim6502/ or <tt/--target sim65c02/.
+
+
+<sect>Usage<p>
+
+The simulator is called as follows:
+
+<tscreen><verb>
+ Usage: sim65 [options] file [arguments]
+ Short options:
+ -h Help (this text)
+ -v Increase verbosity
+ -V Print the simulator version number
+ -x <num> Exit simulator after <num> cycles
+
+ Long options:
+ --help Help (this text)
+ --verbose Increase verbosity
+ --version Print the simulator version number
+</verb></tscreen>
+
+
+<sect1>Command line options in detail<p>
+
+Here is a description of all the command line options:
+
+<descrip>
+
+ <tag><tt>-h, --help</tt></tag>
+
+ Print the short option summary shown above.
+
+
+ <tag><tt>-v, --verbose</tt></tag>
+
+ Increase the simulator verbosity.
+
+
+ <tag><tt>-V, --version</tt></tag>
+
+ Print the version number of the utility. When submitting a bug report,
+ please include the operating system you're using, and the compiler
+ version.
+
+
+ <tag><tt>-x num</tt></tag>
+
+ Exit simulator after num cycles.
+</descrip>
+
+
+<sect>Input and output<p>
+
+The simulator will read one binary file per invocation and can log the
+program loading and paravirtualization calls to stderr.
+
+Example output for the command
+<tscreen><verb>
+sim65 --verbose --verbose samples/gunzip65
+</verb></tscreen>
+<tscreen><verb>
+Loaded `samples/gunzip65' at $0200-$151F
+PVWrite ($0001, $13C9, $000F)
+GZIP file name:PVWrite ($0001, $151F, $0001)
+
+PVRead ($0000, $FFD7, $0001)
+PVOpen ("", $0001)
+PVRead ($0003, $1520, $6590)
+PVClose ($0003)
+PVWrite ($0001, $13D9, $000F)
+Not GZIP formatPVWrite ($0001, $151F, $0001)
+
+PVExit ($01)
+</verb></tscreen>
+
+
+
+<sect>Copyright<p>
+
+sim65 (and all cc65 binutils) are (C) Copyright 1998-2000 Ullrich von
+Bassewitz. For usage of the binaries and/or sources the following conditions
+do apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+<enum>
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
+</enum>
+
+</article>
<label id="Change branch">
<tag><tt>SMC_ChangeBranch label, destination (, register)</tt></tag>
- Used to modify the destination of a branch instruction. If the adress offset
+ Used to modify the destination of a branch instruction. If the address offset
exceeds the supported range of 8-bit of the 6502, a error will be thrown.
Example:
<tag><tt>SMC_TransferLowByte label, value (, register)</tt></tag>
Does the same as '<tt>SMC_TransferValue</tt>' but should be used for
- low-bytes of adresses for better readability.
+ low-bytes of addresses for better readability.
Example:
<tscreen><verb>
<tag><tt>SMC_LoadLowByte label (, register)</tt></tag>
Does the same as '<tt>SMC_LoadValue</tt>' but should be used for low-bytes
- of adresses for better readability.
+ of addresses for better readability.
Example:
<tscreen><verb>
<tag><tt>SMC_StoreLowByte label (, register)</tt></tag>
Does the same as '<tt>SMC_StoreValue</tt>' but should be used for low-bytes
- of adresses for better readability.
+ of addresses for better readability.
Example:
<tscreen><verb>
<tag><tt>SMC_TransferHighByte label, value (, register)</tt></tag>
Loads and stores the given value via the named register to the high-byte
- adress portion of an SMC-instruction.
+ address portion of an SMC-instruction.
Example:
<tscreen><verb>
<label id="Load high-byte">
<tag><tt>SMC_LoadHighByte label (, register)</tt></tag>
- Loads the high-byte part of an SMC-instruction adress to the given register.
+ Loads the high-byte part of an SMC-instruction address to the given register.
Example:
<tscreen><verb>
<label id="Store high-byte">
<tag><tt>SMC_StoreHighByte label (, register)</tt></tag>
- Stores the high-byte adress part of an SMC-instruction from the given
+ Stores the high-byte address part of an SMC-instruction from the given
register.
Example:
</verb></tscreen>
- <label id="Transfer single adress">
+ <label id="Transfer single address">
<tag><tt>SMC_TransferAddressSingle label, address (, register)</tt></tag>
Transfers the contents of the given address via the given register to the
</verb></tscreen>
- <label id="Transfer adress">
+ <label id="Transfer address">
<tag><tt>SMC_TransferAddress label, address</tt></tag>
Loads contents of given address to A/X and stores the result to SMC
8: SMC FirstIncHighByte, { SMC_OperateOnHighByte inc, StoreAccuFirstSection } ; code will be overwritten to 'beq RestoreCode' (*)
9: ...
10: SMC_TransferOpcode FirstIncHighByte, OPC_BEQ , x ; change code marked above with (*)
-11: SMC_TransferValue FirstIncHighByte, #(restoreCode - RestoreCodeBranchBaseAdr-2), x ; set relative adress to 'RestoreCode'
+11: SMC_TransferValue FirstIncHighByte, #(restoreCode - RestoreCodeBranchBaseAdr-2), x ; set relative address to 'RestoreCode'
12: ...
13: restoreCode:
14: SMC_TransferOpcode FirstIncHighByte, OPC_INC_abs , x ; restore original code...
-15: SMC_TransferValue FirstIncHighByte, #(<(StoreToFirstSection+2)), x ; (second byte of inc contained low-byte of adress)
+15: SMC_TransferValue FirstIncHighByte, #(<(StoreToFirstSection+2)), x ; (second byte of inc contained low-byte of address)
16: ...
</verb></tscreen>
/* */
/* ace.h */
/* */
-/* ACE system specific definitions */
+/* ACE system-specific definitions */
/* */
/* */
/* */
-/* (C) 1998-2001 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2015, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
char ad_name [17]; /* Name itself, ASCIIZ */
};
-int aceDirOpen (char* dir);
-int aceDirClose (int handle);
-int aceDirRead (int handle, struct aceDirentBuf* buf);
+int __cdecl__ aceDirOpen (char* dir);
+int __cdecl__ aceDirClose (int handle);
+int __cdecl__ aceDirRead (int handle, struct aceDirentBuf* buf);
/* Type of an ACE key. Key in low byte, shift mask in high byte */
typedef unsigned int aceKey;
#define aceOP_RPTRATE 11 /* Key repeat rate */
/* Console functions */
-void aceConWrite (char* buf, size_t count);
-void aceConPutLit (int c);
-void aceConPos (unsigned x, unsigned y);
-void aceConGetPos (unsigned* x, unsigned* y);
+void __cdecl__ aceConWrite (char* buf, size_t count);
+void __cdecl__ aceConPutLit (int c);
+void __cdecl__ aceConPos (unsigned x, unsigned y);
+void __cdecl__ aceConGetPos (unsigned* x, unsigned* y);
unsigned aceConGetX (void);
unsigned aceConGetY (void);
-char* aceConInput (char* buf, unsigned initial);
+char __cdecl__* aceConInput (char* buf, unsigned initial);
int aceConStopKey (void);
aceKey aceConGetKey (void);
-int aceConKeyAvail (aceKey* key);
-void aceConKeyMat (char* matrix);
-void aceConSetOpt (unsigned char opt, unsigned char val);
-int aceConGetOpt (unsigned char opt);
+int __cdecl__ aceConKeyAvail (aceKey* key);
+void __cdecl__ aceConKeyMat (char* matrix);
+void __cdecl__ aceConSetOpt (unsigned char opt, unsigned char val);
+int __cdecl__ aceConGetOpt (unsigned char opt);
/* Misc stuff */
-int aceMiscIoPeek (unsigned addr);
-void aceMiscIoPoke (unsigned addr, unsigned char val);
+int __cdecl__ aceMiscIoPeek (unsigned addr);
+void __cdecl__ aceMiscIoPoke (unsigned addr, unsigned char val);
/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2015, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#ifdef NDEBUG
# define assert(expr)
#else
-extern void _afailed (const char*, unsigned);
+extern void __fastcall__ _afailed (const char*, unsigned);
# define assert(expr) ((expr)? (void)0 : _afailed(__FILE__, __LINE__))
#endif
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
-unsigned int cbm_load (const char* name, unsigned char device, void* data);
+unsigned int __fastcall__ cbm_load (const char* name, unsigned char device, void* data);
/* Loads file "name", from given device, to given address -- or, to the load
** address of the file if "data" is the null pointer (like load"name",8,1
** in BASIC).
# include <lynx.h>
#elif defined(__NES__)
# include <nes.h>
+#elif defined(__OSIC1P__)
+# include <osic1p.h>
+#elif defined(__PCE__)
+# include <pce.h>
#endif
/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2000, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
int __fastcall__ DbgIsRAM (unsigned Addr);
/* Return true if we can read and write the given address */
-char* DbgMemDump (unsigned Addr, char* Buf, unsigned char Len);
+char* __cdecl__ DbgMemDump (unsigned Addr, char* Buf, unsigned char Len);
/* Create a line of a memory dump in the given buffer. The buffer contains
** the starting address (4 digits hex), then Len bytes in this format:
** "AAAA__XX_YY_ZZ_...". The passed char buffer must hold Len*3+5 bytes
/* */
/* lynx.h */
/* */
-/* Lynx system specific definitions */
+/* Lynx system-specific definitions */
/* */
/* */
/* */
/* Sound support */
/*****************************************************************************/
-void lynx_snd_init ();
+void lynx_snd_init (void);
/* Initialize the sound driver */
-void lynx_snd_pause ();
+void lynx_snd_pause (void);
/* Pause sound */
-void lynx_snd_continue ();
+void lynx_snd_continue (void);
/* Continue sound after pause */
void __fastcall__ lynx_snd_play (unsigned char channel, unsigned char *music);
/* Play tune on channel */
-void lynx_snd_stop ();
+void lynx_snd_stop (void);
/* Stop sound on all channels */
void __fastcall__ lynx_snd_stop_channel (unsigned char channel);
/* Stop sound on all channels */
-unsigned char lynx_snd_active();
+unsigned char lynx_snd_active(void);
/* Show which channels are active */
/*****************************************************************************/
/* The default mouse callbacks */
extern const struct mouse_callbacks mouse_def_callbacks;
+#if defined(__CBM__)
+
+/* The default mouse pointer shape used by the default mouse callbacks */
+extern const unsigned char mouse_def_pointershape[63];
+
+/* The default mouse pointer color used by the default mouse callbacks */
+extern const unsigned char mouse_def_pointercolor;
+
+#endif
+
/* The name of the standard mouse driver for a platform */
extern const char mouse_stddrv[];
/* End of mouse.h */
#endif
-
-
-
/* No support for dynamically loadable drivers */
#define DYN_DRV 0
-
+/* The joystick keys - all keys are supported */
+#define KEY_A 0x01
+#define KEY_B 0x02
+#define KEY_SELECT 0x04
+#define KEY_START 0x08
+#define KEY_UP 0x10
+#define KEY_DOWN 0x20
+#define KEY_LEFT 0x40
+#define KEY_RIGHT 0x80
+
+/* Define hardware */
+
+/* Picture Processing Unit */
+struct __ppu {
+ unsigned char control;
+ unsigned char mask; /* color; show sprites, background */
+ signed char volatile const status;
+ struct {
+ unsigned char address;
+ unsigned char data;
+ } sprite;
+ unsigned char scroll;
+ struct {
+ unsigned char address;
+ unsigned char data;
+ } vram;
+};
+#define PPU (*(struct __ppu*)0x2000)
+#define SPRITE_DMA (APU.sprite.dma)
+
+/* Audio Processing Unit */
+struct __apu {
+ struct {
+ unsigned char control; /* duty, counter halt, volume/envelope */
+ unsigned char ramp;
+ unsigned char period_low; /* timing */
+ unsigned char len_period_high; /* length, timing */
+ } pulse[2];
+ struct {
+ unsigned char counter; /* counter halt, linear counter */
+ unsigned char unused;
+ unsigned char period_low; /* timing */
+ unsigned char len_period_high; /* length, timing */
+ } triangle;
+ struct {
+ unsigned char control; /* counter halt, volume/envelope */
+ unsigned char unused;
+ unsigned char period; /* loop, timing */
+ unsigned char len; /* length */
+ } noise;
+ struct {
+ unsigned char control; /* IRQ, loop, rate */
+ unsigned char output; /* output value */
+ unsigned char address;
+ unsigned char length;
+ } delta_mod; /* delta pulse-code modulation */
+ struct {
+ unsigned char dma;
+ } sprite;
+ signed char volatile status;
+ unsigned char unused;
+ unsigned char fcontrol;
+};
+#define APU (*(struct __apu*)0x4000)
+
+#define JOYPAD ((unsigned char volatile[2])0x4016)
/* The addresses of the static drivers */
extern void nes_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
--- /dev/null
+/*****************************************************************************/\r
+/* */\r
+/* osic1p.h */\r
+/* */\r
+/* Challenger 1P system specific definitions */\r
+/* */\r
+/* */\r
+/* */\r
+/* (C) 2015 Stephan Muehlstrasser */\r
+/* */\r
+/* */\r
+/* This software is provided 'as-is', without any expressed or implied */\r
+/* warranty. In no event will the authors be held liable for any damages */\r
+/* arising from the use of this software. */\r
+/* */\r
+/* Permission is granted to anyone to use this software for any purpose, */\r
+/* including commercial applications, and to alter it and redistribute it */\r
+/* freely, subject to the following restrictions: */\r
+/* */\r
+/* 1. The origin of this software must not be misrepresented; you must not */\r
+/* claim that you wrote the original software. If you use this software */\r
+/* in a product, an acknowledgment in the product documentation would be */\r
+/* appreciated but is not required. */\r
+/* 2. Altered source versions must be plainly marked as such, and must not */\r
+/* be misrepresented as being the original software. */\r
+/* 3. This notice may not be removed or altered from any source */\r
+/* distribution. */\r
+/* */\r
+/*****************************************************************************/\r
+\r
+#ifndef _OSIC1P_H\r
+#define _OSIC1P_H\r
+\r
+/* Check for errors */\r
+#if !defined(__OSIC1P__)\r
+# error "This module may only be used when compiling for the Challenger 1P!"\r
+#endif\r
+\r
+/* The following #defines will cause the matching functions calls in conio.h\r
+** to be overlaid by macros with the same names, saving the function call\r
+** overhead.\r
+*/\r
+#define _textcolor(color) COLOR_WHITE\r
+#define _bgcolor(color) COLOR_BLACK\r
+#define _bordercolor(color) COLOR_BLACK\r
+\r
+#endif\r
--- /dev/null
+/*****************************************************************************/
+/* */
+/* pce.h */
+/* */
+/* PC-Engine system specific definitions */
+/* */
+/* */
+/* */
+/* (C) 2015 Groepaz/Hitmen */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+#ifndef _PCE_H
+#define _PCE_H
+
+/* Check for errors */
+#if !defined(__PCE__)
+# error This module may only be used when compiling for the PCE!
+#endif
+
+#define CH_HLINE 1
+#define CH_VLINE 2
+#define CH_CROSS 3
+#define CH_ULCORNER 4
+#define CH_URCORNER 5
+#define CH_LLCORNER 6
+#define CH_LRCORNER 7
+#define CH_TTEE 8
+#define CH_BTEE 9
+#define CH_LTEE 10
+#define CH_RTEE 11
+
+#define CH_ENTER 13
+#define CH_PI 18
+
+/* Color defines (CBM compatible, for conio) */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+#define COLOR_RED 0x02
+#define COLOR_CYAN 0x03
+#define COLOR_VIOLET 0x04
+#define COLOR_GREEN 0x05
+#define COLOR_BLUE 0x06
+#define COLOR_YELLOW 0x07
+#define COLOR_ORANGE 0x08
+#define COLOR_BROWN 0x09
+#define COLOR_LIGHTRED 0x0A
+#define COLOR_GRAY1 0x0B
+#define COLOR_GRAY2 0x0C
+#define COLOR_LIGHTGREEN 0x0D
+#define COLOR_LIGHTBLUE 0x0E
+#define COLOR_GRAY3 0x0F
+
+#define TV_NTSC 0
+#define TV_PAL 1
+#define TV_OTHER 2
+
+/* No support for dynamically loadable drivers */
+#define DYN_DRV 0
+
+/* The addresses of the static drivers */
+extern void pce_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
+
+#define JOY_FIRE_B 5
+#define JOY_SELECT 6
+#define JOY_RUN 7
+
+void waitvblank (void);
+/* Wait for the vertical blanking */
+
+/* NOTE: all PCE are NTSC */
+#define get_tv() TV_NTSC
+/* Return the video mode the machine is using. */
+
+/* End of pce.h */
+#endif
long __fastcall__ atol (const char* s);
int __fastcall__ atexit (void (*exitfunc) (void));
void* __fastcall__ bsearch (const void* key, const void* base, size_t n,
- size_t size, int (*cmp) (const void*, const void*));
+ size_t size, int __fastcall__ (* cmp) (const void*, const void*));
div_t __fastcall__ div (int numer, int denom);
void __fastcall__ exit (int ret) __attribute__ ((noreturn));
char* __fastcall__ getenv (const char* name);
void __fastcall__ qsort (void* base, size_t count, size_t size,
- int (*compare) (const void*, const void*));
+ int __fastcall__ (* compare) (const void*, const void*));
long __fastcall__ strtol (const char* nptr, char** endptr, int base);
unsigned long __fastcall__ strtoul (const char* nptr, char** endptr, int base);
int __fastcall__ system (const char* s);
#elif defined(__NES__)
# define CLK_TCK 50 /* POSIX */
# define CLOCKS_PER_SEC 50 /* ANSI */
+#elif defined(__PCE__)
+# define CLK_TCK 60 /* POSIX */
+# define CLOCKS_PER_SEC 60 /* ANSI */
#elif defined(__GEOS__)
# define CLK_TCK 1 /* POSIX */
# define CLOCKS_PER_SEC 1 /* ANSI */
/* */\r
/* */\r
/* */\r
-/* (C) 2000-2001 Piotr Fusik <fox@scene.pl> */\r
+/* (C) 2000-2015 Piotr Fusik <fox@scene.pl> */\r
/* */\r
/* This file is based on the zlib.h from 'zlib' general purpose compression */\r
/* library, version 1.1.3, (C) 1995-1998 Jean-loup Gailly and Mark Adler. */\r
*/\r
\r
\r
-int uncompress (char* dest, unsigned* destLen,\r
- const char* source, unsigned sourceLen);\r
+int __fastcall__ uncompress (char* dest, unsigned* destLen,\r
+ const char* source, unsigned sourceLen);\r
/*\r
Original zlib description:\r
\r
$(GEOS) \
lynx \
nes \
+ osic1p \
+ pce \
sim6502 \
sim65c02 \
supervision
.import callmain
.import __LC_START__, __LC_LAST__ ; Linker generated
.import __INIT_RUN__, __INIT_SIZE__ ; Linker generated
- .import __ZPSAVE_RUN__ ; Linker generated
+ .import __INITBSS_RUN__ ; Linker generated
.include "zeropage.inc"
.include "apple2.inc"
bit $C081
; Set the source start address.
- lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
- ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
+ lda #<(__INITBSS_RUN__ + __INIT_SIZE__)
+ ldy #>(__INITBSS_RUN__ + __INIT_SIZE__)
sta $9B
sty $9C
; Set the source last address.
- lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
- ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
+ lda #<(__INITBSS_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
+ ldy #>(__INITBSS_RUN__ + __INIT_SIZE__ + __LC_LAST__ - __LC_START__)
sta $96
sty $97
sta $94
sty $95
- ; Call into the Applesoft Block Transfer Utility -- which handles zero-
+ ; Call into Applesoft Block Transfer Up -- which handles zero-
; sized blocks well -- to move the content of the LC memory area.
- jsr $D396 ; BLTU + 3
+ jsr $D39A ; BLTU2
; Set the source start address.
- lda #<__ZPSAVE_RUN__
- ldy #>__ZPSAVE_RUN__
+ lda #<__INITBSS_RUN__
+ ldy #>__INITBSS_RUN__
sta $9B
sty $9C
; Set the source last address.
- lda #<(__ZPSAVE_RUN__ + __INIT_SIZE__)
- ldy #>(__ZPSAVE_RUN__ + __INIT_SIZE__)
+ lda #<(__INITBSS_RUN__ + __INIT_SIZE__)
+ ldy #>(__INITBSS_RUN__ + __INIT_SIZE__)
sta $96
sty $97
sta $94
sty $95
- ; Call into the Applesoft Block Transfer Utility -- which handles moving
+ ; Call into Applesoft Block Transfer Up -- which handles moving
; overlapping blocks upwards well -- to move the INIT segment.
- jsr $D396 ; BLTU + 3
+ jsr $D39A ; BLTU2
; Delegate all further processing, to keep the STARTUP segment small.
jsr init
: sta sp
stx sp+1
- ; Enable interrupts, as old ProDOS versions (i.e. 1.1.1)
- ; jump to SYS and BIN programs with interrupts disabled.
- cli
-
; Call the module constructors.
jsr initlib
; Final jump when we're done
done: jmp DOSWARM ; Potentially patched at runtime
- .segment "ZPSAVE"
+ .segment "INITBSS"
zpsave: .res zpspace
jmp __mappederrno
_exec:
+ ; Save cmdline
+ sta ptr4
+ stx ptr4+1
+
; Get and push name
jsr popax
jsr pushname
bne oserr
+ ; ProDOS TechRefMan, chapter 5.1.5.1:
+ ; "The complete or partial pathname of the system program
+ ; is stored at $280, starting with a length byte."
+ ; In fact BASIC.SYSTEM does the same for BLOAD and BRUN of
+ ; binary programs so we should do the same too in any case
+ ; especially as _we_ rely on it in mainargs.s for argv[0]
+ ldy #$00
+ lda (sp),y
+ tay
+: lda (sp),y
+ sta $0280,y
+ dey
+ bpl :-
+
; Set pushed name
lda sp
ldx sp+1
lda mliparam + MLI::INFO::FILE_TYPE
cmp #$FF ; SYS file?
bne binary ; No, check for BIN file
+ sta file_type ; Save file type for cmdline handling
- ; ProDOS TechRefMan, chapter 5.1.5.1:
- ; "The complete or partial pathname of the system program
- ; is stored at $280, starting with a length byte."
- ldy #$00
- lda (sp),y
- tay
-: lda (sp),y
- sta $0280,y
- dey
- bpl :-
-
; SYS programs replace BASIC.SYSTEM so set in the ProDOS system bit map
; protection for pages $80 - $BF just in case BASIC.SYSTEM is there now
ldx #$0F ; Start with protection for pages $B8 - $BF
lda #%00000001 ; Protect only system global page
: sta $BF60,x ; Set protection for 8 pages
- lda #$00 ; Protect no page
+ lda #%00000000 ; Protect no page
dex
bpl :-
bmi prodos ; Branch always
dex
dex
dex
-
+
; Set I/O buffer
sta mliparam + MLI::OPEN::IO_BUFFER
stx mliparam + MLI::OPEN::IO_BUFFER+1
stx level
beq :+
dec LEVEL
-
+
; Open file
: lda #OPEN_CALL
ldx #OPEN_COUNT
bit $C080
.endif
+ ; Reset stack as we already passed
+ ; the point of no return anyway
+ ldx #$FF
+ txs
+
+ ; Store up to 127 chars of cmdline (if any)
+ ; including terminating zero in stack page
+ ldy #$00
+ lda ptr4+1 ; NULL?
+ beq :++ ; Yes, store as '\0'
+: lda (ptr4),y
+: sta $0100,y
+ beq :+ ; '\0' stored, done
+ iny
+ cpy #$7E
+ bcc :--
+ lda #$00 ; '\0'
+ beq :- ; Branch always
+
; Call loader stub after C libary shutdown
- lda #<target
+: lda #<target
ldx #>target
sta done+1
stx done+2
source: jsr $BF00
.byte READ_CALL
.word read_param
- bcs :+
+ bcs error
; Close program file
jsr $BF00
.byte CLOSE_CALL
.word close_param
- bcs :+
+ bcs error
+
+ ; Check for cmdline handling
+ lda $0100 ; Valid cmdline?
+ beq jump ; No, jump to program right away
+ ldx file_type ; SYS file?
+ bne system ; Yes, check for startup filename
+
+ ; Store REM and cmdline in BASIC input buffer
+ lda #$B2 ; REM token
+ bne :++ ; Branch always
+: inx
+ lda a:$0100-1,x
+: sta $0200,x
+ bne :--
+ beq jump ; Branch always
+
+ ; Check for startup filename support
+ ; ProDOS TechRefMan, chapter 5.1.5.1:
+ ; "$2000 is a jump instruction. $2003 and $2004 are $EE."
+system: lda $2000
+ cmp #$4C
+ bne jump
+ lda $2003
+ cmp #$EE
+ bne jump
+ lda $2004
+ cmp #$EE
+ bne jump
+
+ ; Store cmdline in startup filename buffer
+ ldx #$01
+: lda a:$0100-1,x
+ beq :+
+ sta $2006,x
+ inx
+ cpx $2005 ; Buffer full?
+ bcc :- ; No, continue
+: dex
+ stx $2006 ; Store cmdline length
; Go for it ...
- jmp (data_buffer)
+jump: jmp (data_buffer)
+
+file_type = * - source + target
+ .byte $00
read_param = * - source + target
.byte $04 ; PARAM_COUNT
; Quit to ProDOS dispatcher
quit = * - source + target
-: jsr $BF00
+error: jsr $BF00
.byte $65 ; QUIT
.word quit_param
jsr callmli
; Check for null prefix
- lda __cwd
+ ldx __cwd
beq done
; Remove length byte and trailing slash
- sta tmp1
- ldx #$01
-: lda __cwd,x
- sta __cwd - 1,x
+ dex
+ stx tmp1
+ ldx #$00
+: lda __cwd + 1,x
+ sta __cwd,x
inx
cpx tmp1
bcc :-
; Add terminating zero
lda #$00
- sta __cwd - 1,x
+ sta __cwd,x
done: rts
.byte $40 ; Alloc interrupt
.addr i_param
bcs prterr
+
+ ; Enable interrupts, as old ProDOS versions (i.e. 1.1.1)
+ ; jump to SYS and BIN programs with interrupts disabled.
+ cli
rts
; Print error message and exit
MAXARGS = 10
; ProDOS stores the filename in the second half of BASIC's input buffer, so
-; there are 128 characters left. At least 7 characters are necessary for the
-; CALLxxxx:REM so 121 characters may be used before overwriting the ProDOS
-; filename. As we don't want to put further restrictions on the command-line
-; length we reserve those 121 characters terminated by a zero.
+; there are 128 characters left. At least 1 character is necessary for the
+; REM so 127 characters (including the terminating zero) may be used before
+; overwriting the ProDOS filename. As we don't want to further restrict the
+; command-line length we reserve those 127 characters.
-BUF_LEN = 122
+BUF_LEN = 127
BASIC_BUF = $200
FNAM_LEN = $280
.bss
-buffer: .res BUF_LEN
\ No newline at end of file
+buffer: .res BUF_LEN
CLOSE_CALL = $CC
FILE_NOT_FOUND_ERR = $46
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ------------------------------------------------------------------------
.import __CODE_0300_SIZE__, __DATA_0300_SIZE__
.import __CODE_0300_LOAD__, __CODE_0300_RUN__
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ------------------------------------------------------------------------
-.segment "DATA_2000"
+ .segment "DATA_2000"
GET_FILE_INFO_PARAM:
.byte $0A ;PARAM_COUNT
ELLIPSES:
.byte " ...", $0D, $0D, $00
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ------------------------------------------------------------------------
-.segment "DATA_0300"
+ .segment "DATA_0300"
READ_PARAM:
.byte $04 ;PARAM_COUNT
FILE_NOT_FOUND:
.asciiz "... File Not Found"
-
+
ERROR_NUMBER:
.asciiz "... Error $"
PRESS_ANY_KEY:
.asciiz " - Press Any Key "
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ------------------------------------------------------------------------
-.segment "CODE_2000"
+ .segment "CODE_2000"
jmp :+
.byte $EE
.byte $EE
- .byte 65
-STARTUP:.res 65
+ .byte $7F
+STARTUP:.res $7F
; Reset stack
: ldx #$FF
; Relocate CODE_0300 and DATA_0300
ldx #<(__CODE_0300_SIZE__ + __DATA_0300_SIZE__)
-: lda __CODE_0300_LOAD__ - 1,x
- sta __CODE_0300_RUN__ - 1,x
+: lda __CODE_0300_LOAD__-1,x
+ sta __CODE_0300_RUN__-1,x
dex
bne :-
; Add trailing '\0' to pathname
tax
lda #$00
- sta PATHNAME + 1,x
+ sta PATHNAME+1,x
; Copy ProDOS startup filename and trailing '\0' to stack
ldx STARTUP
lda #$00
- beq :++ ; bra
-: lda STARTUP + 1,x
+ beq :++ ; Branch always
+: lda STARTUP+1,x
: sta STACK,x
dex
- bpl :--
+ bpl :--
; Provide some user feedback
lda #<LOADING
ldx #>LOADING
jsr PRINT
- lda #<(PATHNAME + 1)
- ldx #>(PATHNAME + 1)
+ lda #<(PATHNAME+1)
+ ldx #>(PATHNAME+1)
jsr PRINT
lda #<ELLIPSES
ldx #>ELLIPSES
; Get load address from aux-type
lda FILE_INFO_ADDR
- ldx FILE_INFO_ADDR + 1
+ ldx FILE_INFO_ADDR+1
sta READ_ADDR
- stx READ_ADDR + 1
+ stx READ_ADDR+1
; It's high time to leave this place
jmp __CODE_0300_RUN__
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ------------------------------------------------------------------------
-.segment "CODE_0300"
+ .segment "CODE_0300"
jsr MLI
.byte READ_CALL
.word CLOSE_PARAM
bcs ERROR
- ; Copy REM token and startup filename to BASIC input buffer
+ ; Copy REM and startup filename to BASIC input buffer
ldx #$00
- lda #$B2
- bne :++ ; bra
+ lda #$B2 ; REM token
+ bne :++ ; Branch always
: inx
- lda a:STACK - 1,x
+ lda a:STACK-1,x
: sta BUF,x
bne :--
-
+
; Go for it ...
jmp (READ_ADDR)
: ora #$80
jsr COUT
iny
- bne :-- ; bra
+ bne :-- ; Branch always
: rts
ERROR:
lda #<FILE_NOT_FOUND
ldx #>FILE_NOT_FOUND
jsr PRINT
- beq :++ ; bra
+ beq :++ ; Branch always
: pha
lda #<ERROR_NUMBER
ldx #>ERROR_NUMBER
jsr MLI
.byte QUIT_CALL
.word QUIT_PARAM
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
.include "atari.inc"
- .constructor detect,26
+ .constructor detect, 26
.export __dos_type
; ------------------------------------------------------------------------
.import __argc, __argv
.importzp ptr1
.import __dos_type
- .constructor initmainargs,25
+ .constructor initmainargs, 25
; --------------------------------------------------------------------------
; Get command line
.export __getdefdev ; get default device
.export __defdev ; this is the default device string (e.g. "D1:")
.ifdef DYNAMIC_DD
- .constructor __getdefdev,24
+ .constructor __getdefdev, 24
.endif
; Get default device (LBUF will be destroyed!!)
.proc initcwd
+ lda #0
+ sta __cwd
jsr findfreeiocb
bne oserr
lda #GETCWD
sta ICBLH,x
jsr CIOV
bmi oserr
- ldx #0 ; ATEOL -> \0
-: lda __cwd,x
- inx
+ ldx #$FF ; ATEOL -> \0
+: inx
+ lda __cwd,x
cmp #ATEOL
bne :-
lda #0
- sta __cwd-1,x
+ sta __cwd,x
oserr: rts
.endproc
.include "atari.inc"
.importzp sp
.export _mouse_pm_callbacks
- .constructor pm_init,27
- .destructor pm_down,7
+ .constructor pm_init, 27
+ .destructor pm_down
; get mouse shape data
.import mouse_pm_bits
SCREEN_BUF_SIZE = 20 * 24
SCREEN_BUF = $4000 - SCREEN_BUF_SIZE
- .code
.export screen_setup_20x24
+ .segment "INIT"
+
screen_setup_20x24:
; initialize SAVMSC
.assert ((* >> 10) = (dlist >> 10)), error, "Display list crosses 1K boundary"
-
.end
--- /dev/null
+;
+; 2010-11-14, Ullrich von Bassewitz
+; 2014-09-06, Greg King
+;
+; This module supplies a small BASIC stub program that uses CALL
+; to jump to the machine-language code that follows it.
+;
+
+ ; The following symbol is used by the linker config. file
+ ; to force this module to be included into the output file.
+ .export __BASHDR__:abs = 1
+
+
+.segment "BASHDR"
+
+ .addr Next
+ .word .version ; Line number
+ .byte $BF,'#' ; CALL token, mark number as hexadecimal
+ .byte <(Start >> 8 ) + '0' + (Start >> 8 > $09) * $07
+ .byte <(Start >> 4 & $0F) + '0' + (Start >> 4 & $0F > $09) * $07
+ .byte <(Start & $0F) + '0' + (Start & $0F > $09) * $07
+ .byte $00 ; End of BASIC line
+Next: .addr $0000 ; BASIC program end marker
+Start:
; Startup code for cc65 (Oric version)
;
; By Debrune Jérôme <jede@oric.org> and Ullrich von Bassewitz <uz@cc65.org>
-; 2014-08-22, Greg King
+; 2015-01-09, Greg King
;
.export _exit
.export __STARTUP__ : absolute = 1 ; Mark as startup
.import initlib, donelib
.import callmain, zerobss
- .import __RAM_START__, __RAM_SIZE__
- .import __ZPSAVE_LOAD__, __STACKSIZE__
+ .import __RAM_START__, __RAM_SIZE__, __STACKSIZE__
.include "zeropage.inc"
.include "atmos.inc"
-; ------------------------------------------------------------------------
-; Oric tape header
-
-.segment "TAPEHDR"
-
- .byte $16, $16, $16 ; Sync bytes
- .byte $24 ; End of header marker
-
- .byte $00 ; $2B0
- .byte $00 ; $2AF
- .byte $80 ; $2AE Machine code flag
- .byte $C7 ; $2AD Autoload flag
- .dbyt __ZPSAVE_LOAD__ - 1 ; $2AB
- .dbyt __RAM_START__ ; $2A9
- .byte $00 ; $2A8
- .byte ((.VERSION >> 8) & $0F) + '0'
- .byte ((.VERSION >> 4) & $0F) + '0'
- .byte (.VERSION & $0F) + '0'
- .byte $00 ; Zero terminated compiler version
-
; ------------------------------------------------------------------------
; Place the startup code in a special segment.
jsr zerobss
-; Unprotect screen columns 0 and 1.
+; Currently, color isn't supported on the text screen.
+; Unprotect screen columns 0 and 1 (where each line's color codes would sit).
lda STATUS
sta stsave
; Call the module destructors. This is also the exit() entry.
-_exit: jsr donelib ; Run module destructors
+_exit: jsr donelib
; Restore the system stuff.
; ------------------------------------------------------------------------
-.segment "ZPSAVE"
+.segment "ZPSAVE1"
+
+zpsave:
+
+; This padding is needed by a bug in the ROM.
+; (The CLOAD command starts BASIC's variables table on top of the last byte
+; that was loaded [instead of at the next address].)
+; This is overlaid on a buffer, so that it doesn't use extra space in RAM.
+
+ .byte 0
+
+; The segments "ZPSAVE1" and "ZPSAVE2" always must be together.
+; They create a single object (the zpsave buffer).
+
+.segment "ZPSAVE2"
-zpsave: .res zpspace
+ .res zpspace - 1
; ------------------------------------------------------------------------
--- /dev/null
+;
+; Based on code by Debrune Jérôme <jede@oric.org>
+; 2015-01-08, Greg King
+;
+
+ ; The following symbol is used by the linker config. file
+ ; to force this module to be included into the output file.
+ .export __TAPEHDR__:abs = 1
+
+ ; These symbols, also, come from the configuration file.
+ .import __BASHDR_LOAD__, __ZPSAVE1_LOAD__, __AUTORUN__, __PROGFLAG__
+
+
+; ------------------------------------------------------------------------
+; Oric cassette-tape header
+
+.segment "TAPEHDR"
+
+ .byte $16, $16, $16 ; Sync bytes
+ .byte $24 ; Beginning-of-header marker
+
+ .byte $00 ; $2B0
+ .byte $00 ; $2AF
+ .byte <__PROGFLAG__ ; $2AE Language flag ($00=BASIC, $80=machine code)
+ .byte <__AUTORUN__ ; $2AD Auto-run flag ($C7=run, $00=only load)
+ .dbyt __ZPSAVE1_LOAD__ ;$2AB Address of end of file
+ .dbyt __BASHDR_LOAD__ ; $2A9 Address of start of file
+ .byte $00 ; $2A8
+
+ ; File name (a maximum of 17 characters), zero-terminated
+ .asciiz .sprintf("%u", .time)
; ------------------------------------------------------------------------
; Data
-.segment "ZPSAVE"
+.segment "INITBSS"
zpsave: .res zpspace
; Data.
.bss
-curpage: .res 1 ; Current page number
+curpage: .res 2 ; Current page number
window: .res 256 ; Memory "window"
stx curpage+1 ; Invalidate the current page
inx
txa ; A = X = EM_ERR_OK
- rts
+; rts ; Run into UNINSTALL instead
; ------------------------------------------------------------------------
; UNINSTALL routine. Is called before the driver is removed from memory.
lda #<ptr1
sta FETVEC
+ sei
; Transfer one page
sta window,y
iny
bne @L1
+ cli
; Return the memory window
lda #<ptr1
sta STAVEC
+ sei
; Transfer one page. Y must be zero on entry
jsr STASH
iny
bne @L1
+ cli
; Done
; Copy full pages
ldy #$00
+ sei
@L1: ldx #MMU_CFG_RAM1
jsr FETCH
sta (ptr2),y
; Done
-@L4: rts
+@L4: cli
+ rts
; ------------------------------------------------------------------------
; COPYTO: Copy from linear into extended memory. A pointer to a structure
; Copy full pages
ldy #$00
+ sei
@L1: lda (ptr2),y
ldx #MMU_CFG_RAM1
jsr STASH
; Done
-@L4: rts
-
+@L4: cli
+ rts
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
-
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNAM_LEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda #FNAM ; Load vector address for FETCH routine
ldx FNAM_BANK ; Load bank for FETCH routine
jsr INDFET ; Load byte from (FETVEC),y
- sta name,y ; Save byte from filename
-L1: dey
+L1: sta name,y ; Save byte from filename
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
-
; be called from an interrupt handler
;
+ .constructor initmcb
.export _mouse_def_callbacks
+ .import _mouse_def_pointershape
+ .import _mouse_def_pointercolor
.include "mouse-kernel.inc"
.include "c128.inc"
.macpack generic
; Sprite definitions. The first value can be changed to adjust the number
-; of the sprite used for the mouse.
+; of the sprite used for the mouse. All others depend on this value.
MOUSE_SPR = 0 ; Sprite used for the mouse
+MOUSE_SPR_MEM = $0E00 ; Memory location
MOUSE_SPR_MASK = $01 .shl MOUSE_SPR ; Positive mask
MOUSE_SPR_NMASK = .lobyte(.not MOUSE_SPR_MASK) ; Negative mask
VIC_SPR_X = (VIC_SPR0_X + 2*MOUSE_SPR) ; Sprite X register
VIC_SPR_Y = (VIC_SPR0_Y + 2*MOUSE_SPR) ; Sprite Y register
+; --------------------------------------------------------------------------
+; Initialize the mouse sprite.
+
+.segment "INIT"
+
+initmcb:
+
+; Copy the mouse sprite data
+
+ ldx #64 - 1
+@L0: lda _mouse_def_pointershape,x
+ sta MOUSE_SPR_MEM,x
+ dex
+ bpl @L0
+
+; Set the mouse sprite pointer
+
+ lda #<(MOUSE_SPR_MEM / 64)
+ sta $07F8 + MOUSE_SPR
+
+; Set the mouse sprite color
+
+ lda _mouse_def_pointercolor
+ sta VIC_SPR0_COLOR + MOUSE_SPR
+ rts
+
; --------------------------------------------------------------------------
; Hide the mouse pointer. Always called with interrupts disabled.
+.code
+
hide:
lda #MOUSE_SPR_NMASK
and VIC_SPR_ENA
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
__randomize:
ldx VIC_HLINE ; Use VIC rasterline as high byte
- lda TIME ; Use 60HZ clock as low byte
+ lda TIME+2 ; Use 60HZ clock as low byte
jmp _srand ; Initialize generator
; Constructor that writes to the 1/10 sec register of the TOD to kick it
; into action. If this is not done, the clock hangs. We will read the register
; and write it again, ignoring a possible change in between.
+.segment "INIT"
.proc initsystime
.endproc
-
;----------------------------------------------------------------------------
; TM struct with date set to 1970-01-01
.data
.word 0 ; tm_wday
.word 0 ; tm_yday
.word 0 ; tm_isdst
-
; ------------------------------------------------------------------------
-.segment "ZPSAVE"
+.segment "INITBSS"
zpsave: .res zpspace
.include "plus4.inc"
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNAM_LEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda #FNAM ; Vector address
jsr FETCH ; Load byte from RAM
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
-
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
__randomize:
ldx TED_VLINELO ; Use TED rasterline as high byte
- lda TIME ; Use 60HZ clock as low byte
+ lda TIME+2 ; Use 60HZ clock as low byte
jmp _srand ; Initialize generator
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+ .export _bordercolor
+
+ .include "c64.inc"
+
+_bordercolor:
+ ldx VIC_BORDERCOLOR ; get old value
+ sta VIC_BORDERCOLOR ; set new value
+ txa
+ rts
+
;
; unsigned char __fastcall__ textcolor (unsigned char color);
; unsigned char __fastcall__ bgcolor (unsigned char color);
-; unsigned char __fastcall__ bordercolor (unsigned char color);
;
- .export _textcolor, _bgcolor, _bordercolor
+ .export _textcolor, _bgcolor
.include "c64.inc"
sta VIC_BG_COLOR0 ; set new value
txa
rts
-
-
-_bordercolor:
- ldx VIC_BORDERCOLOR ; get old value
- sta VIC_BORDERCOLOR ; set new value
- txa
- rts
-
.export _exit
.export __STARTUP__ : absolute = 1 ; Mark as startup
+
.import initlib, donelib
- .import zerobss
- .import callmain
- .import RESTOR, BSOUT, CLRCH
- .import __RAM_START__, __RAM_SIZE__ ; Linker generated
- .import __STACKSIZE__ ; Linker generated
+ .import moveinit, zerobss, callmain
+ .import BSOUT
+ .import __MAIN_START__, __MAIN_SIZE__ ; Linker generated
+ .import __STACKSIZE__ ; from configure file
.importzp ST
.include "zeropage.inc"
Start:
-; Save the zero-page locations that we need.
-
- ldx #zpspace-1
-L1: lda sp,x
- sta zpsave,x
- dex
- bpl L1
-
; Switch to the second charset.
lda #14
; Switch off the BASIC ROM.
lda $01
- pha ; Remember the value
+ sta mmusave ; Save the memory configuration
and #$F8
ora #$06 ; Enable Kernal+I/O, disable BASIC
sta $01
-; Clear the BSS data.
+ tsx
+ stx spsave ; Save the system stack ptr
- jsr zerobss
+; Allow some re-entrancy by skipping the next task if it already was done.
+; This sometimes can let us rerun the program without reloading it.
-; Save some system settings; and, set up the stack.
+ ldx move_init
+ beq L0
- pla
- sta mmusave ; Save the memory configuration
+; Move the INIT segment from where it was loaded (over the bss segments)
+; into where it must be run (over the BSS segment).
- tsx
- stx spsave ; Save the system stack ptr
+ jsr moveinit
+ dec move_init ; Set to false
- lda #<(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
- sta sp
- lda #>(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
- sta sp+1 ; Set argument stack ptr
+; Save space by putting some of the start-up code in the INIT segment,
+; which can be re-used by the BSS segment, the heap and the C stack.
-; Call the module constructors.
+L0: jsr runinit
- jsr initlib
+; Clear the BSS data.
+
+ jsr zerobss
; Push the command-line arguments; and, call main().
rts
+
; ------------------------------------------------------------------------
-; Data
-.segment "ZPSAVE"
+.segment "INIT"
-zpsave: .res zpspace
+runinit:
-.bss
+; Save the zero-page locations that we need.
+
+ ldx #zpspace-1
+L1: lda sp,x
+ sta zpsave,x
+ dex
+ bpl L1
+
+; Set up the stack.
+
+ lda #<(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
+ ldx #>(__MAIN_START__ + __MAIN_SIZE__ + __STACKSIZE__)
+ sta sp
+ stx sp+1 ; Set argument stack ptr
+
+; Call the module constructors.
+
+ jmp initlib
+
+
+; ------------------------------------------------------------------------
+; Data
+
+.data
+
+; These two variables were moved out of the BSS segment, and into DATA, because
+; we need to use them before INIT is moved off of BSS, and before BSS is zeroed.
-spsave: .res 1
mmusave:.res 1
+spsave: .res 1
+
+move_init:
+ .byte 1
+
+.segment "INITBSS"
+
+zpsave: .res zpspace
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; import/overload stubs for the soft80 implementation
+
+ .include "../soft80.inc"
+
+ ; soft80_cgetc.s
+ .import soft80_cgetc
+ .export _cgetc := soft80_cgetc ; cgetc.s
+
+ ; soft80_color.s
+ .import soft80_textcolor
+ .import soft80_bgcolor
+ .export _textcolor := soft80_textcolor ; color.s
+ .export _bgcolor := soft80_bgcolor ; color.s
+
+ ; soft80_cputc.s
+ .import soft80_cputc
+ .import soft80_cputcxy
+ .import soft80_cputdirect
+ .import soft80_putchar
+ .import soft80_newline
+ .import soft80_plot
+ .export _cputc := soft80_cputc ; cputc.s
+ .export _cputcxy := soft80_cputcxy ; cputc.s
+ .export cputdirect := soft80_cputdirect ; cputc.s
+ .export putchar := soft80_putchar ; cputc.s
+ .export newline := soft80_newline ; cputc.s
+ .export plot := soft80_plot ; cputc.s
+
+ ; soft80_kclrscr.s
+ .import soft80_kclrscr
+ .export _clrscr := soft80_kclrscr ; clrscr.s
+
+ ; soft80_kplot.s
+ .import soft80_kplot
+ .export PLOT := soft80_kplot ; kplot.s
+
+ ; soft80_kscreen.s
+ .import soft80_screensize
+ .export screensize := soft80_screensize ; _scrsize.s
+ ; FIXME: use _scrsize.s/remove soft80_scrsize.s
+ ;.export SCREEN := soft80_screensize ; kernal func (kernal.s)
+
+ ; VIC sprite data for the mouse pointer
+ .export mcb_spritememory := soft80_spriteblock
+ .export mcb_spritepointer := (soft80_vram + $03F8)
+
+ ; Chars used by chline () and cvline ()
+ .exportzp chlinechar = CH_HLINE
+ .exportzp cvlinechar = CH_VLINE
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; import/overload stubs for the monochrome soft80 implementation
+;
+; - optimized for size, almost 1k smaller footprint than the full color version
+; - textcolor() sets one common text color for the whole screen
+;
+ .include "../soft80.inc"
+
+ ; soft80mono_cgetc.s
+ .import soft80mono_cgetc
+ .export _cgetc := soft80mono_cgetc ; cgetc.s
+
+ ; soft80mono_color.s
+ .import soft80mono_textcolor
+ .import soft80mono_bgcolor
+ .export _textcolor := soft80mono_textcolor ; color.s
+ .export _bgcolor := soft80mono_bgcolor ; color.s
+
+ ; soft80mono_cputc.s
+ .import soft80mono_cputc
+ .import soft80mono_cputcxy
+ .import soft80mono_cputdirect
+ .import soft80mono_putchar
+ .import soft80mono_newline
+ .import soft80mono_plot
+ .export _cputc := soft80mono_cputc ; cputc.s
+ .export _cputcxy := soft80mono_cputcxy ; cputc.s
+ .export cputdirect := soft80mono_cputdirect ; cputc.s
+ .export putchar := soft80mono_putchar ; cputc.s
+ .export newline := soft80mono_newline ; cputc.s
+ .export plot := soft80mono_plot ; cputc.s
+
+ ; soft80mono_kclrscr.s
+ .import soft80mono_kclrscr
+ .export _clrscr := soft80mono_kclrscr ; clrscr.s
+
+ ; soft80mono_kplot.s
+ .import soft80mono_kplot
+ .export PLOT := soft80mono_kplot ; kplot.s
+
+ ; soft80_kscreen.s
+ .import soft80_screensize
+ .export screensize := soft80_screensize ; _scrsize.s
+ ; FIXME: use _scrsize.s/remove soft80_scrsize.s
+ ;.export SCREEN := soft80_screensize ; kernal func (kernal.s)
+
+ ; VIC sprite data for the mouse pointer
+ .export mcb_spritememory := soft80_spriteblock
+ .export mcb_spritepointer := (soft80_vram + $03F8)
+
+ ; Chars used by chline () and cvline ()
+ .exportzp chlinechar = CH_HLINE
+ .exportzp cvlinechar = CH_VLINE
.include "c64.inc"
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNAM_LEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (FNAM),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
-
; be called from an interrupt handler
;
+ .constructor initmcb
.export _mouse_def_callbacks
+ .import _mouse_def_pointershape
+ .import _mouse_def_pointercolor
+ .import mcb_spritememory
+ .import mcb_spritepointer
.include "mouse-kernel.inc"
.include "c64.inc"
VIC_SPR_X = (VIC_SPR0_X + 2*MOUSE_SPR) ; Sprite X register
VIC_SPR_Y = (VIC_SPR0_Y + 2*MOUSE_SPR) ; Sprite Y register
+; --------------------------------------------------------------------------
+; Initialize the mouse sprite.
+
+.segment "INIT"
+
+initmcb:
+
+; Make all RAM accessible
+
+ lda #$30
+ ldy $01
+ sei
+ sta $01
+
+; Copy the mouse sprite data
+
+ ldx #64 - 1
+@L0: lda _mouse_def_pointershape,x
+ sta mcb_spritememory,x
+ dex
+ bpl @L0
+
+; Set the mouse sprite pointer
+
+ lda #<(mcb_spritememory / 64)
+ sta mcb_spritepointer + MOUSE_SPR
+
+; Restore memory configuration
+
+ sty $01
+ cli
+
+; Set the mouse sprite color
+
+ lda _mouse_def_pointercolor
+ sta VIC_SPR0_COLOR + MOUSE_SPR
+ rts
+
; --------------------------------------------------------------------------
; Hide the mouse pointer. Always called with interrupts disabled.
+.code
+
hide:
lda #MOUSE_SPR_NMASK
and VIC_SPR_ENA
--- /dev/null
+; VIC sprite data for the mouse pointer
+
+ .export mcb_spritememory := $0340
+ .export mcb_spritepointer := $07F8
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
__randomize:
ldx VIC_HLINE ; Use VIC rasterline as high byte
- lda TIME ; Use 60HZ clock as low byte
+ lda TIME+2 ; Use 60HZ clock as low byte
jmp _srand ; Initialize generator
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; internal constants for the soft80 implementation
+
+soft80_lo_charset = $d000
+soft80_hi_charset = $d400
+soft80_vram = $d800 ; ram under i/o
+soft80_colram = $d800 ; color ram (used for temp. storage)
+soft80_spriteblock = $dc00 ; 64 bytes reserved for pointer sprite data
+
+; tables for kplot
+soft80_bitmapxlo = $dc40 ; (80 bytes)
+soft80_bitmapxhi = $dc40 + 80 ; (80 bytes)
+soft80_vramlo = $dc40 + 160 ; (25 bytes)
+; align to next page for speed
+soft80_vramhi = $dd00 ; (25 bytes)
+soft80_bitmapylo = $dd00 + 25 ; (25 bytes)
+soft80_bitmapyhi = $dd00 + 50 ; (25 bytes)
+
+soft80_bitmap = $e000
+
+charsperline = 80
+screenrows = 25
+
+; FIXME: these should match petscii and perhaps come from a common cbm.inc?
+CH_ESC = 95
+CH_HLINE = 96
+CH_CROSS = 123
+CH_VLINE = 125
+CH_PI = 126
+CH_LTEE = 171
+CH_URCORNER = 174
+CH_LLCORNER = 173
+CH_ULCORNER = 176
+CH_BTEE = 177
+CH_TTEE = 178
+CH_RTEE = 179
+CH_LRCORNER = 189
+
+;-------------------------------------------------------------------------------
+; set to 0 to disable the color-ram "voodoo" for debugging purposes
+.define SOFT80COLORVOODOO 1
+; set to 0 to disable special case optimization for the "space" character
+.define SOFT80FASTSPACE 1
+
--- /dev/null
+;
+; Groepaz/Hitmen, 11.10.2015
+;
+; high level implementation for the soft80 implementation
+;
+; char cgetc (void);
+;
+
+ .export soft80_cgetc
+ .import soft80_internal_cellcolor, soft80_internal_cursorxlsb
+ .import cursor
+ .importzp tmp1
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_cgetc:
+ lda KEY_COUNT ; Get number of characters
+ bne @L3 ; Jump if there are already chars waiting
+
+ sec
+ jsr invertcursor ; set cursor on or off accordingly
+
+@L1: lda KEY_COUNT ; wait for key
+ beq @L1
+
+ clc
+ jsr invertcursor ; set cursor on or off accordingly
+
+@L3: jsr KBDREAD ; Read char and return in A
+ ldx #0
+ rts
+
+; Switch the cursor on or off (invert)
+
+invertcursor:
+ lda cursor
+ bne @invert
+ rts
+@invert:
+
+ sei
+ lda $01 ; enable RAM under I/O
+ pha
+ lda #$34
+ sta $01
+
+ ldy #$00
+ jsr setcolor
+
+ ldx soft80_internal_cursorxlsb
+@lp1:
+ lda (SCREEN_PTR),y
+ eor nibble,x
+ sta (SCREEN_PTR),y
+ iny
+ cpy #8
+ bne @lp1
+
+ pla
+ sta $01 ; enable I/O
+ cli
+ rts
+
+ ; do not use soft80_putcolor here to make sure the cursor is always
+ ; shown using the current textcolor without disturbing the "color voodoo"
+ ; in soft80_cputc
+setcolor:
+ ;ldy #0 ; is 0
+ bcs @set
+ ; restore old value
+ lda tmp1
+ sta (CRAM_PTR),y ; vram
+ rts
+@set:
+ ; save old value
+ lda (CRAM_PTR),y ; vram
+ sta tmp1
+ lda soft80_internal_cellcolor
+ sta (CRAM_PTR),y ; vram
+ rts
+
+ .rodata
+nibble: .byte $f0, $0f
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80_init
+conio_init = soft80_init
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; character set for use with the soft80 implementations
+;
+
+; the format of the data follows the following layout:
+;
+; - to avoid unnecessary petscii->screencode conversions, the order of the
+; individual characters is different to the C64 ROM charset:
+; - $00 - $1f screencodes $60 - $7f (petscii codes $a0 - $bf)
+; - $20 - $3f screencodes $20 - $3f (petscii codes $20 - $3f)
+; - $40 - $5f screencodes $00 - $1f (petscii codes $40 - $5f)
+; - $60 - $7f screencodes $40 - $5f (petscii codes $60 - $7f)
+; - only 128 characters are defined here, the soft80 implementation will invert
+; the graphics data for inverted display on the fly.
+; - since the charset is 4 by 8 pixels, only the lower 4bit of each byte is
+; used. the upper bits have to be 0.
+; - finally the lower 4bits are "inverted", ie a space character is represented
+; as $0f, $0f, $0f, $0f, $0f, $0f, $0f, $0f
+;
+; the graphics data is arranged differently to normal C64 charsets for speed,
+; first comes the first row of all characters, then the second row in the next
+; block, etc. like this:
+;
+; +000 ....xxxx ......xx ....xxxx ........
+; +080 ....xxxx ......xx ....xxxx ....xxxx
+; +100 ....xxxx ......xx ....xxxx ....xxxx
+; +180 ....x..x ......xx ....xxxx ....xxxx
+; +200 ....x..x ......xx ........ ....xxxx
+; +280 ....xxxx ......xx ........ ....xxxx
+; +300 ....xxxx ......xx ........ ....xxxx
+; +380 ....xxxx ......xx ........ ....xxxx
+; [...]
+; +040 ....x.xx ....xxxx ....xxxx ....xxxx
+; +0c0 .....x.x ....xxxx .....xxx ....xxxx
+; +140 .......x ....x.xx .....xxx ....x..x
+; +1c0 .......x ....xx.x ......xx .....xxx
+; +240 .....xxx ....x..x .....x.x .....xxx
+; +2c0 .....x.x .....x.x .....x.x .....xxx
+; +340 ....x.xx ....x..x ......xx ....x..x
+; +3c0 ....xxxx ....xxxx ....xxxx ....xxxx
+
+ .export soft80_charset
+
+ .segment "INIT"
+soft80_charset:
+ .byte $0f,$03,$0f,$00,$0f,$07,$05,$0e
+ .byte $0f,$05,$0e,$0b,$0f,$0b,$0f,$0f
+ .byte $0f,$0b,$0f,$0b,$07,$07,$0e,$00
+ .byte $00,$0f,$0e,$0f,$0c,$0b,$03,$03
+ .byte $0f,$0b,$05,$05,$0b,$05,$0b,$0b
+ .byte $0d,$07,$0f,$0f,$0f,$0f,$0f,$0d
+ .byte $0b,$0b,$0b,$0b,$05,$01,$0b,$01
+ .byte $0b,$0b,$0f,$0f,$0d,$0f,$07,$0b
+ .byte $0b,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$09,$07,$03,$0b,$0f
+ .byte $0f,$0b,$03,$0b,$03,$01,$01,$0b
+ .byte $05,$01,$09,$05,$07,$05,$05,$0b
+ .byte $03,$0b,$03,$0b,$01,$05,$05,$05
+ .byte $05,$05,$01,$0b,$07,$0b,$0f,$0a
+
+ .byte $0f,$03,$0f,$0f,$0f,$07,$05,$0e
+ .byte $0f,$0a,$0e,$0b,$0f,$0b,$0f,$0f
+ .byte $0f,$0b,$0f,$0b,$07,$07,$0e,$00
+ .byte $00,$0f,$0e,$0f,$0c,$0b,$03,$03
+ .byte $0f,$0b,$05,$05,$09,$05,$05,$0b
+ .byte $0b,$0b,$05,$0b,$0f,$0f,$0f,$0d
+ .byte $05,$0b,$05,$05,$05,$07,$05,$05
+ .byte $05,$05,$0f,$0f,$0b,$0f,$0b,$05
+ .byte $05,$0f,$07,$0f,$0d,$0f,$09,$0f
+ .byte $07,$0b,$0d,$07,$03,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0b,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0b,$07,$0b,$0b,$0b
+ .byte $0f,$0b,$05,$05,$05,$07,$07,$05
+ .byte $05,$0b,$0d,$05,$07,$01,$01,$05
+ .byte $05,$05,$05,$05,$0b,$05,$05,$05
+ .byte $05,$05,$0d,$0b,$07,$0b,$0f,$0a
+
+ .byte $0f,$03,$0f,$0f,$0f,$07,$0a,$0e
+ .byte $0f,$05,$0e,$0b,$0f,$0b,$0f,$0f
+ .byte $0f,$0b,$0f,$0b,$07,$07,$0e,$0f
+ .byte $00,$0f,$0d,$0f,$0c,$0b,$03,$03
+ .byte $0f,$0b,$05,$00,$07,$0d,$0b,$07
+ .byte $0b,$0b,$0b,$0b,$0f,$0f,$0f,$0b
+ .byte $01,$03,$0d,$0d,$05,$03,$07,$0d
+ .byte $05,$05,$0b,$0b,$0b,$08,$0b,$0d
+ .byte $01,$0b,$07,$09,$0d,$0b,$0b,$09
+ .byte $07,$0f,$0f,$07,$0b,$05,$03,$0b
+ .byte $03,$09,$03,$09,$01,$05,$05,$05
+ .byte $05,$05,$01,$0b,$0b,$0b,$05,$0b
+ .byte $0f,$05,$05,$07,$05,$07,$07,$07
+ .byte $05,$0b,$0d,$03,$07,$01,$01,$05
+ .byte $05,$05,$05,$07,$0b,$05,$05,$05
+ .byte $0b,$05,$0b,$0b,$0b,$0b,$0a,$05
+
+ .byte $09,$03,$0f,$0f,$0f,$07,$0a,$0e
+ .byte $0f,$0a,$0e,$08,$0f,$08,$03,$0f
+ .byte $08,$00,$00,$03,$07,$07,$0e,$0f
+ .byte $0f,$0f,$05,$0f,$0c,$03,$03,$03
+ .byte $0f,$0b,$0f,$05,$0b,$0b,$0b,$0f
+ .byte $0b,$0b,$01,$01,$0f,$01,$0f,$0b
+ .byte $05,$0b,$0b,$0b,$01,$0d,$03,$0b
+ .byte $0b,$09,$0f,$0f,$07,$0f,$0d,$0b
+ .byte $01,$0d,$03,$07,$09,$05,$01,$05
+ .byte $03,$03,$0d,$05,$0b,$01,$05,$05
+ .byte $05,$05,$05,$07,$0b,$05,$05,$05
+ .byte $05,$05,$0d,$0b,$0b,$0b,$05,$00
+ .byte $00,$01,$03,$07,$05,$03,$03,$01
+ .byte $01,$0b,$0d,$03,$07,$05,$01,$05
+ .byte $03,$05,$03,$0b,$0b,$05,$05,$01
+ .byte $0b,$0b,$0b,$00,$0b,$0b,$05,$05
+
+ .byte $09,$03,$00,$0f,$0f,$07,$05,$0e
+ .byte $05,$05,$0e,$08,$0c,$08,$03,$0f
+ .byte $08,$00,$00,$03,$07,$07,$0e,$0f
+ .byte $0f,$0f,$03,$03,$0f,$03,$0f,$0c
+ .byte $0f,$0f,$0f,$00,$0d,$07,$04,$0f
+ .byte $0b,$0b,$0b,$0b,$0f,$0f,$0f,$0b
+ .byte $05,$0b,$07,$0d,$0d,$0d,$05,$0b
+ .byte $05,$0d,$0f,$0f,$0b,$08,$0b,$0b
+ .byte $07,$09,$05,$07,$05,$01,$0b,$05
+ .byte $05,$0b,$0d,$03,$0b,$01,$05,$05
+ .byte $05,$05,$07,$0b,$0b,$05,$05,$01
+ .byte $0b,$05,$0b,$0b,$0b,$0b,$0f,$00
+ .byte $00,$05,$05,$07,$05,$07,$07,$05
+ .byte $05,$0b,$0d,$03,$07,$05,$01,$05
+ .byte $07,$05,$03,$0d,$0b,$05,$05,$01
+ .byte $0b,$0b,$0b,$00,$07,$0b,$05,$0a
+
+ .byte $0f,$03,$00,$0f,$0f,$07,$05,$0e
+ .byte $05,$0a,$0e,$0b,$0c,$0f,$0b,$0f
+ .byte $0b,$0f,$0b,$0b,$07,$07,$0e,$0f
+ .byte $0f,$00,$03,$03,$0f,$0f,$0f,$0c
+ .byte $0f,$0f,$0f,$05,$03,$05,$05,$0f
+ .byte $0b,$0b,$05,$0b,$0b,$0f,$0b,$07
+ .byte $05,$0b,$07,$05,$0d,$05,$05,$0b
+ .byte $05,$05,$0b,$0b,$0b,$0f,$0b,$0f
+ .byte $05,$05,$05,$07,$05,$07,$0b,$09
+ .byte $05,$0b,$0d,$05,$0b,$05,$05,$05
+ .byte $03,$09,$07,$0d,$0b,$05,$0b,$01
+ .byte $05,$09,$07,$0b,$0d,$0b,$0f,$0b
+ .byte $0f,$05,$05,$05,$05,$07,$07,$05
+ .byte $05,$0b,$05,$05,$07,$05,$05,$05
+ .byte $07,$0b,$05,$05,$0b,$05,$0b,$05
+ .byte $05,$0b,$07,$0b,$07,$0b,$05,$0a
+
+ .byte $0f,$03,$00,$0f,$0f,$07,$0a,$0e
+ .byte $0a,$05,$0e,$0b,$0c,$0f,$0b,$00
+ .byte $0b,$0f,$0b,$0b,$07,$07,$0e,$0f
+ .byte $0f,$00,$07,$03,$0f,$0f,$0f,$0c
+ .byte $0f,$0b,$0f,$05,$0b,$05,$08,$0f
+ .byte $0d,$07,$0f,$0f,$0b,$0f,$0b,$07
+ .byte $0b,$01,$01,$0b,$0d,$0b,$0b,$0b
+ .byte $0b,$0b,$0f,$0b,$0d,$0f,$07,$0b
+ .byte $0b,$09,$03,$09,$09,$09,$0b,$0d
+ .byte $05,$01,$0d,$05,$01,$05,$05,$0b
+ .byte $07,$0d,$07,$03,$0d,$09,$0b,$05
+ .byte $05,$0d,$01,$09,$0d,$03,$0f,$0b
+ .byte $0f,$05,$03,$0b,$03,$01,$07,$0b
+ .byte $05,$01,$0b,$05,$01,$05,$05,$0b
+ .byte $07,$0d,$05,$0b,$0b,$0b,$0b,$05
+ .byte $05,$0b,$01,$0b,$0b,$0b,$05,$05
+
+ .byte $0f,$03,$00,$0f,$00,$07,$0a,$0e
+ .byte $0a,$0a,$0e,$0b,$0c,$0f,$0b,$00
+ .byte $0b,$0f,$0b,$0b,$07,$07,$0e,$0f
+ .byte $0f,$00,$0f,$03,$0f,$0f,$0f,$0c
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$07,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$07,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$03
+ .byte $0f,$0f,$03,$0f,$0f,$0f,$0f,$0f
+ .byte $07,$0d,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$03,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ .byte $0f,$0f,$0f,$0b,$0b,$0b,$0f,$05
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; high level implementation for the soft80 implementation
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+;
+
+ .export soft80_textcolor, soft80_bgcolor
+ .import soft80_internal_cellcolor, soft80_internal_bgcolor
+ .import soft80_internal_cursorxlsb
+ .import soft80_kplot, soft80_checkchar
+
+ .importzp tmp1, tmp2
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_textcolor:
+ ldx CHARCOLOR ; get old value
+ sta CHARCOLOR ; set new value
+
+mkcharcolor:
+ lda soft80_internal_bgcolor
+ asl a
+ asl a
+ asl a
+ asl a
+ sta tmp1 ; remember new bg color (high nibble)
+ ora CHARCOLOR
+ sta soft80_internal_cellcolor ; text/bg combo for new chars
+
+ txa ; get old value
+ rts
+
+soft80_bgcolor:
+ ldx soft80_internal_bgcolor ; get old value
+ stx tmp2 ; save old value
+ sta soft80_internal_bgcolor ; set new value
+
+ jsr mkcharcolor
+
+ lda CURS_X
+ pha
+ lda CURS_Y
+ pha
+
+ ldy #0
+ ldx #0
+ clc
+ jsr soft80_kplot
+
+ sei
+ lda $01
+ pha
+ ldx #$34
+ stx $01 ; $34
+
+ ;ldy #0 ; is still 0
+
+ lda #24
+ sta CURS_Y
+lpy:
+ lda #39
+ sta CURS_X
+lpx:
+
+.if SOFT80COLORVOODOO = 1
+ ; if the old bg color is equal to color ram of that cell, then also
+ ; update the color ram to the new value.
+
+ inc $01 ; $35
+ lda (CRAM_PTR),y ; colram
+ stx $01 ; $34
+
+ and #$0f
+ cmp tmp2 ; old bg color
+ bne @sk1
+
+ ; if the left character in the cell is not a space, then dont update
+ ; the color ram
+ lda #1
+ sta soft80_internal_cursorxlsb
+ jsr soft80_checkchar
+ bcc @sk1
+ lda soft80_internal_bgcolor ; new bg color
+
+ inc $01 ; $35
+ sta (CRAM_PTR),y ; colram
+ stx $01 ; $34
+@sk1:
+.endif
+ ; if the old bg color is equal to text color in this cell, then also
+ ; update the text color to the new value.
+
+ lda (CRAM_PTR),y ; vram
+ and #$0f
+ cmp tmp2 ; old bg color
+ bne @sk2
+
+ ; if there are non space characters in the cell, do not update the
+ ; color ram
+ pha
+ lda #0
+ sta soft80_internal_cursorxlsb
+ jsr soft80_checkchar
+ pla
+ bcc @sk2
+
+ pha
+ inc soft80_internal_cursorxlsb
+ jsr soft80_checkchar
+ pla
+ bcc @sk2
+
+ lda soft80_internal_bgcolor ; new bg color
+@sk2:
+ ora tmp1 ; new bg color (high nibble)
+ sta (CRAM_PTR),y ; vram
+
+ inc CRAM_PTR
+ bne @sk3
+ inc CRAM_PTR+1
+@sk3:
+
+ lda SCREEN_PTR
+ clc
+ adc #8
+ sta SCREEN_PTR
+ bcc @sk4
+ inc SCREEN_PTR+1
+@sk4:
+
+ dec CURS_X
+ bpl lpx
+
+ dec CURS_Y
+ bpl lpy
+
+ pla
+ sta $01 ; enable I/O
+ cli
+
+ pla ; CURS_Y
+ tax
+ pla ; CURS_X
+ tay
+ clc
+ jsr soft80_kplot
+
+ lda tmp2 ; get old value
+ rts
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80_init
+conio_init = soft80_init
--- /dev/null
+;
+; Groepaz/Hitmen, 11.10.2015
+;
+; Low level init code for soft80 screen output/console input
+;
+
+ .constructor soft80_init, 8
+ .destructor soft80_shutdown
+
+ .import soft80_kclrscr, soft80_charset
+ .export soft80_internal_bgcolor, soft80_internal_cellcolor
+ .export soft80_internal_cursorxlsb
+
+ .importzp ptr1, ptr2, ptr3
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_init:
+ lda soft80_first_init
+ bne @skp
+ jsr firstinit
+@skp:
+ ; the "color voodoo" in other parts of the code relies on the vram and
+ ; colorram being set up as expected, which is why we cant use the
+ ; _bgcolor and _textcolor functions here.
+
+ lda CHARCOLOR ; use current textcolor
+ and #$0F ; make sure the upper nibble is 0s
+ sta CHARCOLOR
+
+ lda VIC_BG_COLOR0 ; use current bgcolor
+ and #$0F
+ sta soft80_internal_bgcolor
+ asl a
+ asl a
+ asl a
+ asl a
+ ora CHARCOLOR
+ sta soft80_internal_cellcolor
+
+ lda #$3B
+ sta VIC_CTRL1
+ lda #$00
+ sta CIA2_PRA
+ lda #$68
+ sta VIC_VIDEO_ADR
+ lda #$C8
+ sta VIC_CTRL2
+
+ jmp soft80_kclrscr
+
+soft80_shutdown:
+
+ lda #$07
+ sta CIA2_PRA
+ jmp $FF5B ; Initialize video I/O
+
+ .segment "INIT"
+firstinit:
+ ; copy charset to RAM under I/O
+ sei
+ lda $01
+ pha
+ lda #$34
+ sta $01
+
+ inc soft80_first_init
+
+ lda #<soft80_charset
+ ldx #>soft80_charset
+ sta ptr1
+ stx ptr1+1
+ lda #<soft80_lo_charset
+ ldx #>soft80_lo_charset
+ sta ptr2
+ stx ptr2+1
+ lda #<soft80_hi_charset
+ ldx #>soft80_hi_charset
+ sta ptr3
+ stx ptr3+1
+
+ ldx #4
+@l2:
+ ldy #0
+@l1:
+ lda (ptr1),y
+ sta (ptr2),y
+ asl a
+ asl a
+ asl a
+ asl a
+ sta (ptr3),y
+ iny
+ bne @l1
+ inc ptr1+1
+ inc ptr2+1
+ inc ptr3+1
+ dex
+ bne @l2
+
+ ; copy the kplot tables to ram under I/O
+ ;ldx #0 ; is 0
+@l3:
+ lda soft80_tables_data_start,x
+ sta soft80_bitmapxlo,x
+ lda soft80_tables_data_start + (soft80_tables_data_end - soft80_tables_data_start - $0100),x
+ sta soft80_bitmapxlo + (soft80_tables_data_end - soft80_tables_data_start - $0100),x
+ inx
+ bne @l3
+
+ pla
+ sta $01
+ cli
+ rts
+
+; the following tables take up 267 bytes, used by kplot
+soft80_tables_data_start:
+
+soft80_bitmapxlo_data:
+ .repeat 80,col
+ .byte <((col/2)*8)
+ .endrepeat
+soft80_bitmapxhi_data:
+ .repeat 80,col
+ .byte >((col/2)*8)
+ .endrepeat
+soft80_vramlo_data:
+ .repeat 25,row
+ .byte <(soft80_vram+(row*40))
+ .endrepeat
+ .byte 0,0,0,0,0,0,0 ; padding to next page
+soft80_vramhi_data:
+ .repeat 25,row
+ .byte >(soft80_vram+(row*40))
+ .endrepeat
+soft80_bitmapylo_data:
+ .repeat 25,row
+ .byte <(soft80_bitmap+(row*40*8))
+ .endrepeat
+soft80_bitmapyhi_data:
+ .repeat 25,row
+ .byte >(soft80_bitmap+(row*40*8))
+ .endrepeat
+
+soft80_tables_data_end:
+
+;-------------------------------------------------------------------------------
+ .segment "INITBSS"
+soft80_internal_cellcolor:
+ .res 1
+soft80_internal_bgcolor:
+ .res 1
+soft80_internal_cursorxlsb:
+ .res 1
+
+ .data
+soft80_first_init:
+ .byte 0 ; flag to check first init, this really must be in .data
--- /dev/null
+;
+; Groepaz/Hitmen, 11.10.2015
+;
+; high level implementation for the soft80 implementation
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export soft80_cputcxy, soft80_cputc
+ .export soft80_cputdirect, soft80_putchar
+ .export soft80_newline, soft80_plot
+ .export soft80_checkchar
+
+ .import popa, _gotoxy
+
+ .import soft80_kplot
+ .import soft80_internal_bgcolor, soft80_internal_cellcolor
+ .import soft80_internal_cursorxlsb
+
+ .importzp tmp4,tmp3
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+soft80_cputc:
+ cmp #$0A ; CR?
+ bne L1
+
+ lda #0
+ sta CURS_X
+
+ ; Set cursor position, calculate RAM pointers
+soft80_plot:
+ ldx CURS_Y
+ ldy CURS_X
+ clc
+ jmp soft80_kplot ; Set the new cursor
+
+L1: cmp #$0D ; LF?
+ beq soft80_newline ; Recalculate pointers
+
+ ; shortcut for codes < $80 ... codes $20-$7f can be printed directly,
+ ; codes $00-$1f are control codes which are not printable and thus may
+ ; give undefined result.
+ tay
+ bpl @L10
+
+ ; codes $80-$ff must get converted like this:
+ ; $80-$9f -> dont care (control codes)
+ ; $a0-$bf -> $00-$1f
+ ; $c0-$df -> $60-$7f
+ ; $e0-$ff -> $00-$1f
+
+ ora #%01000000 ; $40
+ clc
+ adc #%00100000 ; $20
+ and #%01111111 ; $7f
+@L10:
+
+ ; entry point for direct output of a character. the value passed in
+ ; akku must match the offset in the charset.
+ ; - the following may not modify tmp1
+soft80_cputdirect:
+ jsr soft80_putchar ; Write the character to the screen
+
+ ; Advance cursor position
+ iny ; contains CURS_X
+ cpy #charsperline
+ beq @L3
+
+ sty CURS_X
+ tya
+ and #$01
+ sta soft80_internal_cursorxlsb
+ bne @L5
+
+ lda SCREEN_PTR
+ clc
+ adc #8
+ sta SCREEN_PTR
+ bcc @L4
+ inc SCREEN_PTR+1
+@L4:
+ inc CRAM_PTR
+ bne @L5
+ inc CRAM_PTR+1
+@L5:
+ rts
+@L3:
+ inc CURS_Y ; new line
+ ldy #0 ; + cr
+ sty CURS_X
+ jmp soft80_plot
+
+ ; - the following may not modify tmp1
+soft80_newline:
+
+ lda SCREEN_PTR
+ clc
+ adc #<(40*8)
+ sta SCREEN_PTR
+
+ lda SCREEN_PTR+1
+ adc #>(40*8)
+ sta SCREEN_PTR+1
+
+ lda CRAM_PTR
+ clc
+ adc #40
+ sta CRAM_PTR
+ bcc @L5
+ inc CRAM_PTR+1
+@L5:
+ inc CURS_Y
+ rts
+
+;-------------------------------------------------------------------------------
+; All following code belongs to the character output to bitmap
+;
+; this stuff is going to be used a lot so we unroll it a bit for speed
+;-------------------------------------------------------------------------------
+
+.if SOFT80FASTSPACE = 1
+
+; output inverted space (odd)
+draw_spaceinvers_odd:
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$f0
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+; output inverted space (general entry point)
+; in: y must be $00
+draw_spaceinvers:
+
+.if SOFT80COLORVOODOO = 1
+ jsr soft80_putcolor
+.else
+ lda soft80_internal_cellcolor
+ sta (CRAM_PTR),y ; vram
+.endif
+
+ lda soft80_internal_cursorxlsb
+ bne draw_spaceinvers_odd
+
+; output inverted space (even)
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$0f
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+; output space (odd)
+draw_space_odd:
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ ora #$0f
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+; output space (general entry point)
+; in: y must be $00
+draw_space:
+
+ lda RVS
+ bne draw_spaceinvers
+
+.if SOFT80COLORVOODOO = 1
+ jsr remcolor
+.endif
+ ;ldy #$00 ; is still $00
+
+ lda soft80_internal_cursorxlsb
+ bne draw_space_odd
+
+; output space (even)
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ ora #$f0
+ sta (SCREEN_PTR),y
+ .if (line < 7)
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+.endif
+
+;-------------------------------------------------------------------------------
+; output one character in internal encoding without advancing cursor position
+; generic entry point
+;
+; - the following may not modify tmp1
+; in: A: charcode
+; out: Y: CURS_X
+;
+soft80_putchar:
+ sta tmp3 ; remember charcode
+
+ sei
+ ldx $01
+ stx tmp4
+ ldx #$34
+
+ stx $01 ; will stay $34 for space
+ ldy #$00 ; will be $00 from now on
+
+.if SOFT80FASTSPACE = 1
+ cmp #' ' ; space is a special (optimized) case
+ beq draw_space
+.endif
+
+.if SOFT80COLORVOODOO = 1
+ jsr soft80_putcolor
+.else
+ lda soft80_internal_cellcolor
+ sta (CRAM_PTR),y ; vram
+.endif
+
+; output character
+ ldx tmp3 ; get charcode
+
+ lda RVS
+ beq @skp
+ jmp draw_charinvers
+@skp:
+ lda soft80_internal_cursorxlsb
+ bne draw_char_even
+
+; output character (odd)
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$0f
+ ora soft80_hi_charset+(line*$80),x
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+; output character (even)
+draw_char_even:
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$f0
+ ora soft80_lo_charset+(line*$80),x
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+
+draw_back:
+ lda tmp4
+ sta $01
+ cli
+
+ ldy CURS_X
+ rts
+
+; output inverted character (odd)
+draw_charinvers_odd:
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ ora #$0f
+ eor soft80_lo_charset+(line*$80),x
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+; output inverted character (generic)
+draw_charinvers:
+ lda soft80_internal_cursorxlsb
+ bne draw_charinvers_odd
+
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ ora #$f0
+ eor soft80_hi_charset+(line*$80),x
+ sta (SCREEN_PTR),y
+ .if line < 7
+ iny
+ .endif
+ .endrepeat
+ jmp draw_back
+
+;-------------------------------------------------------------------------------
+; optional "color voodoo". the problem is that each 8x8 cell can only contain
+; two colors, one of which is used for the background color, so two characters
+; have to share the same text color.
+;
+; - in a cell that contains two spaces, both the color ram and the text color
+; in vram contain the background color
+;
+; - in a cell that contains one character, its text color goes into vram. the
+; color ram contains the background color.
+;
+; - in a cell that contains two characters, the color of the left character goes
+; to vram (and is shared by both for display). the "would be" color of the
+; right character goes to color ram as a reminder and can be restored when one
+; of the two characters is cleared by a space.
+
+.if SOFT80COLORVOODOO = 1
+
+; remove color from cell, called before putting a "space" character to the bitmap
+;
+; __ -> __ -
+; _A -> _A -
+; B_ -> B_ -
+; _A -> __ vram = bgcol
+; B_ -> __ vram = bgcol
+; BA -> _A vram = colram, colram = bgcol
+; BA -> B_ colram = bgcol
+;
+; in: x must be $34
+; y must be $00
+; out: x = $34
+; y = $00
+remcolor:
+
+ ;ldy #$00 ; is still $00
+
+ ; if the textcolor in vram is equal to the background color, then
+ ; no (visible) character is in the current cell and we can exit
+ ; immediately.
+ lda (CRAM_PTR),y ; vram (textcolor)
+ and #$0f
+ cmp soft80_internal_bgcolor
+ beq @sk1 ; yes, vram==bgcolor
+
+ ; now check if the textcolor in color ram is equal the background color,
+ ; if yes then there is only one (visible) character in the current cell
+ inc $01 ; $35
+ lda (CRAM_PTR),y ; colram (2nd textcolor)
+ stx $01 ; $34
+ and #$0f
+ cmp soft80_internal_bgcolor
+ beq @sk2 ; yes, colram==bgcolor
+ sta tmp3 ; A contains colram
+
+ ; two characters in the current cell, of which one will get removed
+
+ lda soft80_internal_cursorxlsb
+ bne @sk3
+
+ ; vram = colram
+ lda (CRAM_PTR),y ; vram
+ and #$f0
+ ora tmp3 ; colram value
+ sta (CRAM_PTR),y ; vram
+@sk3:
+ ; colram = bgcolor
+ lda soft80_internal_bgcolor
+ inc $01 ; $35
+ sta (CRAM_PTR),y ; colram
+ stx $01 ; $34
+
+ rts
+
+@sk2:
+ ; colram is bgcolor
+ ; => only one char in cell used
+
+ jsr soft80_checkchar
+ bcs @sk1 ; space at current position
+
+ ; vram (textcolor) = bgcolor
+ lda (CRAM_PTR),y ; vram
+ and #$f0
+ ora soft80_internal_bgcolor
+ sta (CRAM_PTR),y ; vram
+@sk1:
+ rts
+
+; put color to cell
+;
+; __ -> _A vram = textcol
+; __ -> B_ vram = textcol
+; _A -> BA colram = vram, vram = textcol
+; B_ -> BA colram = textcol
+;
+; _A -> _C vram = textcol
+; B_ -> C_ vram = textcol
+; BA -> BC colram = textcol
+; BA -> CA vram = textcol
+;
+; in: $01 is $34 (RAM under I/O) when entering
+; x must be $34
+; y must be $00
+; out: x = $34
+; y = $00
+soft80_putcolor:
+
+ ;ldy #$00 ; is still $00
+
+ lda (CRAM_PTR),y ; vram
+ and #$0f
+ cmp soft80_internal_bgcolor
+ beq @sk1 ; vram==bgcolor => first char in cell
+
+ ; vram!=bgcolor => second char in cell
+
+ inc $01 ; $35
+ lda (CRAM_PTR),y ; colram
+ stx $01 ; $34
+ and #$0f
+ cmp soft80_internal_bgcolor
+ beq @l2s ; colram==bgcolor -> second char in cell
+
+ ; botch characters in the cell are used
+
+ lda soft80_internal_cursorxlsb
+ bne @sk2 ; jump if odd xpos
+
+ ; vram = textcol
+ lda soft80_internal_cellcolor
+ sta (CRAM_PTR),y ; vram
+ rts
+
+@l2s:
+ ; one character in cell is already used
+ jsr soft80_checkchar
+ bcc @sk1 ; char at current position => overwrite 1st
+
+ lda soft80_internal_cursorxlsb
+ beq @sk3 ; jump if even xpos
+@sk2:
+ ; colram = textcol
+ lda CHARCOLOR
+ inc $01 ; $35
+ sta (CRAM_PTR),y ; colram
+ stx $01 ; $34
+ rts
+
+@sk3:
+ ; colram=vram
+ lda (CRAM_PTR),y ; vram
+ inc $01 ; $35
+ sta (CRAM_PTR),y ; colram
+ stx $01 ; $34
+@sk1:
+ ; vram = textcol
+ lda soft80_internal_cellcolor
+ sta (CRAM_PTR),y ; vram
+ rts
+
+;
+; test if there is a space or a character at current position
+;
+; in: x = $34
+; $01 must be $34
+;
+; out: SEC: space
+; CLC: character
+; x = $34
+; y = $00
+soft80_checkchar:
+
+ lda soft80_internal_cursorxlsb
+ bne @l1a
+
+ ; check charset data from bottom up, since a lot of eg lowercase chars
+ ; have no data in the top rows, but all of them DO have data in the
+ ; second to bottom row, this will likely be faster in average.
+
+ ldy #7
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$f0
+ cmp #$f0
+ bne @ischar
+ .if (line < 7)
+ dey
+ .endif
+ .endrepeat
+ ;ldy #$00 ; is 0
+ ;sec ; is set
+ rts
+@ischar:
+ ldy #$00
+ ;clc ; is cleared
+ rts
+@l1a:
+ ldy #$07
+ .repeat 8,line
+ lda (SCREEN_PTR),y
+ and #$0f
+ cmp #$0f
+ bne @ischar
+ .if line < 7
+ dey
+ .endif
+ .endrepeat
+ ;ldy #$00 ; is 0
+ ;sec ; is set
+ rts
+.endif
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; lowlevel kclrscr for soft80 implementation
+;
+
+ .export soft80_kclrscr
+ .import soft80_kplot
+ .import soft80_internal_bgcolor, soft80_internal_cellcolor
+ .importzp ptr1
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_kclrscr:
+
+ lda #<soft80_bitmap
+ sta ptr1
+ lda #>soft80_bitmap
+ sta ptr1+1
+
+ lda #$ff
+
+ ldx #$1f
+@lp2:
+ ldy #0
+@lp1:
+ sta (ptr1),y
+ iny
+ bne @lp1
+ inc ptr1+1
+ dex
+ bne @lp2
+
+ ;ldx #$00
+@lp3:
+ sta soft80_bitmap+$1e40,x
+ inx
+ bne @lp3
+
+.if SOFT80COLORVOODOO = 1
+ lda soft80_internal_bgcolor
+ jsr clear ; clear color ram
+.endif
+
+ sei
+ ldy $01
+ lda #$34 ; enable RAM under I/O
+ sta $01
+
+ lda soft80_internal_cellcolor
+ and #$f0
+ ora soft80_internal_bgcolor
+ jsr clear ; clear vram
+
+ sty $01
+ cli
+
+ ldx #0
+ ldy #0
+ clc
+ jmp soft80_kplot
+
+ ; clear loop for colram and vram
+clear:
+ ;ldx #$00
+@lp1:
+ sta soft80_colram,x
+ sta soft80_colram+$100,x
+ sta soft80_colram+$200,x
+ sta soft80_colram+$2e8,x
+ inx
+ bne @lp1
+ rts
+
+
--- /dev/null
+
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; lowlevel kplot function for the soft80 implementation
+;
+
+ .export soft80_kplot
+ .import soft80_internal_cursorxlsb
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80_kplot:
+ bcs @getpos
+
+ stx CURS_Y
+ sty CURS_X
+
+ sei
+ lda $01
+ pha
+ lda #$34 ; enable RAM under I/O
+ sta $01
+
+ ; calc pointer to bitmap
+ lda soft80_bitmapylo,x
+ clc
+ adc soft80_bitmapxlo,y
+ sta SCREEN_PTR
+ lda soft80_bitmapyhi,x
+ adc soft80_bitmapxhi,y
+ sta SCREEN_PTR+1
+
+ tya
+ and #1
+ sta soft80_internal_cursorxlsb
+
+ ; calc pointer to vram
+ tya
+ lsr a
+
+ clc
+ adc soft80_vramlo,x
+ sta CRAM_PTR
+ lda #0
+ adc soft80_vramhi,x
+ sta CRAM_PTR+1
+
+ pla
+ sta $01
+ cli
+
+@getpos:
+ ldx CURS_Y
+ ldy CURS_X
+ rts
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80_init
+conio_init = soft80_init
--- /dev/null
+;
+; Groepaz/Hitmen, 12.10.2015
+;
+; lowlevel screensize function for the soft80 implementation
+;
+
+ .export soft80_screensize
+
+ .include "soft80.inc"
+
+soft80_screensize:
+ ldy #screenrows
+ ldx #charsperline
+ rts
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; high level implementation for the monochrome soft80 implementation
+;
+; char cgetc (void);
+;
+
+ .export soft80mono_cgetc
+ .import soft80mono_internal_cellcolor, soft80mono_internal_cursorxlsb
+ .import soft80mono_internal_nibble
+ .import cursor
+ .importzp tmp1
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_cgetc:
+ lda KEY_COUNT ; Get number of characters
+ bne @L3 ; Jump if there are already chars waiting
+
+ jsr invertcursor ; set cursor on or off accordingly
+
+@L1: lda KEY_COUNT ; wait for key
+ beq @L1
+
+ jsr invertcursor ; set cursor on or off accordingly
+
+@L3: jsr KBDREAD ; Read char and return in A
+ ldx #0
+ rts
+
+; Switch the cursor on or off (invert)
+
+invertcursor:
+ lda cursor
+ bne @invert
+ rts
+@invert:
+
+ sei
+ lda $01 ; enable RAM under I/O
+ pha
+ lda #$34
+ sta $01
+
+ ldy #$00
+ ldx soft80mono_internal_cursorxlsb
+@lp1:
+ lda (SCREEN_PTR),y
+ eor soft80mono_internal_nibble,x
+ sta (SCREEN_PTR),y
+ iny
+ cpy #8
+ bne @lp1
+
+ pla
+ sta $01 ; enable I/O
+ cli
+ rts
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80mono_init
+conio_init = soft80mono_init
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; high level implementation for the monochrome soft80 implementation
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+;
+
+ .export soft80mono_textcolor, soft80mono_bgcolor
+ .import soft80mono_internal_cellcolor, soft80mono_internal_bgcolor
+
+ .importzp tmp1
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_textcolor:
+ ldx CHARCOLOR ; get old value
+ stx tmp1 ; save old value
+ sta CHARCOLOR ; set new value
+
+mkcharcolor:
+ lda soft80mono_internal_bgcolor
+ asl a
+ asl a
+ asl a
+ asl a
+ ora CHARCOLOR
+ sta soft80mono_internal_cellcolor ; text/bg combo for new chars
+
+ sei
+ ldy $01
+ lda #$34 ; enable RAM under I/O
+ sta $01
+
+ lda soft80mono_internal_cellcolor
+ ; clear loop for vram
+ ldx #$00
+@lp1:
+ sta soft80_vram,x
+ sta soft80_vram+$100,x
+ sta soft80_vram+$200,x
+ sta soft80_vram+$2e8,x
+ inx
+ bne @lp1
+
+ sty $01
+ cli
+
+ lda tmp1 ; get old value
+ rts
+
+soft80mono_bgcolor:
+ ldx soft80mono_internal_bgcolor ; get old value
+ stx tmp1 ; save old value
+ sta soft80mono_internal_bgcolor ; set new value
+
+ jmp mkcharcolor
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80mono_init
+conio_init = soft80mono_init
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; Low level init code for the monochrome soft80 screen output/console input
+;
+
+ .constructor soft80mono_init, 8
+ .destructor soft80mono_shutdown
+
+ .import soft80mono_kclrscr, soft80_charset
+ .export soft80mono_internal_bgcolor, soft80mono_internal_cellcolor
+ .export soft80mono_internal_cursorxlsb
+ .export soft80mono_internal_nibble
+
+ .importzp ptr1, ptr2, ptr3
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_init:
+ lda soft80mono_first_init
+ bne @skp
+ jsr firstinit
+@skp:
+ ; the "color voodoo" in other parts of the code relies on the vram and
+ ; colorram being set up as expected, which is why we cant use the
+ ; _bgcolor and _textcolor functions here.
+
+ lda CHARCOLOR ; use current textcolor
+ and #$0f ; make sure the upper nibble is 0s
+ sta CHARCOLOR
+
+ lda VIC_BG_COLOR0 ; use current bgcolor
+ and #$0f
+ sta soft80mono_internal_bgcolor
+ asl a
+ asl a
+ asl a
+ asl a
+ ora CHARCOLOR
+ sta soft80mono_internal_cellcolor
+
+ lda #$3b
+ sta VIC_CTRL1
+ lda #$00
+ sta CIA2_PRA
+ lda #$68
+ sta VIC_VIDEO_ADR
+ lda #$c8
+ sta VIC_CTRL2
+
+ jmp soft80mono_kclrscr
+
+soft80mono_shutdown:
+ lda #$1b
+ sta VIC_CTRL1
+ lda #$03
+ sta CIA2_PRA
+ lda #$15
+ sta VIC_VIDEO_ADR
+ rts
+
+ .segment "INIT"
+firstinit:
+ ; copy charset to RAM under I/O
+ sei
+ lda $01
+ pha
+ lda #$34
+ sta $01
+
+ inc soft80mono_first_init
+
+ lda #>soft80_charset
+ sta ptr1+1
+ lda #<soft80_charset
+ sta ptr1
+ lda #>soft80_lo_charset
+ sta ptr2+1
+ lda #<soft80_lo_charset
+ sta ptr2
+ lda #>soft80_hi_charset
+ sta ptr3+1
+ lda #<soft80_hi_charset
+ sta ptr3
+
+ ldx #4
+@l2:
+ ldy #0
+@l1:
+ lda (ptr1),y
+ sta (ptr2),y
+ asl a
+ asl a
+ asl a
+ asl a
+ sta (ptr3),y
+ iny
+ bne @l1
+ inc ptr1+1
+ inc ptr2+1
+ inc ptr3+1
+ dex
+ bne @l2
+
+ ; copy the kplot tables to ram under I/O
+ ;ldx #0 ; is 0
+@l3:
+ lda soft80_tables_data_start,x
+ sta soft80_bitmapxlo,x
+ lda soft80_tables_data_start + (soft80_tables_data_end - soft80_tables_data_start - $100) ,x
+ sta soft80_bitmapxlo + (soft80_tables_data_end - soft80_tables_data_start - $100),x
+ inx
+ bne @l3
+
+ pla
+ sta $01
+ cli
+ rts
+
+; the following tables take up 267 bytes, used by kplot
+soft80_tables_data_start:
+
+soft80_bitmapxlo_data:
+ .repeat 80,col
+ .byte <((col/2)*8)
+ .endrepeat
+soft80_bitmapxhi_data:
+ .repeat 80,col
+ .byte >((col/2)*8)
+ .endrepeat
+soft80_vramlo_data:
+ .repeat 25,row
+ .byte <(soft80_vram+(row*40))
+ .endrepeat
+ .byte 0,0,0,0,0,0,0 ; padding to next page
+soft80_vramhi_data:
+ .repeat 25,row
+ .byte >(soft80_vram+(row*40))
+ .endrepeat
+soft80_bitmapylo_data:
+ .repeat 25,row
+ .byte <(soft80_bitmap+(row*40*8))
+ .endrepeat
+soft80_bitmapyhi_data:
+ .repeat 25,row
+ .byte >(soft80_bitmap+(row*40*8))
+ .endrepeat
+
+soft80_tables_data_end:
+
+;-------------------------------------------------------------------------------
+ .segment "INITBSS"
+soft80mono_internal_cellcolor:
+ .res 1
+soft80mono_internal_bgcolor:
+ .res 1
+soft80mono_internal_cursorxlsb:
+ .res 1
+
+ .data
+soft80mono_first_init:
+ .byte 0 ; flag to check first init, this really must be in .data
+
+ .rodata
+soft80mono_internal_nibble:
+ .byte $f0, $0f
+
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; high level implementation for the monochrome soft80 implementation
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export soft80mono_cputcxy, soft80mono_cputc
+ .export soft80mono_cputdirect, soft80mono_putchar
+ .export soft80mono_newline, soft80mono_plot
+
+ .import popa, _gotoxy
+
+ .import soft80mono_kplot
+ .import soft80mono_internal_bgcolor, soft80mono_internal_cellcolor
+ .import soft80mono_internal_cursorxlsb, soft80mono_internal_nibble
+
+ .importzp tmp4, tmp3, ptr2
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+soft80mono_cputc:
+ cmp #$0A ; CR?
+ bne L1
+
+ lda #0
+ sta CURS_X
+
+ ; Set cursor position, calculate RAM pointers
+soft80mono_plot:
+ ldx CURS_Y
+ ldy CURS_X
+ clc
+ jmp soft80mono_kplot ; Set the new cursor
+
+L1: cmp #$0D ; LF?
+ beq soft80mono_newline ; Recalculate pointers
+
+ ; shortcut for codes < $80 ... codes $20-$7f can be printed directly,
+ ; codes $00-$1f are control codes which are not printable and thus may
+ ; give undefined result.
+ tay
+ bpl @L10
+
+ ; codes $80-$ff must get converted like this:
+ ; $80-$9f -> dont care (control codes)
+ ; $a0-$bf -> $00-$1f
+ ; $c0-$df -> $60-$7f
+ ; $e0-$ff -> $00-$1f
+
+ ora #%01000000 ; $40
+ clc
+ adc #%00100000 ; $20
+ and #%01111111 ; $7f
+@L10:
+
+ ; entry point for direct output of a character. the value passed in
+ ; akku must match the offset in the charset.
+ ; - the following may not modify tmp1
+soft80mono_cputdirect:
+ jsr soft80mono_putchar ; Write the character to the screen
+
+ ; Advance cursor position
+ iny ; contains CURS_X
+ cpy #charsperline
+ beq @L3
+
+ sty CURS_X
+ tya
+ and #$01
+ sta soft80mono_internal_cursorxlsb
+ bne @L4
+
+ lda SCREEN_PTR
+ clc
+ adc #8
+ sta SCREEN_PTR
+ bcc @L4
+ inc SCREEN_PTR+1
+@L4:
+ rts
+@L3:
+ inc CURS_Y ; new line
+ ldy #0 ; + cr
+ sty CURS_X
+ jmp soft80mono_plot
+
+ ; - the following may not modify tmp1
+soft80mono_newline:
+
+ lda SCREEN_PTR
+ clc
+ adc #<(40*8)
+ sta SCREEN_PTR
+
+ lda SCREEN_PTR+1
+ adc #>(40*8)
+ sta SCREEN_PTR+1
+
+ inc CURS_Y
+ rts
+
+;-------------------------------------------------------------------------------
+; output one character in internal encoding without advancing cursor position
+; generic entry point
+;
+; - the following may not modify tmp1
+; in: A: charcode
+; out: Y: CURS_X
+;
+soft80mono_putchar:
+ sta tmp3 ; save charcode
+
+ sei
+ lda $01
+ pha
+ lda #$34
+ sta $01 ; enable RAM under I/O
+
+ ldy #$00 ; will be $00 from now on
+
+ ldx soft80mono_internal_cursorxlsb
+ lda chardatal,x
+ clc
+ adc tmp3
+ sta ptr2
+ lda chardatah,x
+ adc #0
+ sta ptr2+1
+
+ lda RVS
+ bne draw_charinvers
+
+ lda nibble,x
+ sta tmp3
+
+ ;ldy #0 ; is still $00
+@lp1:
+ lda (SCREEN_PTR),y
+ and tmp3
+ ora (ptr2),y
+ sta (SCREEN_PTR),y
+ clc
+ lda ptr2
+ adc #$7f
+ sta ptr2
+ bcc @sk1
+ inc ptr2+1
+@sk1:
+ iny
+ cpy #8
+ bne @lp1
+
+draw_back:
+ pla
+ sta $01
+ cli
+
+ ldy CURS_X
+ rts
+
+; output inverted character
+draw_charinvers:
+ lda soft80mono_internal_nibble,x
+ sta tmp3
+
+ ;ldy #0 ; is still $00
+@lp1:
+ lda (SCREEN_PTR),y
+ ora tmp3
+ eor (ptr2),y
+ sta (SCREEN_PTR),y
+ clc
+ lda ptr2
+ adc #$7f
+ sta ptr2
+ bcc @sk1
+ inc ptr2+1
+@sk1:
+ iny
+ cpy #8
+ bne @lp1
+ jmp draw_back
+
+ .rodata
+chardatal:
+ .byte <soft80_hi_charset
+ .byte <soft80_lo_charset
+chardatah:
+ .byte >soft80_hi_charset
+ .byte >soft80_lo_charset
+nibble:
+ .byte $0f, $f0
+
--- /dev/null
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; lowlevel kclrscr for the monochrome soft80 implementation
+;
+
+ .export soft80mono_kclrscr
+ .import soft80mono_kplot
+ .import soft80mono_internal_bgcolor, soft80mono_internal_cellcolor
+ .importzp ptr1
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_kclrscr:
+
+ lda #<soft80_bitmap
+ sta ptr1
+ lda #>soft80_bitmap
+ sta ptr1+1
+
+ lda #$ff
+
+ ldx #$1f
+@lp2:
+ ldy #0
+@lp1:
+ sta (ptr1),y
+ iny
+ bne @lp1
+ inc ptr1+1
+ dex
+ bne @lp2
+
+ ;ldx #$00
+@lp3:
+ sta soft80_bitmap+$1e40,x
+ inx
+ bne @lp3
+
+ sei
+ ldy $01
+ lda #$34 ; enable RAM under I/O
+ sta $01
+
+ lda soft80mono_internal_cellcolor
+ ; clear loop for vram
+ ;ldx #$00
+@lp4:
+ sta soft80_vram,x
+ sta soft80_vram+$100,x
+ sta soft80_vram+$200,x
+ sta soft80_vram+$2e8,x
+ inx
+ bne @lp4
+
+ sty $01
+ cli
+
+ ldx #0
+ ldy #0
+ clc
+ jmp soft80mono_kplot
--- /dev/null
+
+;
+; Groepaz/Hitmen, 19.10.2015
+;
+; lowlevel kplot function for the monochrome soft80 implementation
+;
+
+ .export soft80mono_kplot
+ .import soft80mono_internal_cursorxlsb
+
+ .include "c64.inc"
+ .include "soft80.inc"
+
+soft80mono_kplot:
+ bcs @getpos
+
+ stx CURS_Y
+ sty CURS_X
+
+ sei
+ lda $01
+ pha
+ lda #$34 ; enable RAM under I/O
+ sta $01
+
+ ; calc pointer to bitmap
+ lda soft80_bitmapylo,x
+ clc
+ adc soft80_bitmapxlo,y
+ sta SCREEN_PTR
+ lda soft80_bitmapyhi,x
+ adc soft80_bitmapxhi,y
+ sta SCREEN_PTR+1
+
+ tya
+ and #1
+ sta soft80mono_internal_cursorxlsb
+
+ pla
+ sta $01
+ cli
+
+@getpos:
+ ldx CURS_Y
+ ldy CURS_X
+ rts
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import soft80mono_init
+conio_init = soft80mono_init
; Constructor that writes to the 1/10 sec register of the TOD to kick it
; into action. If this is not done, the clock hangs. We will read the register
; and write it again, ignoring a possible change in between.
+.segment "INIT"
.proc initsystime
.endproc
-
;----------------------------------------------------------------------------
; TM struct with date set to 1970-01-01
.data
.word 0 ; tm_wday
.word 0 ; tm_yday
.word 0 ; tm_isdst
-
/*
** Marc 'BlackJack' Rintsch, 06.03.2001
**
-** unsigned int cbm_load(const char* name,
-** unsigned char device,
-** const unsigned char* data);
+** unsigned int __fastcall__ cbm_load(const char* name,
+** unsigned char device,
+** const unsigned char* data);
*/
#include <cbm.h>
/* loads file "name" from given device to given address or to the load address
** of the file if "data" is 0
*/
-unsigned int cbm_load(const char* name, unsigned char device, void* data)
+unsigned int __fastcall__ cbm_load(const char* name, unsigned char device, void* data)
{
/* LFN is set to 0; but, it's not needed for loading
** (BASIC V2 sets it to the value of the SA for LOAD).
.export _chlinexy, _chline
.import popa, _gotoxy, cputdirect
- .importzp tmp1
+ .importzp tmp1, chlinechar
_chlinexy:
pha ; Save the length
cmp #0 ; Is the length zero?
beq L9 ; Jump if done
sta tmp1
-L1: lda #64 ; Horizontal line, screen code
+L1: lda #chlinechar ; Horizontal line, screen code
jsr cputdirect ; Direct output
dec tmp1
bne L1
--- /dev/null
+;
+; Chars used by chline () and cvline ()
+;
+
+ .exportzp chlinechar = 64
+ .exportzp cvlinechar = 93
.export _cvlinexy, _cvline
.import popa, _gotoxy, putchar, newline
- .importzp tmp1
+ .importzp tmp1, cvlinechar
_cvlinexy:
pha ; Save the length
cmp #0 ; Is the length zero?
beq L9 ; Jump if done
sta tmp1
-L1: lda #93 ; Vertical bar
+L1: lda #cvlinechar ; Vertical bar
jsr putchar ; Write, no cursor advance
jsr newline ; Advance cursor to next line
dec tmp1
/*
** Program-chaining function for Commodore platforms.
**
-** 2013-09-04, Greg King
+** 2015-09-27, Greg King
**
** This function exploits the program-chaining feature in CBM BASIC's ROM.
**
/* The struct below is a line of BASIC code. It sits in the LOWCODE segment
** to make sure that it won't be hidden by a ROM when BASIC is re-enabled.
** The line is:
-** 0 LOAD""+"" ,01
+** 0 CLR:LOAD""+"" ,01
** After this function has written into the line, it might look like this:
-** 0 LOAD""+"program name" ,08
+** 0 CLR:LOAD""+"program name" ,08
**
** When BASIC's LOAD command asks the Kernal to load a file, it gives the
** Kernal a pointer to a file-name string. CC65's CBM programs use that
** pointer to give a copy of the program's name to main()'s argv[0] parameter.
-** But, when BASIC uses a string literal that's in a program, it points
+** But, when BASIC uses a string literal that is in a program, it points
** directly to that literal -- in the models that don't use banked RAM
** (Pet/CBM, VIC-20, and 64). The literal is overwritten by the next program
-** that's loaded. So, argv[0] would point to machine code. String operations
+** that is loaded. So, argv[0] would point to machine code. String operations
** create a new result string -- even when that operation changes nothing. The
** result is put in the string space at the top of BASIC's memory. So, the ""+
** in this BASIC line guarantees that argv[0] will get a name from a safe place.
*/
#pragma data-name(push, "LOWCODE")
static struct line {
- const char end_of_line;
- const struct line *const next;
+ const char end_of_line; /* fake previous line */
+ const struct line* const next;
const unsigned line_num;
- const char load_token, quotes[2], add_token, quote;
+ const char CLR_token, colon, LOAD_token, quotes[2], add_token, quote;
char name[21];
const char comma;
char unit[3];
} basic = {
- '\0', &basic + 1, /* high byte of link must be non-zero */
- 0, 0x93, "\"\"", 0xaa, '\"',
- "\" ", /* format: "123:1234567890123456\"" */
+ '\0', &basic + 1, /* high byte of link must be non-zero */
+ 0, 0x9C, ':', 0x93, "\"\"", 0xAA, '\"',
+ "\" ", /* format: "123:1234567890123456\"" */
',', "01"
};
#pragma data-name(pop)
/* These values are platform-specific. */
-extern const struct line *txtptr;
+extern const void* vartab; /* points to BASIC program variables */
+#pragma zpsym("vartab")
+extern const void* memsize; /* points to top of BASIC RAM */
+#pragma zpsym("memsize")
+extern const struct line* txtptr; /* points to BASIC code */
#pragma zpsym("txtptr")
-extern char basbuf[]; /* BASIC's input buffer */
+extern char basbuf[]; /* BASIC's input buffer */
extern void basbuf_len[];
#pragma zpsym("basbuf_len")
int __fastcall__ exec (const char* progname, const char* cmdline)
{
static int fd;
- static unsigned char dv, n = 0;
+ static unsigned char dv, n;
/* Exclude devices that can't load files. */
+ /* (Use hand optimization, to make smaller code.) */
dv = getcurrentdevice ();
- if (dv < 8 && dv != 1 || dv > 30) {
+ if (dv < 8 && __AX__ != 1 || __AX__ > 30) {
return _mappederrno (9); /* illegal device number */
}
utoa (dv, basic.unit, 10);
- /* Don't try to run a program that can't be found. */
- fd = open (progname, O_RDONLY);
- if (fd < 0) {
- return fd;
+ /* Tape files can be openned only once; skip this test for the Datasette. */
+ if (dv != 1) {
+ /* Don't try to run a program that can't be found. */
+ fd = open (progname, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+ close (fd);
}
- close (fd);
+ n = 0;
do {
if ((basic.name[n] = progname[n]) == '\0') {
break;
}
- } while (++n < 20); /* truncate long names */
+ } while (++n < 20); /* truncate long names */
basic.name[n] = '\"';
+/* This next part isn't needed by machines that put
+** BASIC source and variables in different RAM banks.
+*/
+#if !defined(__CBM510__) && !defined(__CBM610__) && !defined(__C128__)
+ /* cc65 program loads might extend beyond the end of the RAM that is allowed
+ ** for BASIC. Then, the LOAD statement would complain that it is "out of
+ ** memory". Some pointers that say where to put BASIC program variables
+ ** must be changed, so that we do not get that error. One pointer is
+ ** changed here; a BASIC CLR statement changes the others.
+ */
+ vartab = (char*)memsize - 256;
+#endif
+
/* Build the next program's argument list. */
- basbuf[0] = 0x8f; /* REM token */
+ basbuf[0] = 0x8F; /* REM token */
basbuf[1] = '\0';
if (cmdline != NULL) {
strncat (basbuf, cmdline, (size_t)basbuf_len - 2);
}
+ /* Tell the ROM where to find that BASIC program. */
#if defined(__CBM510__) || defined(__CBM610__)
pokewsys ((unsigned)&txtptr, (unsigned)&basic);
#else
txtptr = &basic;
#endif
- /* (The return code, in ST, will be destroyed by LOAD.
+ /* (The return code, in ST [status], will be destroyed by LOAD.
** So, don't bother to set it here.)
*/
exit (__AX__);
.include "vic20.inc"
.endif
- .export _txtptr:zp, _basbuf, _basbuf_len:zp
+; exec() is written in C.
+; Provide the spellings that the C compiler wants to use.
-_txtptr := TXTPTR
+.ifdef VARTAB
+.exportzp _vartab := VARTAB
+.exportzp _memsize := MEMSIZE
+.endif
+
+.exportzp _txtptr := TXTPTR
-_basbuf := BASIC_BUF
-_basbuf_len = BASIC_BUF_LEN
+.export _basbuf := BASIC_BUF
+.exportzp _basbuf_len = BASIC_BUF_LEN
;
+ .include "cbm.inc"
.include "filedes.inc"
.code
;--------------------------------------------------------------------------
; Data
-.bss
-fdtab: .res MAX_FDS
-unittab:.res MAX_FDS
-
+.data
+fdtab: .byte LFN_READ
+ .byte LFN_WRITE
+ .byte LFN_WRITE
+ .res MAX_FDS-3
+unittab:.byte CBMDEV_KBD
+ .byte CBMDEV_SCREEN
+ .byte CBMDEV_SCREEN
+ .res MAX_FDS-3
.importzp devnum
-.bss
+.segment "INITBSS"
curunit:
.res 1
--- /dev/null
+; VIC sprite color for the mouse pointer
+
+ .export _mouse_def_pointercolor
+
+
+.segment "INIT"
+
+_mouse_def_pointercolor:
+
+ .byte $01 ; White
--- /dev/null
+; VIC sprite data for the mouse pointer (an arrow)
+
+ .export _mouse_def_pointershape
+
+
+.segment "INIT"
+
+_mouse_def_pointershape:
+
+ .byte %11111110, %00000000, %00000000
+ .byte %11111100, %00000000, %00000000
+ .byte %11111000, %00000000, %00000000
+ .byte %11111100, %00000000, %00000000
+ .byte %11011110, %00000000, %00000000
+ .byte %10001111, %00000000, %00000000
+ .byte %00000111, %10000000, %00000000
+ .byte %00000011, %11000000, %00000000
+ .byte %00000001, %11100000, %00000000
+ .byte %00000000, %11110000, %00000000
+ .byte %00000000, %01111000, %00000000
+ .byte %00000000, %00111000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
+ .byte %00000000, %00000000, %00000000
.proc initstdin
- lda #LFN_READ
- sta fdtab+STDIN_FILENO
lda #STDIN_FILENO + LFN_OFFS
ldx #CBMDEV_KBD
- stx unittab+STDIN_FILENO
ldy #$FF
jsr SETLFS
jmp OPEN ; Will always succeed
.bss
unit: .res 1
-
-
.proc initstdout
- lda #LFN_WRITE
- sta fdtab+STDOUT_FILENO
- sta fdtab+STDERR_FILENO
- lda #CBMDEV_SCREEN
- sta unittab+STDOUT_FILENO
- sta unittab+STDERR_FILENO
lda #STDOUT_FILENO + LFN_OFFS
jsr @L1
lda #STDERR_FILENO + LFN_OFFS
jmp __directerrno ; Sets _errno, clears _oserror, returns -1
.endproc
-
-
-
-
.macpack generic
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run.
ldy #FNAM_LEN
lda (sysp0),y
tay
+ lda #0 ; The terminating NUL character
stx IndReg ; Look for name in correct bank
cpy #NAME_LEN + 1
blt L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (ptr1),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
jsr restore_bank
inc __argc ; argc always is equal to at least 1
; Find a "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- bze done ; no "rem," no args.
+ bze done ; No "rem," no args.
inx
cmp #REM
bne L2
ldy #1 * 2
; Find the next argument.
-;
+
next: lda BASIC_BUF,x
bze done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. That is useful because we
; will check now for a quoted argument; in which case, we will have to skip that
; first character.
-;
+
found: cmp #'"' ; Is the argument quoted?
beq setterm ; Jump if so
dex ; Reset pointer to first argument character
setterm:sta term ; Set end-of-argument marker
; Now, store a pointer to the argument into the next slot.
-;
+
txa ; Get low byte
add #<BASIC_BUF
sta argv,y ; argv[y]= &arg
inc __argc ; Found another arg
; Search for the end of the argument.
-;
+
argloop:lda BASIC_BUF,x
bze done
inx
; We've found the end of the argument. X points one character behind it, and
; A contains the terminating character. To make the argument a valid C string,
; replace the terminating character by a zero.
-;
+
lda #$00
sta BASIC_BUF-1,x
blt next ; Parse next one if not
; (The last vector in argv[] already is NULL.)
-;
+
done: lda #<argv
ldx #>argv
sta __argv
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
- .res MAXARGS * 2, $00
+ .res MAXARGS * 2
; be called from an interrupt handler.
;
+ .constructor initmcb
.export _mouse_def_callbacks
+ .import _mouse_def_pointershape
+ .import _mouse_def_pointercolor
.import vic:zp
.include "mouse-kernel.inc"
; Sprite definitions. The first value can be changed to adjust the number
; of the sprite used for the mouse. All others depend on that value.
MOUSE_SPR = 0 ; Sprite used for the mouse
+MOUSE_SPR_MEM = $F400 ; Memory location
MOUSE_SPR_MASK = $01 .shl MOUSE_SPR ; Positive mask
MOUSE_SPR_NMASK = .lobyte(.not MOUSE_SPR_MASK) ; Negative mask
VIC_SPR_X = (VIC_SPR0_X + 2*MOUSE_SPR) ; Sprite X register
VIC_SPR_Y = (VIC_SPR0_Y + 2*MOUSE_SPR) ; Sprite Y register
+; --------------------------------------------------------------------------
+; Initialize the mouse sprite.
+
+.segment "INIT"
+
+initmcb:
+
+; Copy the mouse sprite data
+
+ ldx #64 - 1
+@L0: lda _mouse_def_pointershape,x
+ sta MOUSE_SPR_MEM,x
+ dex
+ bpl @L0
+
+; Set the mouse sprite pointer
+
+ lda #<(MOUSE_SPR_MEM / 64)
+ sta $F3F8 + MOUSE_SPR
+
+; Set the mouse sprite color
+
+ ldx IndReg
+ lda #15
+ sta IndReg
+
+ lda _mouse_def_pointercolor
+ ldy #VIC_SPR0_COLOR + MOUSE_SPR
+ sta (vic),y
+
+ stx IndReg
+ rts
+
; --------------------------------------------------------------------------
; Hide the mouse pointer. Always called with interrupts disabled.
+.code
+
hide:
ldy #15
sty IndReg
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
.importzp time
__randomize:
- ldx time ; Use 50/60HZ clock
+ ldx time+2 ; Use 50/60HZ clock
lda time+1
jmp _srand ; Initialize generator
.macpack generic
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run.
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
jsr sys_bank
ldy #FNAM
lda (sysp0),y ; Get file-name pointer from system bank
ldy #FNAM_LEN
lda (sysp0),y
tay
+ lda #0 ; The terminating NUL character
stx IndReg ; Look for name in correct bank
cpy #NAME_LEN + 1
blt L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (ptr1),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
jsr restore_bank
inc __argc ; argc always is equal to at least 1
; Find a "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- bze done ; no "rem," no args.
+ bze done ; No "rem," no args.
inx
cmp #REM
bne L2
ldy #1 * 2
; Find the next argument.
-;
+
next: lda BASIC_BUF,x
bze done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. That is useful because we
; will check now for a quoted argument; in which case, we will have to skip that
; first character.
-;
+
found: cmp #'"' ; Is the argument quoted?
beq setterm ; Jump if so
dex ; Reset pointer to first argument character
setterm:sta term ; Set end-of-argument marker
; Now, store a pointer to the argument into the next slot.
-;
+
txa ; Get low byte
add #<BASIC_BUF
sta argv,y ; argv[y]= &arg
inc __argc ; Found another arg
; Search for the end of the argument.
-;
+
argloop:lda BASIC_BUF,x
bze done
inx
; We've found the end of the argument. X points one character behind it, and
; A contains the terminating character. To make the argument a valid C string,
; replace the terminating character by a zero.
-;
+
lda #$00
sta BASIC_BUF-1,x
; Check if the maximum number of command-line arguments is reached. If not,
; parse the next one.
-;
+
lda __argc ; Get low byte of argument count
cmp #MAXARGS ; Maximum number of arguments reached?
blt next ; Parse next one if not
; (The last vector in argv[] already is NULL.)
-;
+
done: lda #<argv
ldx #>argv
sta __argv
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
- .res MAXARGS * 2, $00
+ .res MAXARGS * 2
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
.importzp time
__randomize:
- ldx time ; Use 50/60HZ clock
+ ldx time+2 ; Use 50/60HZ clock
lda time+1
jmp _srand ; Initialize generator
/*
** _afailed.c
**
-** Ullrich von Bassewitz, 06.06.1998
+** 1998-06-06, Ullrich von Bassewitz
+** 2015-03-13, Greg King
*/
-void _afailed (char* file, unsigned line)
+void __fastcall__ _afailed (char* file, unsigned line)
{
fprintf (stderr, "ASSERTION FAILED IN %s(%u)\n", file, line);
exit (2);
.import initcwd
.include "stdio.inc"
-
+
__cwd_buf_size = FILENAME_MAX
cwd_init := initcwd
-.bss
+.segment "INITBSS"
__cwd: .res __cwd_buf_size
; checking the other sources.
.assert __cwd_buf_size < 256, error, "__cwd_buf_size must not be > 255"
-
--- /dev/null
+;
+; 2003-08-12, Ullrich von Bassewitz
+; 2015-09-24, Greg King
+;
+; Helper function for several high-level file functions.
+;
+
+ .include "errno.inc"
+
+ .macpack cpu
+
+; ----------------------------------------------------------------------------
+; int __fastcall__ _directerrno (unsigned char code);
+; /* Set errno to a specific error code, clear _oserror, and return -1. Used
+; ** by the library.
+; */
+
+__directerrno:
+ jsr __seterrno ; Set errno (returns with .A = 0)
+ sta __oserror ; Clear __oserror
+.if (.cpu .bitand CPU_ISET_65SC02)
+ dec a
+.else
+ lda #$FF ; Return -1
+.endif
+ tax
+ rts
--- /dev/null
+;
+; 2003-08-12, Ullrich von Bassewitz
+; 2015-09-24, Greg King
+;
+; Helper function for several high-level file functions.
+;
+
+ .include "errno.inc"
+
+ .macpack generic
+ .macpack cpu
+
+; ----------------------------------------------------------------------------
+; int __fastcall__ _mappederrno (unsigned char code);
+; /* Set _oserror to the given platform-specific error code. If it is a real
+; ** error code (not zero), set errno to the corresponding system error code,
+; ** and return -1. Otherwise, return zero.
+; ** Used by the library.
+; */
+
+__mappederrno:
+ sta __oserror ; Store the error code
+ tax ; Did we have an error?
+ bze ok ; Branch if no
+ jsr __osmaperrno ; Map OS error into errno code
+ jsr __seterrno ; Save in errno (returns with .A = 0)
+.if (.cpu .bitand CPU_ISET_65SC02)
+ dec a
+.else
+ lda #$FF ; Return -1 if error
+.endif
+ tax
+ok: rts
struct outdesc;
/* Type of the function that is called to output data */
-typedef void (*outfunc) (struct outdesc* desc, const char* buf, unsigned count);
+typedef void __cdecl__ (* outfunc) (struct outdesc* desc, const char* buf, unsigned count);
/*
** bsearch.c
**
-** Ullrich von Bassewitz, 17.06.1998
+** 1998-06-17, Ullrich von Bassewitz
+** 2015-06-21, Greg King
*/
void* __fastcall__ bsearch (const void* key, const void* base, size_t n,
- size_t size, int (*cmp) (const void*, const void*))
+ size_t size, int __fastcall__ (* cmp) (const void*, const void*))
{
int current;
int result;
;
-; Ullrich von Bassewitz, 2003-08-12
+; 2003-08-12, Ullrich von Bassewitz
+; 2015-09-24, Greg King
;
-; Helper functions for several high level file functions.
+; extern int _errno;
+; /* Library errors go here. */
;
-
.include "errno.inc"
-.code
-
-; ----------------------------------------------------------------------------
-; int __fastcall__ _directerrno (unsigned char code);
-; /* Set errno to a specific error code, clear _oserror and return -1. Used
-; ** by the library.
-; */
-
-__directerrno:
- jsr __seterrno ; Set errno, returns with A = 0
- sta __oserror ; Clear __oserror
- beq fail ; Branch always
-
-; ----------------------------------------------------------------------------
-; int __fastcall__ _mappederrno (unsigned char code);
-; /* Set _oserror to the given platform specific error code. If it is a real
-; ** error code (not zero) set errno to the corresponding system error code
-; ** and return -1. Otherwise return zero.
-; ** Used by the library.
-; */
-
-__mappederrno:
- sta __oserror ; Store the error code
- tax ; Did we have an error?
- beq ok ; Branch if no
- jsr __osmaperrno ; Map os error into errno code
- jsr __seterrno ; Save in errno
-fail: lda #$FF ; Return -1
- tax
-ok: rts
-
-
-; ----------------------------------------------------------------------------
.bss
__errno:
.word 0
-
;
-; Oliver Schmidt, 2012-01-18
+; 2012-01-18, Oliver Schmidt
+; 2015-08-22, Greg King
;
; void __fastcall__ set_irq (irq_handler f, void *stack_addr, size_t stack_size);
; void reset_irq (void);
.export _set_irq, _reset_irq
.interruptor clevel_irq, 1 ; Export as low priority IRQ handler
- .import popax
- .importzp __ZP_START__
+ .import popax, __ZP_START__
.include "zeropage.inc"
; ---------------------------------------------------------------------------
+.code
+
.proc _set_irq
; Keep clevel_irq from being called right now
; Save our zero page locations
@L1: ldx #.sizeof(::zpsave)-1
-@L2: lda __ZP_START__,x
+@L2: lda <__ZP_START__,x
sta zpsave,x
dex
bpl @L2
; Copy back our zero page content
ldx #.sizeof(::zpsave)-1
@L3: ldy zpsave,x
- sty __ZP_START__,x
+ sty <__ZP_START__,x
dex
bpl @L3
rts
.endproc
-
;
-; Ullrich von Bassewitz, 06.06.1998
+; 1998-06-06, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
-; void longjmp (jmp_buf buf, int retval);
+; void __fastcall__ longjmp (jmp_buf buf, int retval);
;
.export _longjmp
stx ptr2+1
ora ptr2+1 ; Check for 0
bne @L1
- lda #1 ; 0 is illegal according to the standard...
- sta ptr2 ; ... and must be replaced by 1
+ inc ptr2 ; 0 is illegal, according to the standard ...
+ ; ... and, must be replaced by 1
@L1: jsr popax ; get buf
sta ptr1
stx ptr1+1
lda ptr2
ldx ptr2+1
rts
-
;
-; Ullrich von Bassewitz, 2003-08-20
-; Performance increase (about 20%) by
-; Christian Krueger, 2009-09-13
+; 2003-08-20, Ullrich von Bassewitz
+; 2009-09-13, Christian Krueger -- performance increase (about 20%)
+; 2015-10-23, Greg King
;
; void* __fastcall__ memmove (void* dest, const void* src, size_t size);
;
; low addresses and increase pointers), otherwise we must copy downwards
; (start at high addresses and decrease pointers).
- sec
- sbc ptr1
+ cmp ptr1
txa
sbc ptr1+1
jcc memcpy_upwards ; Branch if dest < src (upwards copy)
; Done, return dest
done: jmp popax ; Pop ptr and return as result
-
--- /dev/null
+;
+; 2015-10-07, Greg King
+;
+
+ .export moveinit
+
+ .import __INIT_LOAD__, __INIT_RUN__, __INIT_SIZE__ ; Linker-generated
+
+ .macpack cpu
+ .macpack generic
+
+
+; Put this in the DATA segment because it is self-modifying code.
+
+.data
+
+; Move the INIT segment from where it was loaded (over the bss segments)
+; into where it must be run (over the BSS segment). The two areas might overlap;
+; and, the segment is moved upwards. Therefore, this code starts at the highest
+; address, and decrements to the lowest address. The low bytes of the starting
+; pointers are not sums. The high bytes are sums; but, they do not include the
+; carry. Both the low-byte sums and the carries will be done when the pointers
+; are indexed by the .Y register.
+
+moveinit:
+
+; First, move the last, partial page.
+; Then, move all of the full pages.
+
+ ldy #<__INIT_SIZE__ ; size of partial page
+ ldx #>__INIT_SIZE__ + (<__INIT_SIZE__ <> 0) ; number of pages, including partial
+
+L1: dey
+init_load:
+ lda __INIT_LOAD__ + (__INIT_SIZE__ & $FF00) - $0100 * (<__INIT_SIZE__ = 0),y
+init_run:
+ sta __INIT_RUN__ + (__INIT_SIZE__ & $FF00) - $0100 * (<__INIT_SIZE__ = 0),y
+ tya
+ bnz L1 ; page not finished
+
+ dec init_load+2
+ dec init_run+2
+ dex
+ bnz L1 ; move next page
+ rts
/*
** qsort.c
**
-** Ullrich von Bassewitz, 09.12.1998
+** 1998.12.09, Ullrich von Bassewitz
+** 2015-06-21, Greg King
*/
static void QuickSort (register unsigned char* Base, int Lo, int Hi,
register size_t Size,
- int (*Compare)(const void*, const void*))
+ int __fastcall__ (* Compare) (const void*, const void*))
/* Internal recursive function. Works with ints, but this shouldn't be
** a problem.
*/
void __fastcall__ qsort (void* base, size_t nmemb, size_t size,
- int (*compare)(const void*, const void*))
+ int __fastcall__ (* compare) (const void*, const void*))
/* Quicksort implementation */
{
if (nmemb > 1) {
;
-; Ullrich von Bassewitz, 06.06.1998
+; 1998-06-06, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
-; int setjmp (jmp_buf buf);
+; int __fastcall__ setjmp (jmp_buf buf);
;
.export __setjmp
+
+ .import return0
.importzp sp, ptr1
__setjmp:
; Return zero
- lda #0
- tax
- rts
-
-
-
+ jmp return0
; can ignore the passed pointer d, and access the data directly. While this
; is not very clean, it gives better and shorter code.
;
-; static void out (struct outdesc* d, const char* buf, unsigned count)
+; static void cdecl out (struct outdesc* d, const char* buf, unsigned count)
; /* Routine used for writing */
; {
; register size_t cnt;
ldy #7
jsr pushwysp ; Push count
lda ptr
- ldx ptr+1
+ ldx ptr+1
jsr _fwrite
sta ptr1 ; Save function result
stx ptr1+1
;
-; int vsnprintf (char* Buf, size_t size, const char* Format, va_list ap);
+; int __fastcall__ vsnprintf (char* Buf, size_t size, const char* Format, va_list ap);
;
-; Ullrich von Bassewitz, 2009-09-26
+; 2009-09-26, Ullrich von Bassewitz
+; 2015-07-17, Greg King
;
.export _vsnprintf, vsnprintf
.import _memcpy, __printf
.importzp sp, ptr1
+ .include "errno.inc"
+
.macpack generic
.data
sta ccount+1 ; Clear ccount
; Get the size parameter and replace it by a pointer to outdesc. This is to
-; build a stack frame for the call to _printf.
-; If size is zero, there's nothing to do.
+; build a stack frame for the call to _printf. The size must not be greater
+; than INT_MAX because the return type is int. If the size is zero,
+; then nothing will be written into the buffer; but, the arguments still will
+; be formatted and counted.
ldy #2
lda (sp),y
iny
lda (sp),y
+ bmi L9 ; More than $7FFF
sta ptr1+1
- ora ptr1
- beq L9
-
lda #>outdesc
sta (sp),y
-; Write size-1 to outdesc.uns
+; Write size-1 to outdesc.uns. It will be -1 if there is no buffer.
ldy ptr1+1
ldx ptr1
sta bufptr+0
stx bufptr+1
+; There must be a buffer if its size is non-zero.
+
+ bit bufsize+1
+ bmi L5
+ ora bufptr+1
+ bze L0 ; The pointer shouldn't be NULL
+
; Restore ap and call _printf
- pla
+L5: pla
tax
pla
jsr __printf
-; Terminate the string. The last char is either at bufptr+ccount or
-; bufptr+bufsize, whichever is smaller.
+; Terminate the string if there is a buffer. The last char. is at either
+; bufptr+bufsize or bufptr+ccount, whichever is smaller.
- lda ccount+0
- ldx ccount+1
- cpx bufsize+1
+ ldx bufsize+1
+ bmi L4 ; -1 -- No buffer
+ lda bufsize+0
+ cpx ccount+1
bne L2
- cmp bufsize+0
+ cmp ccount+0
L2: bcc L3
- lda bufsize+0
- ldx bufsize+1
+ lda ccount+0
+ ldx ccount+1
clc
L3: adc bufptr+0
sta ptr1
; Return the number of bytes written and drop buf
- lda ccount+0
+L4: lda ccount+0
ldx ccount+1
jmp incsp2
-; Bail out if size is zero.
+; Bail out if size is too high.
-L9: pla
- pla ; Discard ap
- lda #0
- tax
+L9: ldy #ERANGE
+ .byte $2C ;(bit $xxxx)
+
+; NULL buffer pointers usually are invalid.
+
+L0: ldy #EINVAL
+ pla ; Drop ap
+ pla
+ tya
+ jsr __directerrno ; Return -1
jmp incsp6 ; Drop parameters
; ----------------------------------------------------------------------------
; Callback routine used for the actual output.
;
-; static void out (struct outdesc* d, const char* buf, unsigned count)
+; static void __cdecl__ out (struct outdesc* d, const char* buf, unsigned count)
; /* Routine used for writing */
;
; Since we know, we're called with a pointer to our static outdesc structure,
sbc ccount+0 ; Low byte of bytes already written
sta ptr1
lda bufsize+1
+ bmi @L9 ; -1 -- No buffer
sbc ccount+1
sta ptr1+1
bcs @L0 ; Branch if space left
- lda #$00
+@L9: lda #$0000
sta ptr1
sta ptr1+1 ; No space left
.importzp ptr1
-.segment "INIT"
+.code
zerobss:
lda #<__BSS_RUN__
; Done
L4: rts
-
-
-
;
-; int vcprintf (const char* Format, va_list ap);
+; int __fastcall__ vcprintf (const char* Format, va_list ap);
;
; Ullrich von Bassewitz, 2.12.2000
;
; ----------------------------------------------------------------------------
; Callback routine used for the actual output.
;
-; static void out (struct outdesc* d, const char* buf, unsigned count)
+; static void __cdecl__ out (struct outdesc* d, const char* buf, unsigned count)
; /* Routine used for writing */
; {
; /* Fast screen output */
; ----------------------------------------------------------------------------
; vcprintf - formatted console i/o
;
-; int vcprintf (const char* format, va_list ap)
+; int __fastcall__ vcprintf (const char* format, va_list ap)
; {
; struct outdesc d;
;
; /* Return bytes written */
; return d.ccount;
; }
-;
-; It is intentional that this function does not have __fastcall__ calling
-; conventions - we need the space on the stack anyway, so there's nothing
-; gained by using __fastcall__.
_vcprintf:
sta ptr1 ; Save ap
lda outdesc ; ccount
ldx outdesc+1
rts
-
-
-
; ----------------------------------------------------------------------------
-; static int unget(int c) {
+; static int cdecl unget(int c) {
; pushed = true;
; return back = c;
; }
pla
jmp __scanf
.endproc
-
;
; Ullrich von Bassewitz, 11.08.1998
;
-; char* DbgMemDump (unsigend Addr, char* Buf, unsigned char Length);
+; char* __cdecl__ DbgMemDump (unsigend Addr, char* Buf, unsigned char Length);
;
.export _DbgMemDump
copy: lda (ptr1),y
iny
-set: sta joy_vectors,x
+ sta joy_vectors,x
inx
rts
--- /dev/null
+;
+; IRQ handling (NES version)
+;
+
+ .export initirq, doneirq
+
+; ------------------------------------------------------------------------
+
+.segment "INIT"
+
+initirq:
+ rts
+
+; ------------------------------------------------------------------------
+
+.code
+
+doneirq:
+ rts
tay ; Joystick number (0,1) into Y
lda #1
- sta APU_PAD1,y
+ sta APU_PAD1
lda #0
- sta APU_PAD1,y
+ sta APU_PAD1
; Read joystick
--- /dev/null
+;
+; 2015-03-08, Greg King
+;
+
+; When you want to create a program with the alternate file format,
+; add "-u __BOOT__" to the cl65/ld65 command line. Then, the linker
+; will import this symbol name; and, link this module at the front
+; of your program file.
+;
+ .export __BOOT__:abs = 1
+
+ .import __RAM_START__, __RAM_SIZE__, __BSS_RUN__
+
+; ------------------------------------------------------------------------
+
+load_addr := __RAM_START__
+load_size = __BSS_RUN__ - __RAM_START__
+ram_top := __RAM_START__ + __RAM_SIZE__
+
+ .segment "BOOT"
+
+; If you want to change how this bootstrap loader works, then:
+; 1. edit this assembly source code,
+; 2. define the constant ASM (uncomment the line below),
+; 3. assemble this file (and, make a listing of that assembly),
+; 4. copy the listing's hex codes into the .byte lines below (notice that most
+; of the strings are followed by CR; it's required by the OS65V monitor)
+; (be sure to match the listing's lines against the .byte lines),
+; 5. undefine ASM (recomment the line),
+; 6. assemble this file, again,
+; 7. and, add the object file to "osic1p.lib".
+
+;ASM = 1
+
+.ifdef ASM
+
+ .include "osic1p.inc"
+ .macpack generic
+
+load := $08 ; private variables
+count := $0A
+
+GETCHAR := $FFBF ; gets one character from ACIA
+
+FIRSTVISC = $85 ; Offset of first visible character in video RAM
+LINEDIST = $20 ; Offset in video RAM between two lines
+
+ ldy #<$0000
+ lda #<load_addr
+ ldx #>load_addr
+ sta load
+ stx load+1
+ lda #<load_size
+ eor #$FF
+ sta count ; store (-size - 1)
+ lda #>load_size
+ eor #$FF
+ sta count+1
+
+L1: inc count ; pre-count one's-complement upwards
+ bnz L2
+ inc count+1
+ bze L3
+L2: jsr GETCHAR ; (doesn't change .Y)
+ sta (load),y
+
+; Show that the file is being loaded by rotating an arrow on the screen.
+;
+ tya
+ lsr a
+ lsr a
+ and #8 - 1
+ ora #$10 ; eight arrow characters
+ sta SCRNBASE + FIRSTVISC + 2 * LINEDIST + 11
+
+ iny
+ bnz L1
+ inc load+1
+ bnz L1 ; branch always
+
+L3: jmp load_addr
+
+.else
+
+.mac hex1 h
+ .lobytes ((h) & $0F) + (((h) & $0F) > 9) * 7 + '0'
+.endmac
+
+.mac hex2 h
+ hex1 (h) >> 4
+ hex1 (h) >> 0
+.endmac
+
+.mac hex4 h
+ hex2 >(h)
+ hex2 <(h)
+.endmac
+
+CR = $0D
+
+ .byte CR, CR
+ .byte "." ; set an address
+ hex4 ram_top ; put loader where stack will sit
+ .byte "/" ; write bytes into RAM
+
+; ASCII-coded hexadecimal translation of the above assembly code.
+; It was copied from the assembler listing.
+
+ .byte "A0", CR, "00", CR
+ .byte "A9", CR
+ hex2 <load_addr
+ .byte CR, "A2", CR
+ hex2 >load_addr
+ .byte CR, "85", CR, "08", CR
+ .byte "86", CR, "09", CR
+ .byte "A9", CR
+ hex2 <load_size
+ .byte CR, "49", CR, "FF", CR
+ .byte "85", CR, "0A", CR
+ .byte "A9", CR
+ hex2 >load_size
+ .byte CR, "49", CR, "FF", CR
+ .byte "85", CR, "0B", CR
+
+ .byte "E6", CR, "0A", CR
+ .byte "D0", CR, "04", CR
+ .byte "E6", CR, "0B", CR
+ .byte "F0", CR, "16", CR
+ .byte "20", CR, "BF", CR, "FF", CR
+ .byte "91", CR, "08", CR
+
+ .byte "98", CR
+ .byte "4A", CR
+ .byte "4A", CR
+ .byte "29", CR, "07", CR
+ .byte "09", CR, "10", CR
+ .byte "8D", CR, "D0", CR, "D0", CR
+
+ .byte "C8", CR
+ .byte "D0", CR, "E6", CR
+ .byte "E6", CR, "09", CR
+ .byte "D0", CR, "E2", CR
+
+ .byte "4C", CR
+ hex2 <load_addr
+ .byte CR
+ hex2 >load_addr
+
+ .byte CR, "."
+ hex4 ram_top
+ .byte "G" ; go to address
+
+.endif
--- /dev/null
+;
+; Copied from CBM implementation
+;
+; originally by:
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+ .export _cclearxy, _cclear
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_cclearxy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cclear
+
+_cclear:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #' '
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
--- /dev/null
+;\r
+; char cgetc (void);\r
+;\r
+\r
+ .constructor initcgetc\r
+ .export _cgetc\r
+ .import cursor\r
+\r
+ .include "osic1p.inc"\r
+ .include "extzp.inc"\r
+ .include "zeropage.inc"\r
+\r
+; Initialize one-character buffer that is filled by kbhit()\r
+ .segment "INIT"\r
+initcgetc:\r
+ lda #$00\r
+ sta CHARBUF ; No character in buffer initially\r
+ rts\r
+\r
+; Input routine from 65V PROM MONITOR, show cursor if enabled\r
+ .code\r
+_cgetc:\r
+ lda CHARBUF ; character in buffer available?\r
+ beq nobuffer\r
+ tax ; save character in X\r
+ lda #$00\r
+ sta CHARBUF ; empty buffer\r
+ beq restorex ; restore X and return\r
+nobuffer:\r
+ lda cursor ; show cursor?\r
+ beq nocursor\r
+ ldy CURS_X\r
+ lda (SCREEN_PTR),y ; fetch current character\r
+ sta tmp1 ; save it\r
+ lda #$A1 ; full white square\r
+ sta (SCREEN_PTR),y ; store at cursor position\r
+nocursor:\r
+ jsr INPUTC ; get input character in A\r
+ ldx cursor\r
+ beq done ; was cursor on?\r
+ tax ; save A in X\r
+ lda tmp1 ; fetch saved character\r
+ ldy CURS_X\r
+ sta (SCREEN_PTR),y ; store at cursor position\r
+\r
+restorex:\r
+ txa ; restore saved character from X\r
+done:\r
+ ldx #$00 ; high byte of int return value\r
+ rts\r
--- /dev/null
+;
+; based on CBM implementation
+;
+; originally by:
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+ .export _chlinexy, _chline
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_chlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length
+
+_chline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$94 ; Horizontal line, screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
--- /dev/null
+; ---------------------------------------------------------------------------
+; crt0.s
+; ---------------------------------------------------------------------------
+;
+; Startup code for Ohio Scientific Challenger 1P
+
+.export _init, _exit
+.import _main
+
+.export __STARTUP__ : absolute = 1 ; Mark as startup
+.import __RAM_START__, __RAM_SIZE__ ; Linker generated
+.import __STACKSIZE__
+
+.import zerobss, initlib, donelib
+
+.include "zeropage.inc"
+.include "extzp.inc"
+.include "osic1p.inc"
+
+; ---------------------------------------------------------------------------
+; Place the startup code in a special segment
+
+.segment "STARTUP"
+
+; ---------------------------------------------------------------------------
+; A little light 6502 housekeeping
+
+_init: ldx #$FF ; Initialize stack pointer to $01FF
+ txs
+ cld ; Clear decimal mode
+
+; ---------------------------------------------------------------------------
+; Set cc65 argument stack pointer
+
+ lda #<(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
+ sta sp
+ lda #>(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
+ sta sp+1
+
+; ---------------------------------------------------------------------------
+; Initialize memory storage
+
+ jsr zerobss ; Clear BSS segment
+ jsr initlib ; Run constructors
+
+; ---------------------------------------------------------------------------
+; Call main()
+
+ jsr _main
+
+; ---------------------------------------------------------------------------
+; Back from main (this is also the _exit entry):
+
+_exit: jsr donelib ; Run destructors
+ jmp RESET ; Display boot menu after program exit
--- /dev/null
+;
+; Character specification table.
+;
+; Ullrich von Bassewitz, 02.06.1998
+; 2003-05-02, Greg King
+;
+; Copied from cbm/ctype.s
+
+; The following 256-byte-wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+; * It is fast. If it weren't for the slow parameter-passing of cc65,
+; one even could define C-language macroes for the isxxx functions
+; (as it usually is done, on other platforms).
+;
+; * It is highly portable. The only unportable part is the table itself;
+; all real code goes into the common library.
+;
+; * We save some code in the isxxx functions.
+
+; This table is taken from Craig S. Bruce's technical docs. for the ACE OS.
+
+ .include "ctype.inc"
+
+; The table is read-only, put it into the RODATA segment.
+
+ .rodata
+
+__ctype:
+ .byte CT_CTRL ; 0/00 ___rvs_@___
+ .byte CT_CTRL ; 1/01 ___rvs_a___
+ .byte CT_CTRL ; 2/02 ___rvs_b___
+ .byte CT_CTRL ; 3/03 ___rvs_c___
+ .byte CT_CTRL ; 4/04 ___rvs_d___
+ .byte CT_CTRL ; 5/05 ___rvs_e___
+ .byte CT_CTRL ; 6/06 ___rvs_f___
+ .byte CT_CTRL ; 7/07 _BEL/rvs_g_
+ .byte CT_CTRL ; 8/08 ___rvs_h___
+ .byte CT_CTRL | CT_OTHER_WS | CT_SPACE_TAB ; 9/09 _TAB/rvs_i_
+ .byte CT_CTRL | CT_OTHER_WS ; 10/0a _BOL/rvs_j_
+ .byte CT_CTRL ; 11/0b ___rvs_k___
+ .byte CT_CTRL ; 12/0c ___rvs_l___
+ .byte CT_CTRL | CT_OTHER_WS ; 13/0d _CR_/rvs_m_
+ .byte CT_CTRL ; 14/0e ___rvs_n___
+ .byte CT_CTRL ; 15/0f ___rvs_o___
+ .byte CT_CTRL ; 16/10 ___rvs_p___
+ .byte CT_CTRL | CT_OTHER_WS ; 17/11 _VT_/rvs_q_
+ .byte CT_CTRL ; 18/12 ___rvs_r___
+ .byte CT_CTRL | CT_OTHER_WS ; 19/13 HOME/rvs_s_
+ .byte CT_CTRL | CT_OTHER_WS ; 20/14 _BS_/rvs_t_
+ .byte CT_CTRL ; 21/15 ___rvs_u___
+ .byte CT_CTRL ; 22/16 ___rvs_v___
+ .byte CT_CTRL ; 23/17 ___rvs_w___
+ .byte CT_CTRL ; 24/18 ___rvs_x___
+ .byte CT_CTRL ; 25/19 ___rvs_y___
+ .byte CT_CTRL ; 26/1a ___rvs_z___
+ .byte CT_CTRL ; 27/1b ___rvs_[___
+ .byte CT_CTRL ; 28/1c ___rvs_\___
+ .byte CT_CTRL | CT_OTHER_WS ; 29/1d cursr-right
+ .byte CT_CTRL ; 30/1e ___rvs_^___
+ .byte CT_CTRL ; 31/1f _rvs_under_
+ .byte CT_SPACE | CT_SPACE_TAB ; 32/20 ___SPACE___
+ .byte $00 ; 33/21 _____!_____
+ .byte $00 ; 34/22 _____"_____
+ .byte $00 ; 35/23 _____#_____
+ .byte $00 ; 36/24 _____$_____
+ .byte $00 ; 37/25 _____%_____
+ .byte $00 ; 38/26 _____&_____
+ .byte $00 ; 39/27 _____'_____
+ .byte $00 ; 40/28 _____(_____
+ .byte $00 ; 41/29 _____)_____
+ .byte $00 ; 42/2a _____*_____
+ .byte $00 ; 43/2b _____+_____
+ .byte $00 ; 44/2c _____,_____
+ .byte $00 ; 45/2d _____-_____
+ .byte $00 ; 46/2e _____._____
+ .byte $00 ; 47/2f _____/_____
+ .byte CT_DIGIT | CT_XDIGIT ; 48/30 _____0_____
+ .byte CT_DIGIT | CT_XDIGIT ; 49/31 _____1_____
+ .byte CT_DIGIT | CT_XDIGIT ; 50/32 _____2_____
+ .byte CT_DIGIT | CT_XDIGIT ; 51/33 _____3_____
+ .byte CT_DIGIT | CT_XDIGIT ; 52/34 _____4_____
+ .byte CT_DIGIT | CT_XDIGIT ; 53/35 _____5_____
+ .byte CT_DIGIT | CT_XDIGIT ; 54/36 _____6_____
+ .byte CT_DIGIT | CT_XDIGIT ; 55/37 _____7_____
+ .byte CT_DIGIT | CT_XDIGIT ; 56/38 _____8_____
+ .byte CT_DIGIT | CT_XDIGIT ; 57/39 _____9_____
+ .byte $00 ; 58/3a _____:_____
+ .byte $00 ; 59/3b _____;_____
+ .byte $00 ; 60/3c _____<_____
+ .byte $00 ; 61/3d _____=_____
+ .byte $00 ; 62/3e _____>_____
+ .byte $00 ; 63/3f _____?_____
+
+ .byte $00 ; 64/40 _____@_____
+ .byte CT_LOWER | CT_XDIGIT ; 65/41 _____a_____
+ .byte CT_LOWER | CT_XDIGIT ; 66/42 _____b_____
+ .byte CT_LOWER | CT_XDIGIT ; 67/43 _____c_____
+ .byte CT_LOWER | CT_XDIGIT ; 68/44 _____d_____
+ .byte CT_LOWER | CT_XDIGIT ; 69/45 _____e_____
+ .byte CT_LOWER | CT_XDIGIT ; 70/46 _____f_____
+ .byte CT_LOWER ; 71/47 _____g_____
+ .byte CT_LOWER ; 72/48 _____h_____
+ .byte CT_LOWER ; 73/49 _____i_____
+ .byte CT_LOWER ; 74/4a _____j_____
+ .byte CT_LOWER ; 75/4b _____k_____
+ .byte CT_LOWER ; 76/4c _____l_____
+ .byte CT_LOWER ; 77/4d _____m_____
+ .byte CT_LOWER ; 78/4e _____n_____
+ .byte CT_LOWER ; 79/4f _____o_____
+ .byte CT_LOWER ; 80/50 _____p_____
+ .byte CT_LOWER ; 81/51 _____q_____
+ .byte CT_LOWER ; 82/52 _____r_____
+ .byte CT_LOWER ; 83/53 _____s_____
+ .byte CT_LOWER ; 84/54 _____t_____
+ .byte CT_LOWER ; 85/55 _____u_____
+ .byte CT_LOWER ; 86/56 _____v_____
+ .byte CT_LOWER ; 87/57 _____w_____
+ .byte CT_LOWER ; 88/58 _____x_____
+ .byte CT_LOWER ; 89/59 _____y_____
+ .byte CT_LOWER ; 90/5a _____z_____
+ .byte $00 ; 91/5b _____[_____
+ .byte $00 ; 92/5c _____\_____
+ .byte $00 ; 93/5d _____]_____
+ .byte $00 ; 94/5e _____^_____
+ .byte $00 ; 95/5f _UNDERLINE_
+ .byte $00 ; 96/60 _A`_grave__
+ .byte $00 ; 97/61 _A'_acute__
+ .byte $00 ; 98/62 _A^_circum_
+ .byte $00 ; 99/63 _A~_tilde__
+ .byte $00 ; 100/64 _A"_dieres_
+ .byte $00 ; 101/65 _A__ring___
+ .byte $00 ; 102/66 _AE________
+ .byte $00 ; 103/67 _C,cedilla_
+ .byte $00 ; 104/68 _E`_grave__
+ .byte $00 ; 105/69 _E'_acute__
+ .byte $00 ; 106/6a _E^_circum_
+ .byte $00 ; 107/6b _E"_dieres_
+ .byte $00 ; 108/6c _I`_grave__
+ .byte $00 ; 109/6d _I'_acute__
+ .byte $00 ; 110/6e _I^_circum_
+ .byte $00 ; 111/6f _I"_dieres_
+ .byte $00 ; 112/70 _D-_Eth_lr_
+ .byte $00 ; 113/71 _N~_tilde__
+ .byte $00 ; 114/72 _O`_grave__
+ .byte $00 ; 115/73 _O'_acute__
+ .byte $00 ; 116/74 _O^_circum_
+ .byte $00 ; 117/75 _O~_tilde__
+ .byte $00 ; 118/76 _O"_dieres_
+ .byte $00 ; 119/77 __multiply_
+ .byte $00 ; 120/78 _O/_slash__
+ .byte $00 ; 121/79 _U`_grave__
+ .byte $00 ; 122/7a _U'_acute__
+ .byte $00 ; 123/7b _U^_circum_
+ .byte $00 ; 124/7c _U"_dieres_
+ .byte $00 ; 125/7d _Y'_acute__
+ .byte $00 ; 126/7e _cap_thorn_
+ .byte $00 ; 127/7f _Es-sed_B__
+
+ .byte CT_CTRL ; 128/80 __bullet___
+ .byte CT_CTRL ; 129/81 __v_line___
+ .byte CT_CTRL ; 130/82 __h_line___
+ .byte CT_CTRL ; 131/83 ___cross___
+ .byte CT_CTRL ; 132/84 _tl_corner_
+ .byte CT_CTRL ; 133/85 _tr_corner_
+ .byte CT_CTRL ; 134/86 _bl_corner_
+ .byte CT_CTRL ; 135/87 _br_corner_
+ .byte CT_CTRL ; 136/88 ___l_tee___
+ .byte CT_CTRL ; 137/89 ___r_tee___
+ .byte CT_CTRL ; 138/8a ___t_tee___
+ .byte CT_CTRL ; 139/8b ___b_tee___
+ .byte CT_CTRL ; 140/8c ___heart___
+ .byte CT_CTRL | CT_OTHER_WS ; 141/8d _CR/diamond
+ .byte CT_CTRL ; 142/8e ___club____
+ .byte CT_CTRL ; 143/8f ___spade___
+ .byte CT_CTRL ; 144/90 _s_circle__
+ .byte CT_CTRL | CT_OTHER_WS ; 145/91 _cursor-up_
+ .byte CT_CTRL ; 146/92 ___pound___
+ .byte CT_CTRL | CT_OTHER_WS ; 147/93 _CLS/check_
+ .byte CT_CTRL | CT_OTHER_WS ; 148/94 __INSert___
+ .byte CT_CTRL ; 149/95 ____+/-____
+ .byte CT_CTRL ; 150/96 __divide___
+ .byte CT_CTRL ; 151/97 __degree___
+ .byte CT_CTRL ; 152/98 _c_checker_
+ .byte CT_CTRL ; 153/99 _f_checker_
+ .byte CT_CTRL ; 154/9a _solid_sq__
+ .byte CT_CTRL ; 155/9b __cr_char__
+ .byte CT_CTRL ; 156/9c _up_arrow__
+ .byte CT_CTRL | CT_OTHER_WS ; 157/9d cursor-left
+ .byte CT_CTRL ; 158/9e _left_arro_
+ .byte CT_CTRL ; 159/9f _right_arr_
+ .byte CT_SPACE | CT_SPACE_TAB ; 160/a0 _req space_
+ .byte $00 ; 161/a1 _!_invertd_
+ .byte $00 ; 162/a2 ___cent____
+ .byte $00 ; 163/a3 ___pound___
+ .byte $00 ; 164/a4 __currency_
+ .byte $00 ; 165/a5 ____yen____
+ .byte $00 ; 166/a6 _|_broken__
+ .byte $00 ; 167/a7 __section__
+ .byte $00 ; 168/a8 __umulaut__
+ .byte $00 ; 169/a9 _copyright_
+ .byte $00 ; 170/aa __fem_ord__
+ .byte $00 ; 171/ab _l_ang_quo_
+ .byte $00 ; 172/ac ____not____
+ .byte $00 ; 173/ad _syl_hyphn_
+ .byte $00 ; 174/ae _registerd_
+ .byte $00 ; 175/af _overline__
+ .byte $00 ; 176/b0 __degrees__
+ .byte $00 ; 177/b1 ____+/-____
+ .byte $00 ; 178/b2 _2_supersc_
+ .byte $00 ; 179/b3 _3_supersc_
+ .byte $00 ; 180/b4 ___acute___
+ .byte $00 ; 181/b5 ____mu_____
+ .byte $00 ; 182/b6 _paragraph_
+ .byte $00 ; 183/b7 __mid_dot__
+ .byte $00 ; 184/b8 __cedilla__
+ .byte $00 ; 185/b9 _1_supersc_
+ .byte $00 ; 186/ba __mas_ord__
+ .byte $00 ; 187/bb _r_ang_quo_
+ .byte $00 ; 188/bc ____1/4____
+ .byte $00 ; 189/bd ____1/2____
+ .byte $00 ; 190/be ____3/4____
+ .byte $00 ; 191/bf _?_invertd_
+
+ .byte $00 ; 192/c0 _____`_____
+ .byte CT_UPPER | CT_XDIGIT ; 193/c1 _____A_____
+ .byte CT_UPPER | CT_XDIGIT ; 194/c2 _____B_____
+ .byte CT_UPPER | CT_XDIGIT ; 195/c3 _____C_____
+ .byte CT_UPPER | CT_XDIGIT ; 196/c4 _____D_____
+ .byte CT_UPPER | CT_XDIGIT ; 197/c5 _____E_____
+ .byte CT_UPPER | CT_XDIGIT ; 198/c6 _____F_____
+ .byte CT_UPPER ; 199/c7 _____G_____
+ .byte CT_UPPER ; 200/c8 _____H_____
+ .byte CT_UPPER ; 201/c9 _____I_____
+ .byte CT_UPPER ; 202/ca _____J_____
+ .byte CT_UPPER ; 203/cb _____K_____
+ .byte CT_UPPER ; 204/cc _____L_____
+ .byte CT_UPPER ; 205/cd _____M_____
+ .byte CT_UPPER ; 206/ce _____N_____
+ .byte CT_UPPER ; 207/cf _____O_____
+ .byte CT_UPPER ; 208/d0 _____P_____
+ .byte CT_UPPER ; 209/d1 _____Q_____
+ .byte CT_UPPER ; 210/d2 _____R_____
+ .byte CT_UPPER ; 211/d3 _____S_____
+ .byte CT_UPPER ; 212/d4 _____T_____
+ .byte CT_UPPER ; 213/d5 _____U_____
+ .byte CT_UPPER ; 214/d6 _____V_____
+ .byte CT_UPPER ; 215/d7 _____W_____
+ .byte CT_UPPER ; 216/d8 _____X_____
+ .byte CT_UPPER ; 217/d9 _____Y_____
+ .byte CT_UPPER ; 218/da _____Z_____
+ .byte $00 ; 219/db _____{_____
+ .byte $00 ; 220/dc _____|_____
+ .byte $00 ; 221/dd _____}_____
+ .byte $00 ; 222/de _____~_____
+ .byte $00 ; 223/df ___HOUSE___
+ .byte $00 ; 224/e0 _a`_grave__
+ .byte $00 ; 225/e1 _a'_acute__
+ .byte $00 ; 226/e2 _a^_circum_
+ .byte $00 ; 227/e3 _a~_tilde__
+ .byte $00 ; 228/e4 _a"_dieres_
+ .byte $00 ; 229/e5 _a__ring___
+ .byte $00 ; 230/e6 _ae________
+ .byte $00 ; 231/e7 _c,cedilla_
+ .byte $00 ; 232/e8 _e`_grave__
+ .byte $00 ; 233/e9 _e'_acute__
+ .byte $00 ; 234/ea _e^_circum_
+ .byte $00 ; 235/eb _e"_dieres_
+ .byte $00 ; 236/ec _i`_grave__
+ .byte $00 ; 237/ed _i'_acute__
+ .byte $00 ; 238/ee _i^_circum_
+ .byte $00 ; 239/ef _i"_dieres_
+ .byte $00 ; 240/f0 _o^x_Eth_s_
+ .byte $00 ; 241/f1 _n~_tilda__
+ .byte $00 ; 242/f2 _o`_grave__
+ .byte $00 ; 243/f3 _o'_acute__
+ .byte $00 ; 244/f4 _o^_circum_
+ .byte $00 ; 245/f5 _o~_tilde__
+ .byte $00 ; 246/f6 _o"_dieres_
+ .byte $00 ; 247/f7 __divide___
+ .byte $00 ; 248/f8 _o/_slash__
+ .byte $00 ; 249/f9 _u`_grave__
+ .byte $00 ; 250/fa _u'_acute__
+ .byte $00 ; 251/fb _u^_circum_
+ .byte $00 ; 252/fc _u"_dieres_
+ .byte $00 ; 253/fd _y'_acute__
+ .byte $00 ; 254/fe _sm_thorn__
+ .byte $00 ; 255/ff _y"_dieres_
--- /dev/null
+;
+; based on CBM version
+; originally by:
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+ .export _cvlinexy, _cvline
+ .import popa, _gotoxy, putchar, newline
+ .importzp tmp1
+
+_cvlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cvline
+
+_cvline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$95 ; Vertical bar
+ jsr putchar ; Write, no cursor advance
+ jsr newline ; Advance cursor to next line
+ dec tmp1
+ bne L1
+L9: rts
--- /dev/null
+;
+; Implementation of screen-layout related functions for Superboard ///
+;
+
+ .include "../osiscreen.inc"
+
+S3_SCR_BASE := $D000 ; Base of Superboard /// video RAM
+S3_VRAM_SIZE = $0400 ; Size of Superboard /// video RAM (1 kB)
+S3_SCR_WIDTH = $20 ; Screen width
+S3_SCR_HEIGHT = $1C ; Screen height
+S3_SCR_FIRSTCHAR = $80 ; Offset of cursor position (0, 0) from base
+ ; of video RAM
+S3_SCROLL_DIST = $20 ; Memory distance for scrolling by one line
+
+osi_screen_funcs S3_SCR_BASE, S3_VRAM_SIZE, S3_SCR_FIRSTCHAR, \
+ S3_SCR_WIDTH, S3_SCR_HEIGHT, S3_SCROLL_DIST
--- /dev/null
+;
+; Additional zero page locations for the Challenger 1P.
+;
+
+; ------------------------------------------------------------------------
+
+ .globalzp CURS_X, CURS_Y, SCREEN_PTR, CHARBUF
--- /dev/null
+;
+; Additional zero page locations for the Challenger 1P.
+; NOTE: The zeropage locations contained in this file get initialized
+; in the startup code, so if you change anything here, be sure to check
+; not only the linker config, but also the startup file.
+;
+
+; ------------------------------------------------------------------------
+
+ .include "extzp.inc"
+
+.segment "EXTZP" : zeropage
+
+CURS_X: .res 1
+CURS_Y: .res 1
+SCREEN_PTR: .res 2
+CHARBUF: .res 1
+
+; size 5
+; Adjust size of the ZP segment in osic1p.cfg if the size changes
--- /dev/null
+;
+; copied from CBM implementation
+; originally by:
+; Ullrich von Bassewitz, 07.08.1998
+;
+; void gotox (unsigned char x);
+;
+ .export _gotox
+ .import plot
+ .include "extzp.inc"
+
+_gotox: sta CURS_X ; Set new position
+ jmp plot ; And activate it
--- /dev/null
+;
+; copied from CBM implementation
+;
+; originally by:
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+ .export _gotoxy
+ .import popa, plot
+ .include "extzp.inc"
+
+_gotoxy:
+ sta CURS_Y ; Set Y
+ jsr popa ; Get X
+ sta CURS_X ; Set X
+ jmp plot ; Set the cursor position
--- /dev/null
+;
+; copied from CBM implementation
+; originally by:
+; Ullrich von Bassewitz, 0.08.1998
+;
+; void gotoy (unsigned char y);
+;
+ .export _gotoy
+ .import plot
+ .include "extzp.inc"
+
+_gotoy: sta CURS_Y ; Set the new position
+ jmp plot ; And activate it
--- /dev/null
+;
+; unsigned char kbhit (void);
+;
+; The method to detect a pressed key is based on the documentation in
+; "Section 3 Programmed Key Functions" in "The Challenger Character Graphics
+; Reference Manual"
+; We only want to return true for characters that can be returned by cgetc(),
+; but not for keys like <Shift> or <Ctrl>. Therefore a special handling is
+; needed for the first row. This is implemented by a bit mask that is stored
+; in tmp1 and that is set to zero after the first round.
+;
+
+ .export _kbhit
+ .include "osic1p.inc"
+ .include "extzp.inc"
+ .include "zeropage.inc"
+
+_kbhit:
+ lda #%11011111 ; Mask for only checking the column for the
+ sta tmp1 ; ESC key in the first keyboard row.
+
+ lda #%11111110 ; Mask for first keyboard row
+scan:
+ sta KBD ; Select keyboard row
+ tax ; Save A
+ lda KBD ; Read keyboard columns
+ ora tmp1 ; Mask out uninteresting keys (only relevant in
+ ; first row)
+ cmp #$FF ; No keys pressed?
+ bne keypressed
+ lda #$00 ; For remaining rows no keys masked
+ sta tmp1
+ txa ; Restore A
+ sec ; Want to shift in ones
+ rol a ; Rotate row select to next bit position
+ cmp #$FF ; Done?
+ bne scan ; If not, continue
+ lda #$00 ; Return false
+ tax ; High byte of return is also zero
+ sta CHARBUF ; No character in buffer
+ rts
+keypressed:
+ jsr INPUTC ; Get input character in A
+ sta CHARBUF ; Save in buffer
+ ldx #$00 ; High byte of return is always zero
+ lda #$01 ; Return true
+ rts
--- /dev/null
+;
+; dummy implementation for Challenger 1P based on atmos implementation
+;
+; original by
+; Stefan Haubenthal, 2011-04-18
+;
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+; /* Map a system specific error into a system independent code */
+;
+
+ .include "errno.inc"
+ .export __osmaperrno
+
+.proc __osmaperrno
+
+ lda #<EUNKNOWN
+ ldx #>EUNKNOWN
+ rts
+
+.endproc
--- /dev/null
+; Addresses\r
+INPUTC := $FD00 ; Input character from keyboard\r
+RESET := $FF00 ; Reset address, show boot prompt\r
+KBD := $DF00 ; Polled keyboard register\r
--- /dev/null
+;\r
+; Macro definitions for screen layout modules\r
+;\r
+\r
+ .include "extzp.inc"\r
+ \r
+.linecont +\r
+\r
+;\r
+; Internal function for screensize()\r
+;\r
+.macro osi_screensize ScrWidth, ScrHeight\r
+ ; Macro implementation of internal screensize\r
+ ; function for given width and height in\r
+ ; characters\r
+ \r
+ .export screensize\r
+\r
+.proc screensize\r
+ ldx #ScrWidth\r
+ ldy #ScrHeight\r
+ rts\r
+.endproc\r
+.endmacro\r
+\r
+;\r
+; void clrscr (void);\r
+;\r
+.macro osi_clrscr ScrBase, ScrRamSize\r
+\r
+ .export _clrscr\r
+\r
+.proc _clrscr\r
+ lda #<ScrBase ; Fill whole video RAM with blanks by calling\r
+ ldx #>ScrBase ; memset appropriately\r
+ jsr pushax\r
+ \r
+ lda #' '\r
+ ldx #$00\r
+ jsr pushax\r
+ \r
+ lda #<ScrRamSize\r
+ ldx #>ScrRamSize\r
+ jsr _memset\r
+\r
+ lda #$00 ; Cursor in upper left corner\r
+ sta CURS_X\r
+ sta CURS_Y\r
+ \r
+ jmp plot ; Set the cursor position\r
+.endproc\r
+\r
+.endmacro\r
+\r
+;\r
+; cputc/cputcxy for Challenger 1P\r
+; Based on PET/CBM implementation\r
+;\r
+\r
+.macro osi_cputfuncs ScrBase, ScrFirstChar, ScrWidth, ScrHeight, \\r
+ ScrollDist, ScrLo, ScrHi\r
+\r
+ ; Number of characters to move for scrolling\r
+ ; by one line\r
+ScrollLength = (ScrHeight - 1) * ScrollDist\r
+\r
+;\r
+; void cputcxy (unsigned char x, unsigned char y, char c);\r
+; void cputc (char c);\r
+;\r
+ .export _cputcxy, _cputc, cputdirect, putchar\r
+ .export newline, plot\r
+\r
+_cputcxy:\r
+ pha ; Save C\r
+ jsr popa ; Get Y\r
+ jsr _gotoxy ; Set cursor, drop x\r
+ pla ; Restore C\r
+\r
+; Plot a character - also used as internal function\r
+\r
+_cputc: cmp #$0A ; CR?\r
+ bne L1\r
+ lda #0\r
+ sta CURS_X\r
+ beq plot ; Recalculate pointers\r
+\r
+L1: cmp #$0D ; LF?\r
+ beq newline ; Recalculate pointers\r
+\r
+cputdirect:\r
+ jsr putchar ; Write the character to the screen\r
+\r
+; Advance cursor position, register Y contains horizontal position after\r
+; putchar\r
+\r
+ cpy #(ScrWidth - 1) ; Check whether line is full\r
+ bne L3\r
+ jsr newline ; New line\r
+ ldy #$FF ; + cr\r
+L3: iny\r
+ sty CURS_X\r
+ rts\r
+\r
+newline:\r
+ inc CURS_Y\r
+ lda CURS_Y\r
+ cmp #ScrHeight ; Screen height\r
+ bne plot\r
+ dec CURS_Y ; Bottom of screen reached, scroll\r
+\r
+ ; Scroll destination address\r
+ lda #<(ScrBase + ScrFirstChar)\r
+ ldx #>(ScrBase + ScrFirstChar)\r
+ jsr pushax\r
+ \r
+ ; Scroll source address\r
+ lda #<(ScrBase + ScrFirstChar + ScrollDist)\r
+ ldx #>(ScrBase + ScrFirstChar + ScrollDist)\r
+ jsr pushax\r
+ \r
+ ; Number of characters to move\r
+ lda #<ScrollLength\r
+ ldx #>ScrollLength\r
+ jsr _memmove\r
+\r
+ ; Address of first character in last line\r
+ ; of screen\r
+ lda #<(ScrBase + ScrFirstChar + ScrollLength)\r
+ sta ptr1\r
+ lda #>(ScrBase + ScrFirstChar + ScrollLength)\r
+ sta ptr1+1\r
+ \r
+ ldy #ScrWidth ; Fill last line with blanks\r
+ lda #' '\r
+clrln: sta (ptr1),y\r
+ dey\r
+ bpl clrln\r
+\r
+plot: ldy CURS_Y\r
+ lda ScrLo,y\r
+ sta SCREEN_PTR\r
+ lda ScrHi,y\r
+ sta SCREEN_PTR+1\r
+ rts\r
+\r
+; Write one character to the screen without doing anything else, return X\r
+; position in register Y\r
+\r
+putchar:\r
+ ldy CURS_X\r
+ sta (SCREEN_PTR),y ; Set char\r
+ rts\r
+ \r
+.endmacro\r
+\r
+.macro osi_screen_funcs ScrBase, ScrRamSize, ScrFirstChar, \\r
+ ScrWidth, ScrHeight, ScrollDist\r
+\r
+ .import popa, _gotoxy\r
+ .import _memmove, _memset, pushax\r
+ .importzp ptr1\r
+\r
+.rodata\r
+\r
+; Screen address tables - offset to real screen\r
+ScrTabLo:\r
+ .repeat ScrHeight, I\r
+ .byte <(ScrBase + ScrFirstChar + I * ScrollDist)\r
+ .endrep\r
+ \r
+ScrTabHi:\r
+ .repeat ScrHeight, I\r
+ .byte >(ScrBase + ScrFirstChar + I * ScrollDist)\r
+ .endrep\r
+\r
+.code\r
+\r
+osi_cputfuncs ScrBase, ScrFirstChar, ScrWidth, ScrHeight, \\r
+ ScrollDist, ScrTabLo, ScrTabHi\r
+osi_screensize ScrWidth, ScrHeight\r
+osi_clrscr ScrBase, ScrRamSize\r
+\r
+.endmacro
\ No newline at end of file
--- /dev/null
+;
+; Implementation of screen-layout related functions for Challenger 1P
+;
+
+ .include "osiscreen.inc"
+
+C1P_SCR_BASE := $D000 ; Base of C1P video RAM
+C1P_VRAM_SIZE = $0400 ; Size of C1P video RAM (1 kB)
+C1P_SCR_WIDTH = $18 ; Screen width
+C1P_SCR_HEIGHT = $18 ; Screen height
+C1P_SCR_FIRSTCHAR = $85 ; Offset of cursor position (0, 0) from base
+ ; of video RAM
+C1P_SCROLL_DIST = $20 ; Memory distance for scrolling by one line
+
+osi_screen_funcs C1P_SCR_BASE, C1P_VRAM_SIZE, C1P_SCR_FIRSTCHAR, \
+ C1P_SCR_WIDTH, C1P_SCR_HEIGHT, C1P_SCROLL_DIST
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+; Copied from cbm/wherex.s
+
+; unsigned char wherex (void);
+;
+ .export _wherex
+ .include "extzp.inc"
+
+.proc _wherex
+ lda CURS_X
+ ldx #$00
+ rts
+.endproc
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+; Copied from cbm/wherey.s
+;
+; unsigned char wherey (void);
+;
+ .export _wherey
+ .include "extzp.inc"
+
+.proc _wherey
+ lda CURS_Y
+ ldx #$00
+ rts
+.endproc
--- /dev/null
+;
+; Screen size variables
+;
+ .include "pce.inc"
+
+ .export screensize
+screensize:
+ ldx xsize
+ ldy ysize
+ rts
+
+; FIXME: changing the video mode allows for different screen sizes
+
+.rodata
+ .export xsize, ysize
+
+xsize: .byte charsperline
+ysize: .byte screenrows
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+ .export _chlinexy, _chline
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+ .include "pce.inc"
+
+_chlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length
+
+_chline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #CH_HLINE ; Horizontal line, screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+;
+; clock_t clock (void);
+;
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .export _clock
+ .forceimport ticktock
+ .importzp sreg
+ .constructor initclock
+
+
+.proc _clock
+
+ lda tickcount+3
+ sta sreg+1
+ lda tickcount+2
+ sta sreg
+ ldx tickcount+1
+ lda tickcount
+ rts
+
+.endproc
+
+ .segment "INIT"
+initclock:
+ lda #0
+ ldx #3
+@lp: sta tickcount,x
+ dex
+ bpl @lp
+ rts
--- /dev/null
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .import plot
+ .export _clrscr
+_clrscr:
+
+ st0 #VDC_MAWR
+ st1 #<$0000
+ st2 #>$0000
+
+ st0 #VDC_VWR
+ ldy #$40
+rowloop:
+ ldx #$80
+colloop:
+ lda #' '
+ sta a:VDC_DATA_LO
+ lda #$02
+ sta a:VDC_DATA_HI
+
+ dex
+ bne colloop
+ dey
+ bne rowloop
+
+; Go to the home position.
+
+ stz CURS_X
+ stz CURS_Y
+ jmp plot
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
--- /dev/null
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+ .export _textcolor, _bgcolor, _bordercolor
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+_textcolor:
+ ldx CHARCOLOR ; get old value
+ sta CHARCOLOR ; set new value
+ txa
+ rts
+
+_bgcolor:
+ ldx BGCOLOR ; get old value
+ sta BGCOLOR ; set new value
+ asl a
+ tay
+
+ stz VCE_ADDR_LO
+ stz VCE_ADDR_HI
+ lda colors,y
+ sta VCE_DATA_LO
+ lda colors+1,y
+ sta VCE_DATA_HI
+
+ txa
+ rts
+
+_bordercolor:
+ lda #0
+ tax
+ rts
+
+ .rodata
+ .export colors
+
+colors:
+ ; G R B
+ .word ((0<<6)+(0<<3)+(0)) ; 0 black
+ .word ((7<<6)+(7<<3)+(7)) ; 1 white
+ .word ((0<<6)+(7<<3)+(0)) ; 2 red
+ .word ((7<<6)+(0<<3)+(7)) ; 3 cyan
+ .word ((0<<6)+(5<<3)+(7)) ; 4 violett
+ .word ((7<<6)+(0<<3)+(0)) ; 5 green
+ .word ((0<<6)+(0<<3)+(7)) ; 6 blue
+ .word ((7<<6)+(7<<3)+(0)) ; 7 yellow
+ .word ((5<<6)+(7<<3)+(0)) ; 8 orange
+ .word ((3<<6)+(4<<3)+(3)) ; 9 brown
+ .word ((4<<6)+(7<<3)+(4)) ; a light red
+ .word ((3<<6)+(3<<3)+(3)) ; b dark grey
+ .word ((4<<6)+(4<<3)+(4)) ; c middle grey
+ .word ((7<<6)+(4<<3)+(4)) ; d light green
+ .word ((4<<6)+(4<<3)+(7)) ; e light blue
+ .word ((6<<6)+(6<<3)+(6)) ; f light gray
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
--- /dev/null
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .import vce_init
+ .import psg_init
+ .import colors
+ .importzp ptr1, tmp1
+
+ .constructor initconio
+
+ .macpack longbranch
+
+ .segment "INIT"
+initconio:
+ jsr vce_init
+ jsr psg_init
+ jsr conio_init
+ jsr set_palette
+
+ st0 #VDC_CR
+ st1 #<$0088
+ st2 #>$0088
+ rts
+
+set_palette:
+ stz VCE_ADDR_LO
+ stz VCE_ADDR_HI
+
+ ldx #0
+@lp:
+ ldy #16
+@lp1:
+ lda colors,x
+ sta VCE_DATA_LO
+ lda colors+1,x
+ sta VCE_DATA_HI
+ dey
+ bne @lp1
+
+ inx
+ inx
+ cpx #16*2
+ jne @lp
+
+ stz VCE_ADDR_LO
+ stz VCE_ADDR_HI
+ stz VCE_DATA_LO
+ stz VCE_DATA_HI
+
+ rts
+
+conio_init:
+ ; Load font
+ st0 #VDC_MAWR
+ st1 #<$2000
+ st2 #>$2000
+
+ ; ptr to font data
+ lda #<font
+ sta ptr1
+ lda #>font
+ sta ptr1+1
+
+ st0 #VDC_VWR ; VWR
+
+ lda #0
+ sta tmp1
+ jsr copy
+
+ lda #<font
+ sta ptr1
+ lda #>font
+ sta ptr1+1
+
+ lda #$ff
+ sta tmp1
+ jsr copy
+
+ ldx #0
+ stx BGCOLOR
+ inx
+ stx CHARCOLOR
+
+ rts
+
+copy:
+ ldy #$80 ; 128 chars
+charloop:
+ ldx #$08 ; 8 bytes/char
+lineloop:
+ lda (ptr1)
+ eor tmp1
+ sta a:VDC_DATA_LO ; bitplane 0
+ stz a:VDC_DATA_HI ; bitplane 1
+
+ clc ; increment font pointer
+ lda ptr1
+ adc #$01
+ sta ptr1
+ lda ptr1+1
+ adc #$00
+ sta ptr1+1
+ dex
+ bne lineloop ; next bitplane 0 byte
+ ldx #$08 ; fill bitplane 2/3 with 0
+fillloop:
+ st1 #$00
+ st2 #$00
+ dex
+ bne fillloop ; next byte
+ dey
+ bne charloop ; next character
+
+ rts
+
+font:
+ .include "vga.inc"
--- /dev/null
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export newline, plot
+ .import popa, _gotoxy
+ .import PLOT
+ .import xsize
+
+ .importzp tmp3,tmp4
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0d ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0a ; LF?
+ beq newline ; Recalculate pointers
+
+; Printable char of some sort
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ ldy CURS_X
+ iny
+ cpy xsize
+ bne L3
+ jsr newline ; new line
+ ldy #0 ; + cr
+L3: sty CURS_X
+ jmp plot
+
+newline:
+ inc CURS_Y
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT ; Set the new cursor
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+
+ ora RVS ; Set revers bit
+
+ tax
+
+ st0 #VDC_MAWR ; Memory Adress Write
+
+ lda SCREEN_PTR
+ sta a:VDC_DATA_LO
+
+ lda SCREEN_PTR + 1
+ sta a:VDC_DATA_HI
+
+ st0 #VDC_VWR ; VWR
+
+ txa
+ sta a:VDC_DATA_LO ; character
+
+ lda CHARCOLOR
+
+ asl a
+ asl a
+ asl a
+ asl a
+
+ ora #$02
+ sta a:VDC_DATA_HI
+
+ rts
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
--- /dev/null
+;
+; Startup code for cc65 (PCEngine version)
+;
+; by Groepaz/Hitmen <groepaz@gmx.net>
+; based on code by Ullrich von Bassewitz <uz@cc65.org>
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .export __STARTUP__ : absolute = 1 ; Mark as startup
+
+ .import initlib, donelib
+ .import push0, _main, zerobss
+ .import initheap
+ .import IRQStub
+
+ ; Linker generated
+ .import __RAM_START__, __RAM_SIZE__
+ .import __ROM0_START__, __ROM0_SIZE__
+ .import __ROM_START__, __ROM_SIZE__
+ .import __STARTUP_LOAD__,__STARTUP_RUN__, __STARTUP_SIZE__
+ .import __CODE_LOAD__,__CODE_RUN__, __CODE_SIZE__
+ .import __RODATA_LOAD__,__RODATA_RUN__, __RODATA_SIZE__
+ .import __DATA_LOAD__,__DATA_RUN__, __DATA_SIZE__
+ .import __BSS_SIZE__
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .importzp sp
+ .importzp ptr1,ptr2
+ .importzp tmp1,tmp2,tmp3
+
+; ------------------------------------------------------------------------
+; Place the startup code in a special segment.
+
+ .segment "STARTUP"
+
+start:
+
+ ; setup the CPU and System-IRQ
+
+ ; Initialize CPU
+
+ sei
+ nop
+ csh ; set high speed CPU mode
+ nop
+ cld
+ nop
+
+ ; Setup stack and memory mapping
+ ldx #$FF ; Stack top ($21FF)
+ txs
+
+ ; at startup all MPRs are set to 0, so init them
+ lda #$ff
+ tam #%00000001 ; 0000-1FFF = Hardware page
+ lda #$F8
+ tam #%00000010 ; 2000-3FFF = Work RAM
+
+ ; FIXME: setup a larger block of memory to use with C-code
+ ;lda #$F7
+ ;tam #%00000100 ; 4000-5FFF = Save RAM
+ ;lda #1
+ ;tam #%00001000 ; 6000-7FFF Page 2
+ ;lda #2
+ ;tam #%00010000 ; 8000-9FFF Page 3
+ ;lda #3
+ ;tam #%00100000 ; A000-BFFF Page 4
+ ;lda #4
+ ;tam #%01000000 ; C000-DFFF Page 5
+ ;lda #0
+ ;tam #%10000000 ; e000-fFFF hucard/syscard bank 0
+
+ ; Clear work RAM (2000-3FFF)
+ stz <$00
+ tii $2000, $2001, $1FFF
+
+ ; Initialize hardware
+ stz TIMER_CTRL ; Timer off
+ lda #$07
+ sta IRQ_MASK ; Interrupts off
+ stz IRQ_STATUS ; Acknowledge timer
+
+ ; FIXME; i dont know why the heck this one doesnt work when called from a constructor :/
+ .import vdc_init
+ jsr vdc_init
+
+ ; Turn on background and VD interrupt/IRQ1
+ lda #$05
+ sta IRQ_MASK ; IRQ1=on
+
+ ; Clear the BSS data
+ jsr zerobss
+
+ ; Copy the .data segment to RAM
+ tii __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__
+
+ ; setup the stack
+ lda #<(__RAM_START__+__RAM_SIZE__)
+ sta sp
+ lda #>(__RAM_START__+__RAM_SIZE__)
+ sta sp + 1
+
+ ; Call module constructors
+ jsr initlib
+
+ cli ; allow IRQ only after constructors have run
+
+ ; Pass an empty command line
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+ ; Call module destructors. This is also the _exit entry.
+_exit:
+ jsr donelib ; Run module destructors
+
+ ; reset the PCEngine (start over)
+ jmp start
+
+_nmi:
+ rti
+
+ .export initmainargs
+initmainargs:
+ rts
+
+; ------------------------------------------------------------------------
+; hardware vectors
+; ------------------------------------------------------------------------
+ .segment "VECTORS"
+
+ .word IRQStub ; $fff6 IRQ2 (External IRQ, BRK)
+ .word IRQStub ; $fff8 IRQ1 (VDC)
+ .word IRQStub ; $fffa Timer
+ .word _nmi ; $fffc NMI
+ .word start ; $fffe reset
--- /dev/null
+;
+; Stefan Haubenthal with minor changes from Ullrich von Bassewitz, 2003-05-02
+;
+; Character specification table.
+;
+
+ .include "ctype.inc"
+
+; The tables are readonly, put them into the rodata segment
+
+.rodata
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+; * It is fast. If it were'nt for the slow parameter passing of cc65, one
+; could even define macros for the isxxx functions (this is usually
+; done on other platforms).
+;
+; * It is highly portable. The only unportable part is the table itself,
+; all real code goes into the common library.
+;
+; * We save some code in the isxxx functions.
+
+
+__ctype:
+ .repeat 2
+ .byte CT_CTRL ; 0/00 ___ctrl_@___
+ .byte CT_CTRL ; 1/01 ___ctrl_A___
+ .byte CT_CTRL ; 2/02 ___ctrl_B___
+ .byte CT_CTRL ; 3/03 ___ctrl_C___
+ .byte CT_CTRL ; 4/04 ___ctrl_D___
+ .byte CT_CTRL ; 5/05 ___ctrl_E___
+ .byte CT_CTRL ; 6/06 ___ctrl_F___
+ .byte CT_CTRL ; 7/07 ___ctrl_G___
+ .byte CT_CTRL ; 8/08 ___ctrl_H___
+ .byte CT_CTRL | CT_OTHER_WS | CT_SPACE_TAB
+ ; 9/09 ___ctrl_I___
+ .byte CT_CTRL | CT_OTHER_WS ; 10/0a ___ctrl_J___
+ .byte CT_CTRL | CT_OTHER_WS ; 11/0b ___ctrl_K___
+ .byte CT_CTRL | CT_OTHER_WS ; 12/0c ___ctrl_L___
+ .byte CT_CTRL | CT_OTHER_WS ; 13/0d ___ctrl_M___
+ .byte CT_CTRL ; 14/0e ___ctrl_N___
+ .byte CT_CTRL ; 15/0f ___ctrl_O___
+ .byte CT_CTRL ; 16/10 ___ctrl_P___
+ .byte CT_CTRL ; 17/11 ___ctrl_Q___
+ .byte CT_CTRL ; 18/12 ___ctrl_R___
+ .byte CT_CTRL ; 19/13 ___ctrl_S___
+ .byte CT_CTRL ; 20/14 ___ctrl_T___
+ .byte CT_CTRL ; 21/15 ___ctrl_U___
+ .byte CT_CTRL ; 22/16 ___ctrl_V___
+ .byte CT_CTRL ; 23/17 ___ctrl_W___
+ .byte CT_CTRL ; 24/18 ___ctrl_X___
+ .byte CT_CTRL ; 25/19 ___ctrl_Y___
+ .byte CT_CTRL ; 26/1a ___ctrl_Z___
+ .byte CT_CTRL ; 27/1b ___ctrl_[___
+ .byte CT_CTRL ; 28/1c ___ctrl_\___
+ .byte CT_CTRL ; 29/1d ___ctrl_]___
+ .byte CT_CTRL ; 30/1e ___ctrl_^___
+ .byte CT_CTRL ; 31/1f ___ctrl_____
+ .byte CT_SPACE | CT_SPACE_TAB ; 32/20 ___SPACE___
+ .byte CT_NONE ; 33/21 _____!_____
+ .byte CT_NONE ; 34/22 _____"_____
+ .byte CT_NONE ; 35/23 _____#_____
+ .byte CT_NONE ; 36/24 _____$_____
+ .byte CT_NONE ; 37/25 _____%_____
+ .byte CT_NONE ; 38/26 _____&_____
+ .byte CT_NONE ; 39/27 _____'_____
+ .byte CT_NONE ; 40/28 _____(_____
+ .byte CT_NONE ; 41/29 _____)_____
+ .byte CT_NONE ; 42/2a _____*_____
+ .byte CT_NONE ; 43/2b _____+_____
+ .byte CT_NONE ; 44/2c _____,_____
+ .byte CT_NONE ; 45/2d _____-_____
+ .byte CT_NONE ; 46/2e _____._____
+ .byte CT_NONE ; 47/2f _____/_____
+ .byte CT_DIGIT | CT_XDIGIT ; 48/30 _____0_____
+ .byte CT_DIGIT | CT_XDIGIT ; 49/31 _____1_____
+ .byte CT_DIGIT | CT_XDIGIT ; 50/32 _____2_____
+ .byte CT_DIGIT | CT_XDIGIT ; 51/33 _____3_____
+ .byte CT_DIGIT | CT_XDIGIT ; 52/34 _____4_____
+ .byte CT_DIGIT | CT_XDIGIT ; 53/35 _____5_____
+ .byte CT_DIGIT | CT_XDIGIT ; 54/36 _____6_____
+ .byte CT_DIGIT | CT_XDIGIT ; 55/37 _____7_____
+ .byte CT_DIGIT | CT_XDIGIT ; 56/38 _____8_____
+ .byte CT_DIGIT | CT_XDIGIT ; 57/39 _____9_____
+ .byte CT_NONE ; 58/3a _____:_____
+ .byte CT_NONE ; 59/3b _____;_____
+ .byte CT_NONE ; 60/3c _____<_____
+ .byte CT_NONE ; 61/3d _____=_____
+ .byte CT_NONE ; 62/3e _____>_____
+ .byte CT_NONE ; 63/3f _____?_____
+
+ .byte CT_NONE ; 64/40 _____@_____
+ .byte CT_UPPER | CT_XDIGIT ; 65/41 _____A_____
+ .byte CT_UPPER | CT_XDIGIT ; 66/42 _____B_____
+ .byte CT_UPPER | CT_XDIGIT ; 67/43 _____C_____
+ .byte CT_UPPER | CT_XDIGIT ; 68/44 _____D_____
+ .byte CT_UPPER | CT_XDIGIT ; 69/45 _____E_____
+ .byte CT_UPPER | CT_XDIGIT ; 70/46 _____F_____
+ .byte CT_UPPER ; 71/47 _____G_____
+ .byte CT_UPPER ; 72/48 _____H_____
+ .byte CT_UPPER ; 73/49 _____I_____
+ .byte CT_UPPER ; 74/4a _____J_____
+ .byte CT_UPPER ; 75/4b _____K_____
+ .byte CT_UPPER ; 76/4c _____L_____
+ .byte CT_UPPER ; 77/4d _____M_____
+ .byte CT_UPPER ; 78/4e _____N_____
+ .byte CT_UPPER ; 79/4f _____O_____
+ .byte CT_UPPER ; 80/50 _____P_____
+ .byte CT_UPPER ; 81/51 _____Q_____
+ .byte CT_UPPER ; 82/52 _____R_____
+ .byte CT_UPPER ; 83/53 _____S_____
+ .byte CT_UPPER ; 84/54 _____T_____
+ .byte CT_UPPER ; 85/55 _____U_____
+ .byte CT_UPPER ; 86/56 _____V_____
+ .byte CT_UPPER ; 87/57 _____W_____
+ .byte CT_UPPER ; 88/58 _____X_____
+ .byte CT_UPPER ; 89/59 _____Y_____
+ .byte CT_UPPER ; 90/5a _____Z_____
+ .byte CT_NONE ; 91/5b _____[_____
+ .byte CT_NONE ; 92/5c _____\_____
+ .byte CT_NONE ; 93/5d _____]_____
+ .byte CT_NONE ; 94/5e _____^_____
+ .byte CT_NONE ; 95/5f _UNDERLINE_
+ .byte CT_NONE ; 96/60 ___grave___
+ .byte CT_LOWER | CT_XDIGIT ; 97/61 _____a_____
+ .byte CT_LOWER | CT_XDIGIT ; 98/62 _____b_____
+ .byte CT_LOWER | CT_XDIGIT ; 99/63 _____c_____
+ .byte CT_LOWER | CT_XDIGIT ; 100/64 _____d_____
+ .byte CT_LOWER | CT_XDIGIT ; 101/65 _____e_____
+ .byte CT_LOWER | CT_XDIGIT ; 102/66 _____f_____
+ .byte CT_LOWER ; 103/67 _____g_____
+ .byte CT_LOWER ; 104/68 _____h_____
+ .byte CT_LOWER ; 105/69 _____i_____
+ .byte CT_LOWER ; 106/6a _____j_____
+ .byte CT_LOWER ; 107/6b _____k_____
+ .byte CT_LOWER ; 108/6c _____l_____
+ .byte CT_LOWER ; 109/6d _____m_____
+ .byte CT_LOWER ; 110/6e _____n_____
+ .byte CT_LOWER ; 111/6f _____o_____
+ .byte CT_LOWER ; 112/70 _____p_____
+ .byte CT_LOWER ; 113/71 _____q_____
+ .byte CT_LOWER ; 114/72 _____r_____
+ .byte CT_LOWER ; 115/73 _____s_____
+ .byte CT_LOWER ; 116/74 _____t_____
+ .byte CT_LOWER ; 117/75 _____u_____
+ .byte CT_LOWER ; 118/76 _____v_____
+ .byte CT_LOWER ; 119/77 _____w_____
+ .byte CT_LOWER ; 120/78 _____x_____
+ .byte CT_LOWER ; 121/79 _____y_____
+ .byte CT_LOWER ; 122/7a _____z_____
+ .byte CT_NONE ; 123/7b _____{_____
+ .byte CT_NONE ; 124/7c _____|_____
+ .byte CT_NONE ; 125/7d _____}_____
+ .byte CT_NONE ; 126/7e _____~_____
+ .byte CT_OTHER_WS ; 127/7f ____DEL____
+ .endrepeat
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+ .export _cvlinexy, _cvline
+ .import popa, _gotoxy, putchar, newline
+ .importzp tmp1
+
+ .include "pce.inc"
+
+_cvlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cvline
+
+_cvline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #CH_VLINE ; Vertical bar
+ jsr putchar ; Write, no cursor advance
+ jsr newline ; Advance cursor to next line
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
--- /dev/null
+;
+; extzp.inc for the PC-Engine
+;
+; Groepaz/Hitmen, 2015-11-19
+;
+; Assembler include file that imports the runtime zero page locations used
+; by the PC-Engine runtime, ready for usage in asm code.
+;
+
+
+ .global CURS_X: zp
+ .global CURS_Y: zp
+ .global SCREEN_PTR: zp
+ .global CHARCOLOR: zp
+ .global RVS: zp
+ .global BGCOLOR: zp
+ .global tickcount: zp
+ .global vdc_flags: zp
--- /dev/null
+;
+; Groepaz/Hitmen, 2015-11-19
+;
+; zeropage locations for exclusive use by the library
+;
+
+ .include "extzp.inc"
+
+ .segment "EXTZP" : zeropage
+
+CURS_X: .res 1
+CURS_Y: .res 1
+SCREEN_PTR: .res 2
+CHARCOLOR: .res 1
+RVS: .res 1
+BGCOLOR: .res 1
+tickcount: .res 4
+vdc_flags: .res 1
--- /dev/null
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+
+ .export _gotoxy
+ .import popa, plot
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+_gotoxy:
+ sta CURS_Y ; Set Y
+ jsr popa ; Get X
+ sta CURS_X ; Set X
+ jmp plot ; Set the cursor position
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
+
--- /dev/null
+;
+; IRQ handling (PCE version)
+;
+
+ .export initirq, doneirq, IRQStub
+
+ .import __INTERRUPTOR_COUNT__, callirq_y
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+; ------------------------------------------------------------------------
+.segment "INIT"
+
+; a constructor
+;
+initirq:
+ rts
+
+; ------------------------------------------------------------------------
+.code
+
+; a destructor
+;
+doneirq:
+ rts
+
+; ------------------------------------------------------------------------
+
+IRQStub:
+ phy
+
+; Save the display-source flags (and, release the interrupt).
+;
+ ldy a:VDC_CTRL
+ sty vdc_flags
+
+ ldy #<(__INTERRUPTOR_COUNT__ * 2)
+ beq @L1
+ phx
+ pha
+
+ jsr callirq_y
+
+ pla
+ plx
+@L1: ply
+ rti
--- /dev/null
+
+;
+; Standard joystick driver for the PCEngine
+;
+
+ .include "joy-kernel.inc"
+ .include "joy-error.inc"
+ .include "pce.inc"
+
+ .macpack module
+
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table
+
+ module_header _pce_stdjoy_joy
+
+; Driver signature
+
+ .byte $6A, $6F, $79 ; "joy"
+ .byte JOY_API_VERSION ; Driver API version number
+
+; Library reference
+
+ .addr $0000
+
+; Button state masks (8 values)
+
+ .byte $10 ; JOY_UP
+ .byte $40 ; JOY_DOWN
+ .byte $80 ; JOY_LEFT
+ .byte $20 ; JOY_RIGHT
+ .byte $01 ; JOY_FIRE_A
+ .byte $02 ; JOY_FIRE_B
+ .byte $04 ; JOY_SELECT
+ .byte $08 ; JOY_RUN
+
+; Jump table.
+
+ .addr INSTALL
+ .addr UNINSTALL
+ .addr COUNT
+ .addr READJOY
+ .addr 0 ; IRQ entry unused
+
+; ------------------------------------------------------------------------
+; Constants
+
+JOY_COUNT = 4 ; Number of joysticks we support
+
+
+.code
+
+; ------------------------------------------------------------------------
+; INSTALL routine. Is called after the driver is loaded into memory. If
+; possible, check if the hardware is present and determine the amount of
+; memory available.
+; Must return an JOY_ERR_xx code in a/x.
+;
+
+INSTALL:
+ lda #<JOY_ERR_OK
+ ldx #>JOY_ERR_OK
+
+; rts ; Run into UNINSTALL instead
+
+; ------------------------------------------------------------------------
+; DEINSTALL routine. Is called before the driver is removed from memory.
+; Can do cleanup or whatever. Must not return anything.
+;
+
+UNINSTALL:
+ rts
+
+
+; ------------------------------------------------------------------------
+; COUNT: Return the total number of available joysticks in a/x.
+;
+;unsigned char __fastcall__ joy_count (void);
+
+COUNT:
+ lda #<JOY_COUNT
+ ldx #>JOY_COUNT
+ rts
+
+; ------------------------------------------------------------------------
+; READ: Read a particular joystick passed in A.
+;
+;unsigned char __fastcall__ joy_read (unsigned char joystick);
+
+READJOY:
+ pha
+ jsr read_joy
+ pla
+ tax ; Joystick number into X
+
+ ; return value from buffer
+
+joy1:
+ lda padbuffer,x
+ ldx #0
+ rts
+
+read_joy:
+ ; reset multitap counter
+ lda #$01
+ sta JOY_CTRL
+ pha
+ pla
+ nop
+ nop
+
+ lda #$03
+ sta JOY_CTRL
+ pha
+ pla
+ nop
+ nop
+
+ cly
+nextpad:
+ lda #$01
+ sta JOY_CTRL ; sel = 1
+ pha
+ pla
+ nop ; some delay is required
+ nop
+
+ lda JOY_CTRL
+ asl a
+ asl a
+ asl a
+ asl a
+ sta padbuffer, y ; store new value
+
+ stz JOY_CTRL
+ pha
+ pla
+
+ nop ; some delay is required
+ nop
+
+ lda JOY_CTRL
+ and #$0F
+ ora padbuffer, y ; second half of new value
+
+ eor #$FF
+ sta padbuffer, y ; store new value
+
+ iny
+ cpy #$05
+ bcc nextpad
+ rts
+
+.bss
+
+padbuffer:
+ .res 4
+
--- /dev/null
+;
+; Address of the static standard joystick driver
+;
+; Oliver Schmidt, 2012-11-01
+;
+; const void joy_static_stddrv[];
+;
+
+ .export _joy_static_stddrv
+ .import _pce_stdjoy_joy
+
+.rodata
+
+_joy_static_stddrv := _pce_stdjoy_joy
--- /dev/null
+;
+; Name of the standard joystick driver
+;
+; Oliver Schmidt, 2012-11-01
+;
+; const char joy_stddrv[];
+;
+
+ .export _joy_stddrv
+
+.rodata
+
+_joy_stddrv: .asciiz "pce-stdjoy.joy"
--- /dev/null
+
+ .export PLOT
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+PLOT:
+ bcs @getpos
+
+ tya
+ ;clc ; already cleared
+ adc _plotlo,x
+ sta SCREEN_PTR
+
+ lda _plothi,x
+ adc #0
+ sta SCREEN_PTR+1
+@getpos:
+ ldx CURS_Y
+ ldy CURS_X
+ rts
+
+ .rodata
+
+_plotlo:
+ .repeat screenrows,line
+ .byte <($0000+(line*$80))
+ .endrepeat
+
+_plothi:
+ .repeat screenrows,line
+ .byte >($0000+(line*$80))
+ .endrepeat
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
--- /dev/null
+;
+; Oliver Schmidt, 2013-05-31
+;
+
+ .export joy_libref
+ .import _exit
+
+joy_libref := _exit
--- /dev/null
+;
+; This file, instead of "common/memcpy.s", will be assembled for the pce
+; target. This version is smaller and faster because it uses the HuC6280's
+; block-copy instructions.
+;
+; 2003-08-20, Ullrich von Bassewitz
+; 2015-11-02, Greg King
+;
+; void* __fastcall__ memcpy (void* dest, const void* src, size_t size);
+;
+; NOTE: This function contains entry points for memmove(), which resorts to
+; memcpy() for incrementing copies. The PC-Engine memset() uses this memcpy()
+; to fill memory quickly. Don't change this module without looking at
+; "pce/memmove.s" and "pce/memset.s"!
+;
+
+ .export _memcpy
+ .export memcpy_increment, memcpy_transfer, memcpy_getparams
+
+ .import incsp2, popax
+ .importzp sp, ptr1, ptr2, ptr3
+
+
+; The structure of the transfer instructions
+
+ .struct
+opcode .byte
+source .addr
+destination .addr
+length .word
+ .endstruct
+
+; ----------------------------------------------------------------------
+_memcpy:
+ jsr memcpy_getparams
+
+memcpy_increment:
+ ldy #$73 ; TII opcode
+
+memcpy_transfer:
+ sty transfer + opcode
+
+ lda ptr1
+ ldx ptr1+1
+ sta transfer + source
+ stx transfer + source+1
+
+ lda ptr2
+ ldx ptr2+1
+ sta transfer + destination
+ stx transfer + destination+1
+
+ lda ptr3
+ ldx ptr3+1
+ sta transfer + length
+ stx transfer + length+1
+
+ jmp transfer
+
+; ----------------------------------------------------------------------
+; Get the parameters from the stack, as follows:
+;
+; size --> ptr3
+; src --> ptr1
+; dest --> ptr2
+;
+; The first argument (dest) will remain on the stack; and, is returned in .XA!
+
+memcpy_getparams:
+ sta ptr3
+ stx ptr3+1 ; save size
+ ora ptr3+1
+ bne @L1
+
+; The size is zero; copy nothing; just return the dest address.
+; (The HuC6280's transfer instructions can't copy $0000 bytes;
+; they would copy $10000 [64K] bytes instead.)
+
+ ply ; drop return address
+ plx
+ jsr incsp2 ; drop src address
+ jmp popax ; get pointer; return it as result
+
+@L1: jsr popax
+ sta ptr1
+ stx ptr1+1 ; save src
+
+; (Direct stack access is six cycles faster [total cycle count].)
+
+ ldy #1 ; save dest
+ lda (sp),y ; get high byte
+ tax
+ lda (sp) ; get low byte
+ sta ptr2
+ stx ptr2+1
+ rts ; return dest address (for memmove)
+
+; ----------------------------------------------------------------------
+; The transfer instructions use inline arguments.
+; Therefore, we must build the instruction, in the DATA segment.
+
+.data
+
+transfer:
+ tii $FFFF, $FFFF, $0001
+ jmp popax ; get pointer; return it as result
--- /dev/null
+;
+; This file, instead of "common/memmove.s", will be assembled for the pce
+; target. This version is smaller and faster because it uses the HuC6280's
+; block-copy instructions.
+;
+; 2003-08-20, Ullrich von Bassewitz
+; 2015-10-23, Greg King
+;
+; void* __fastcall__ memmove (void* dest, const void* src, size_t size);
+;
+; NOTE: This function uses entry points from "pce/memcpy.s"!
+;
+
+ .export _memmove
+
+ .import memcpy_getparams, memcpy_increment, memcpy_transfer
+ .importzp ptr1, ptr2, ptr3
+
+ .macpack generic
+ .macpack longbranch
+
+
+; ----------------------------------------------------------------------
+_memmove:
+ jsr memcpy_getparams
+
+; Check for the copy direction. If dest < src, we must copy downwards (start
+; at low addresses, and increase pointers); otherwise, we must copy upwards
+; (start at high addresses, and decrease pointers).
+
+ cmp ptr1
+ txa
+ sbc ptr1+1
+ jcc memcpy_increment ; Branch if dest < src
+
+; Copy decrementing; adjust the pointers to the end of the memory regions.
+
+ lda ptr1
+ add ptr3
+ sta ptr1
+ lda ptr1+1
+ adc ptr3+1
+ sta ptr1+1
+
+ lda ptr1 ; point to last byte of source
+ bne @L1
+ dec ptr1+1
+@L1: dec ptr1
+
+ lda ptr2
+ add ptr3
+ sta ptr2
+ lda ptr2+1
+ adc ptr3+1
+ sta ptr2+1
+
+ lda ptr2 ; point to last byte of target
+ bne @L2
+ dec ptr2+1
+@L2: dec ptr2
+
+ ldy #$C3 ; TDD opcode
+ jmp memcpy_transfer
--- /dev/null
+;
+; This file, instead of "common/memset.s", will be assembled for the pce
+; target. This version is smaller and faster because it uses a HuC6280
+; block-copy instruction.
+;
+; 1998-05-29, Ullrich von Bassewitz
+; 2015-11-06, Greg King
+;
+; void* __fastcall__ _bzero (void* ptr, size_t n);
+; void __fastcall__ bzero (void* ptr, size_t n);
+; void* __fastcall__ memset (void* ptr, int c, size_t n);
+;
+; NOTE: bzero() will return its first argument, as memset() does. It is no
+; problem to declare the return value as void, because it can be ignored.
+; _bzero() (note the leading underscore) is declared with the proper
+; return type because the compiler will replace memset() by _bzero() if
+; the fill value is zero; and, the optimizer looks at the return type
+; to see if the value in .XA is of any use.
+;
+; NOTE: This function uses entry points from "pce/memcpy.s"!
+;
+
+ .export __bzero, _bzero, _memset
+
+ .import memcpy_getparams, memcpy_increment
+ .import pushax, popax
+ .importzp ptr1, ptr2, ptr3
+
+ .macpack longbranch
+
+
+; ----------------------------------------------------------------------
+__bzero:
+_bzero: pha
+ cla ; fill with zeros
+ jsr pushax ; (high byte isn't important)
+ pla
+
+_memset:
+ jsr memcpy_getparams
+
+; The fill byte is put at the beginning of the buffer; then, the buffer is
+; copied to a second buffer that starts one byte above the start of the first
+; buffer. Normally, we would use memmove() to avoid trouble; but here, we
+; exploit that overlap, by using memcpy(). Therefore, the fill value is copied
+; from each byte to the next byte, all the way to the end of the buffer.
+
+ lda ptr1 ; get fill value
+ sta (ptr2)
+
+ lda ptr3 ; count first byte
+ bne @L3
+ dec ptr3+1
+@L3: dec a
+ sta ptr3
+ ora ptr3+1
+ jeq popax ; return ptr. if no more bytes
+
+ lda ptr2 ; point to first buffer
+ ldx ptr2+1
+ sta ptr1
+ stx ptr1+1
+ inc ptr2 ; point to second buffer
+ bne @L2
+ inc ptr2+1
+
+@L2: jmp memcpy_increment
--- /dev/null
+ .include "pce.inc"
+
+ .export psg_init
+
+ .segment "INIT"
+psg_init:
+ clx
+ stz PSG_GLOBAL_PAN ; Clear global balance
+
+psg_clear_loop:
+ stx PSG_CHAN_SELECT ; Select channel
+ stz PSG_FREQ_LO ; Clear frequency LSB
+ stz PSG_FREQ_HI ; Clear frequency MSB
+ stz PSG_CHAN_CTRL ; Clear volume
+ stz PSG_CHAN_PAN ; Clear balance
+ stz PSG_NOISE ; Clear noise control
+ stz PSG_LFO_FREQ ; Clear LFO frequency
+ stz PSG_LFO_CTRL ; Clear LFO control
+
+ cly
+psg_clear_waveform:
+ stz PSG_CHAN_DATA ; Clear waveform byte
+ iny
+ cpy #$20
+ bne psg_clear_waveform
+
+ inx
+ cpx #$06
+ bne psg_clear_loop
+ rts
--- /dev/null
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .export _revers
+
+.proc _revers
+
+ ldx #$00 ; Assume revers off
+ tay ; Test onoff
+ beq L1 ; Jump if off
+ ldx #$80 ; Load on value
+ ldy #$00 ; Assume old value is zero
+L1: lda RVS ; Load old value
+ stx RVS ; Set new value
+ beq L2 ; Jump if old value zero
+ iny ; Make old value = 1
+L2: ldx #$00 ; Load high byte of result
+ tya ; Load low byte, set CC
+ rts
+
+.endproc
+
+;-------------------------------------------------------------------------------
+; force the init constructor to be imported
+
+ .import initconio
+conio_init = initconio
--- /dev/null
+ .interruptor ticktock, 24
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ticktock:
+ bbr5 vdc_flags,@s1 ; not vertical-blank interrupt
+
+ ; Increment the system tick counter.
+ inc tickcount
+ bne @s1
+ inc tickcount+1
+ bne @s1
+ inc tickcount+2
+ bne @s1
+ inc tickcount+3
+
+@s1: rts
--- /dev/null
+ .include "pce.inc"
+
+ .export vce_init
+
+ .segment "INIT"
+vce_init:
+ ; Set CTA to zero
+ stz VCE_ADDR_LO
+ stz VCE_ADDR_HI
+ ldy #$01
+vce_clear_bank:
+ ldx #$00
+vce_clear_color:
+ stz VCE_DATA_LO ; Clear color (LSB)
+ stz VCE_DATA_HI ; Clear color (MSB)
+ dex
+ bne vce_clear_color
+ dey
+ bne vce_clear_bank
+ rts
--- /dev/null
+
+ .include "pce.inc"
+
+; FIXME: implement selection of different video modes at runtime
+HIRES = 1
+
+ .export vdc_init
+
+vdc_init:
+ lda a:VDC_CTRL
+
+ VREG $00, $0000 ; MAWR
+ VREG $01, $0000 ; MARR
+ VREG $05, $0000 ; CR
+ VREG $06, $0000 ; RCR
+ VREG $07, $0000 ; BXR
+ VREG $08, $0000 ; BYR
+ VREG $09, $0070 ; MAWR
+ VREG $0C, $1702 ; CRTC - VSR
+ VREG $0D, $00DF ; CRTC - VDS
+ VREG $0E, $000C ; CRTC - VDE
+ VREG $0F, $0000 ; DCR
+
+.if HIRES
+
+ VREG $0A, $0C02 ; CRTC - HSR
+ VREG $0B, $043C ; CRTC - HDS
+ lda #$06
+ sta VCE_CTRL
+
+.else
+
+ VREG $0A, $0202 ; CRTC - HSR
+ VREG $0B, $041F ; CRTC - HDS
+ lda #$04
+ sta VCE_CTRL
+
+.endif
+
+ lda a:VDC_CTRL
+ rts
--- /dev/null
+
+; VGA charset for the PC-Engine conio implementation
+
+ .byte $00, $00, $00, $00, $00, $00, $00, $00
+
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %11111111
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %11111111
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %00011111
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %11110000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00011111
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %11110000
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %11111111
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %11111111
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+ .byte %00000000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00011111
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %11110000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+ .byte %00010000
+
+ .byte $3C, $66, $66, $66, $3C, $18, $7E, $18
+ .byte $3F, $33, $3F, $30, $30, $70, $F0, $E0
+ .byte $7F, $63, $7F, $63, $63, $67, $E6, $C0
+ .byte $99, $5A, $3C, $E7, $E7, $3C, $5A, $99
+ .byte $80, $E0, $F8, $FE, $F8, $E0, $80, $00
+ .byte $02, $0E, $3E, $FE, $3E, $0E, $02, $00
+ .byte $18, $3C, $7E, $18, $18, $7E, $3C, $18
+ .byte $66, $66, $66, $66, $66, $00, $66, $00
+ .byte $7F, $DB, $DB, $7B, $1B, $1B, $1B, $00
+ .byte $3E, $63, $38, $6C, $6C, $38, $CC, $78
+ .byte $00, $00, $00, $00, $7E, $7E, $7E, $00
+ .byte $18, $3C, $7E, $18, $7E, $3C, $18, $FF
+ .byte $18, $3C, $7E, $18, $18, $18, $18, $00
+ .byte $18, $18, $18, $18, $7E, $3C, $18, $00
+ .byte $00, $18, $0C, $FE, $0C, $18, $00, $00
+ .byte $00, $30, $60, $FE, $60, $30, $00, $00
+ .byte $00, $00, $C0, $C0, $C0, $FE, $00, $00
+ .byte $00, $24, $66, $FF, $66, $24, $00, $00
+ .byte $00, $18, $3C, $7E, $FF, $FF, $00, $00
+ .byte $00, $FF, $FF, $7E, $3C, $18, $00, $00
+ .byte $00, $00, $00, $00, $00, $00, $00, $00
+ .byte $30, $78, $78, $78, $30, $00, $30, $00
+ .byte $6C, $6C, $6C, $00, $00, $00, $00, $00
+ .byte $6C, $6C, $FE, $6C, $FE, $6C, $6C, $00
+ .byte $30, $7C, $C0, $78, $0C, $F8, $30, $00
+ .byte $00, $C6, $CC, $18, $30, $66, $C6, $00
+ .byte $38, $6C, $38, $76, $DC, $CC, $76, $00
+ .byte $60, $60, $C0, $00, $00, $00, $00, $00
+ .byte $18, $30, $60, $60, $60, $30, $18, $00
+ .byte $60, $30, $18, $18, $18, $30, $60, $00
+ .byte $00, $66, $3C, $FF, $3C, $66, $00, $00
+ .byte $00, $30, $30, $FC, $30, $30, $00, $00
+ .byte $00, $00, $00, $00, $00, $30, $30, $60
+ .byte $00, $00, $00, $FC, $00, $00, $00, $00
+ .byte $00, $00, $00, $00, $00, $30, $30, $00
+ .byte $06, $0C, $18, $30, $60, $C0, $80, $00
+ .byte $7C, $C6, $CE, $DE, $F6, $E6, $7C, $00
+ .byte $30, $70, $30, $30, $30, $30, $FC, $00
+ .byte $78, $CC, $0C, $38, $60, $CC, $FC, $00
+ .byte $78, $CC, $0C, $38, $0C, $CC, $78, $00
+ .byte $1C, $3C, $6C, $CC, $FE, $0C, $1E, $00
+ .byte $FC, $C0, $F8, $0C, $0C, $CC, $78, $00
+ .byte $38, $60, $C0, $F8, $CC, $CC, $78, $00
+ .byte $FC, $CC, $0C, $18, $30, $30, $30, $00
+ .byte $78, $CC, $CC, $78, $CC, $CC, $78, $00
+ .byte $78, $CC, $CC, $7C, $0C, $18, $70, $00
+ .byte $00, $30, $30, $00, $00, $30, $30, $00
+ .byte $00, $30, $30, $00, $00, $30, $30, $60
+ .byte $18, $30, $60, $C0, $60, $30, $18, $00
+ .byte $00, $00, $FC, $00, $00, $FC, $00, $00
+ .byte $60, $30, $18, $0C, $18, $30, $60, $00
+ .byte $78, $CC, $0C, $18, $30, $00, $30, $00
+ .byte $7C, $C6, $DE, $DE, $DE, $C0, $78, $00
+ .byte $30, $78, $CC, $CC, $FC, $CC, $CC, $00
+ .byte $FC, $66, $66, $7C, $66, $66, $FC, $00
+ .byte $3C, $66, $C0, $C0, $C0, $66, $3C, $00
+ .byte $F8, $6C, $66, $66, $66, $6C, $F8, $00
+ .byte $7E, $60, $60, $78, $60, $60, $7E, $00
+ .byte $7E, $60, $60, $78, $60, $60, $60, $00
+ .byte $3C, $66, $C0, $C0, $CE, $66, $3E, $00
+ .byte $CC, $CC, $CC, $FC, $CC, $CC, $CC, $00
+ .byte $78, $30, $30, $30, $30, $30, $78, $00
+ .byte $1E, $0C, $0C, $0C, $CC, $CC, $78, $00
+ .byte $E6, $66, $6C, $78, $6C, $66, $E6, $00
+ .byte $60, $60, $60, $60, $60, $60, $7E, $00
+ .byte $C6, $EE, $FE, $FE, $D6, $C6, $C6, $00
+ .byte $C6, $E6, $F6, $DE, $CE, $C6, $C6, $00
+ .byte $38, $6C, $C6, $C6, $C6, $6C, $38, $00
+ .byte $FC, $66, $66, $7C, $60, $60, $F0, $00
+ .byte $78, $CC, $CC, $CC, $DC, $78, $1C, $00
+ .byte $FC, $66, $66, $7C, $6C, $66, $E6, $00
+ .byte $78, $CC, $E0, $70, $1C, $CC, $78, $00
+ .byte $FC, $30, $30, $30, $30, $30, $30, $00
+ .byte $CC, $CC, $CC, $CC, $CC, $CC, $FC, $00
+ .byte $CC, $CC, $CC, $CC, $CC, $78, $30, $00
+ .byte $C6, $C6, $C6, $D6, $FE, $EE, $C6, $00
+ .byte $C6, $C6, $6C, $38, $38, $6C, $C6, $00
+ .byte $CC, $CC, $CC, $78, $30, $30, $78, $00
+ .byte $FE, $06, $0C, $18, $30, $60, $FE, $00
+ .byte $78, $60, $60, $60, $60, $60, $78, $00
+ .byte $C0, $60, $30, $18, $0C, $06, $02, $00
+ .byte $78, $18, $18, $18, $18, $18, $78, $00
+ .byte $10, $38, $6C, $C6, $00, $00, $00, $00
+ .byte $00, $00, $00, $00, $00, $00, $00, $FF
+ .byte $30, $30, $18, $00, $00, $00, $00, $00
+ .byte $00, $00, $78, $0C, $7C, $CC, $76, $00
+ .byte $E0, $60, $60, $7C, $66, $66, $DC, $00
+ .byte $00, $00, $78, $CC, $C0, $CC, $78, $00
+ .byte $1C, $0C, $0C, $7C, $CC, $CC, $76, $00
+ .byte $00, $00, $78, $CC, $FC, $C0, $78, $00
+ .byte $38, $6C, $60, $F0, $60, $60, $F0, $00
+ .byte $00, $00, $76, $CC, $CC, $7C, $0C, $F8
+ .byte $E0, $60, $6C, $76, $66, $66, $E6, $00
+ .byte $30, $00, $70, $30, $30, $30, $78, $00
+ .byte $0C, $00, $0C, $0C, $0C, $CC, $CC, $78
+ .byte $E0, $60, $66, $6C, $78, $6C, $E6, $00
+ .byte $70, $30, $30, $30, $30, $30, $78, $00
+ .byte $00, $00, $CC, $FE, $FE, $D6, $C6, $00
+ .byte $00, $00, $F8, $CC, $CC, $CC, $CC, $00
+ .byte $00, $00, $78, $CC, $CC, $CC, $78, $00
+ .byte $00, $00, $DC, $66, $66, $7C, $60, $F0
+ .byte $00, $00, $76, $CC, $CC, $7C, $0C, $1E
+ .byte $00, $00, $DC, $76, $66, $60, $F0, $00
+ .byte $00, $00, $7C, $C0, $78, $0C, $F8, $00
+ .byte $10, $30, $7C, $30, $30, $34, $18, $00
+ .byte $00, $00, $CC, $CC, $CC, $CC, $76, $00
+ .byte $00, $00, $CC, $CC, $CC, $78, $30, $00
+ .byte $00, $00, $C6, $D6, $FE, $FE, $6C, $00
+ .byte $00, $00, $C6, $6C, $38, $6C, $C6, $00
+ .byte $00, $00, $CC, $CC, $CC, $7C, $0C, $F8
+ .byte $00, $00, $FC, $98, $30, $64, $FC, $00
+ .byte $1C, $30, $30, $E0, $30, $30, $1C, $00
+ .byte $18, $18, $18, $00, $18, $18, $18, $00
+ .byte $E0, $30, $30, $1C, $30, $30, $E0, $00
+ .byte $76, $DC, $00, $00, $00, $00, $00, $00
+ .byte $00, $10, $38, $6C, $C6, $C6, $FE, $00
--- /dev/null
+;
+; void waitvblank (void);
+;
+
+ .include "pce.inc"
+ .include "extzp.inc"
+
+ .forceimport ticktock
+ .export _waitvblank
+
+.proc _waitvblank
+
+ lda tickcount
+@lp: cmp tickcount
+ beq @lp
+ rts
+
+.endproc
; ------------------------------------------------------------------------
-.segment "ZPSAVE"
+.segment "INITBSS"
zpsave: .res zpspace
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
;---------------------------------------------------------------------------
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNLEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (FNADR),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
.endproc
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
.include "pet.inc"
__randomize:
- ldx TIME
+ ldx TIME+2
lda TIME+1 ; Use 60HZ clock
jmp _srand ; Initialize generator
irqcount: .byte 0
-.segment "ZPSAVE"
+.segment "INITBSS"
zpsave: .res zpspace
.import __argc, __argv
.include "plus4.inc"
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNAM_LEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (FNAM),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
sta __argv
stx __argv + 1
rts
-
-; --------------------------------------------------------------------------
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
-
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
__randomize:
ldx TED_VLINELO ; Use TED rasterline as high byte
- lda TIME ; Use 60HZ clock as low byte
+ lda TIME+2 ; Use 60HZ clock as low byte
jmp _srand ; Initialize generator
;---------------------------------------------------------------------------
; Data
-.bss
-__argc: .res 2
-__argv: .res 2
+.data
+__argc: .word 0
+__argv: .addr 0
; ----------------------------------------------------------------------------
; Data
-.bss
+.segment "INITBSS"
; Initial stack pointer value. Stack is reset to this in case of overflows to
; allow program exit processing.
-initialsp: .word 0
+initialsp: .res 2
; Stack low water mark.
-lowwater: .word 0
+lowwater: .res 2
+++ /dev/null
-;
-; Oliver Schmidt, 2013-05-16
-;
-; extern int errno;
-;
-
- .include "errno.inc"
-
- .bss
-
-__errno:
- .word 0
; ------------------------------------------------------------------------
-.segment "ZPSAVE"
+.segment "INITBSS"
zpsave: .res zpspace
.include "vic20.inc"
-
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
-NAME_LEN = 16 ; maximum length of command-name
+NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special INIT segment,
; which may be reused after the startup code is run
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
-; Because the buffer, that we're copying into, was zeroed out,
-; we don't need to add a NUL character.
-;
+
+ lda #0 ; The terminating NUL character
ldy FNAM_LEN
cpy #NAME_LEN + 1
bcc L1
- ldy #NAME_LEN - 1 ; limit the length
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
L0: lda (FNAM),y
- sta name,y
-L1: dey
+L1: sta name,y
+ dey
bpl L0
inc __argc ; argc always is equal to, at least, 1
; Find the "rem" token.
-;
+
ldx #0
L2: lda BASIC_BUF,x
- beq done ; no "rem," no args.
+ beq done ; No "rem," no args.
inx
cmp #REM
bne L2
beq done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
- beq next ;
+ beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. This is useful since we
stx __argv + 1
rts
-; These arrays are zeroed before initmainargs is called.
-; char name[16+1];
-; char* argv[MAXARGS+1]={name};
-;
-.bss
+.segment "INITBSS"
+
term: .res 1
name: .res NAME_LEN + 1
.data
+
+; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
-
;
-; Ullrich von Bassewitz, 05.11.2002
+; 2002-11-05, Ullrich von Bassewitz
+; 2015-09-11, Greg King
;
; void _randomize (void);
; /* Initialize the random number generator */
lda VIC_HLINE ; Get bit 1-8 of rasterline
rol a ; Use bit 0-7
tax ; Use VIC rasterline as high byte
- lda TIME ; Use 60HZ clock as low byte
+ lda TIME+2 ; Use 60HZ clock as low byte
jmp _srand ; Initialize generator
#include <zlib.h>
-int uncompress (char* dest, unsigned* destLen,
- const char* source, unsigned sourceLen)
+int __fastcall__ uncompress (char* dest, unsigned* destLen,
+ const char* source, unsigned sourceLen)
{
unsigned len;
unsigned char* ptr;
C1541 = c1541
# --------------------------------------------------------------------------
-# System dependent settings
+# System-dependent settings
# The Apple machines need the start address adjusted when using TGI
LDFLAGS_mandelbrot_apple2 = --start-addr 0x4000
.PRECIOUS: %.o
.o:
- @$(LD) $(LDFLAGS_$(basename $@)_$(SYS)) -o $@ -t $(SYS) -m $@.map $^ $(CLIB)
+ @$(LD) $(LDFLAGS_$(@F)_$(SYS)) -o $@ -t $(SYS) -m $@.map $^ $(CLIB)
# --------------------------------------------------------------------------
-# List of executables. This list could be made target dependent by checking
+# List of executables. This list could be made target-dependent by checking
# $(SYS).
EXELIST = ascii \
tgidemo
# --------------------------------------------------------------------------
-# Rules how to make each one of the binaries
+# Rules to make the binaries
.PHONY: all
all: $(EXELIST)
# --------------------------------------------------------------------------
-# Rule to make a disk with all samples. Needs the c1541 program that comes
+# Overlay rules. Overlays need special ld65 configuration files. Also, the
+# overlay file-names are shortenned to fit the Atari's 8.3-character limit.
+
+multdemo: multidemo.o
+ @$(LD) -o $@ -C $(SYS)-overlay.cfg -m $@.map $^ $(CLIB)
+
+ovrldemo: overlaydemo.o
+ @$(LD) -o $@ -C $(SYS)-overlay.cfg -m $@.map $^ $(CLIB)
+
+# --------------------------------------------------------------------------
+# Rule to make a CBM disk with all samples. Needs the c1541 program that comes
# with the VICE emulator.
.PHONY: disk
done
# --------------------------------------------------------------------------
-# Cleanup rules
+# Clean-up rules
.PHONY: clean
clean:
.PHONY: zap
zap: clean
$(RM) $(EXELIST) samples.d64
+ $(RM) multdemo.? ovrldemo.?
the programs manually.
* The makefile specifies the C64 as the default target platform, because all
+ but one
of the programs run on this platform. When compiling for another platform,
you will have to change the line that specifies the target system at the
top of the makefile.
#include <stdlib.h>
#include <string.h>
#include <conio.h>
-#include <dbg.h>
+#include <joystick.h>
gotoxy ((XSize - strlen (Text)) / 2, YSize / 2);
cprintf ("%s", Text);
+#if defined(__NES__) || defined(__PCE__)
+
+ /* Wait for the user to press a button */
+ joy_install (joy_static_stddrv);
+ while (!joy_read (JOY_1)) ;
+ joy_uninstall ();
+
+#else
+
/* Wait for the user to press a key */
(void) cgetc ();
+#endif
+
/* Clear the screen again */
clrscr ();
/* Done */
return EXIT_SUCCESS;
}
-
-
-
-#if defined(__C64__) || defined(__C128__) || defined(__CBM510__)
+#ifdef __CBM__
-/* Addresses of data for sprite 0 */
-#if defined(__C64__)
-# define SPRITE0_DATA ((unsigned char[64])0x0340)
-# define SPRITE0_PTR ((unsigned char *)0x07F8)
-#elif defined(__C128__)
-# define SPRITE0_DATA ((unsigned char[64])0x0E00)
-# define SPRITE0_PTR ((unsigned char *)0x07F8)
-#elif defined(__CBM510__)
-# define SPRITE0_DATA ((unsigned char[64])0xF400)
-# define SPRITE0_PTR ((unsigned char *)0xF3F8)
-#endif
+/* Set dark-on-light colors. */
+const unsigned char mouse_def_pointercolor = COLOR_BLACK;
-/* The mouse sprite (an arrow) */
-static const unsigned char MouseSprite[64] = {
- 0xFE, 0x00, 0x00,
- 0xFC, 0x00, 0x00,
- 0xF8, 0x00, 0x00,
- 0xFC, 0x00, 0x00,
- 0xDE, 0x00, 0x00,
- 0x8F, 0x00, 0x00,
- 0x07, 0x80, 0x00,
- 0x03, 0xC0, 0x00,
- 0x01, 0xE0, 0x00,
- 0x00, 0xF0, 0x00,
- 0x00, 0x78, 0x00,
- 0x00, 0x38, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00
-};
#endif
cursor (0);
clrscr ();
- /* The pointer should be created before the driver is installed,
- ** in case a lightpen driver needs it during calibration.
- */
-
-#if defined(__C64__) || defined(__C128__) || defined(__CBM510__)
- /* Copy the sprite data */
- memcpy ((void*) SPRITE0_DATA, MouseSprite, sizeof (MouseSprite));
-
- /* Set the VIC-II sprite pointer. */
- *SPRITE0_PTR = ((unsigned) SPRITE0_DATA & 0x3FFF) / sizeof SPRITE0_DATA;
-
- /* Set the color of sprite 0 */
-# ifdef __CBM510__
- pokebsys ((unsigned) &VIC.spr0_color, COLOR_BLACK);
-# else
- VIC.spr0_color = COLOR_BLACK;
-# endif
-#endif
-
/* If a lightpen driver is installed, then it can get a calibration value
** from this file (if it exists). Or, the user can adjust the pen; and,
** the value will be put into this file, for the next time.
J = 0;
}
}
- if (kbhit() && ReadUpperKey == 'Q') {
+ if (kbhit() && ReadUpperKey () == 'Q') {
break;
}
}
while (1) {
if (strcmp (L->Name, Name) == 0) {
/* Duplicate entry */
- Warning ("External symbol `%s' in module `%s', library `%s' "
+ Warning ("External symbol `%s' in module `%s', library `%s', "
"is duplicated in module `%s'",
- Name, L->Name, LibName, Module->Name);
+ Name, L->Module->Name, LibName, Module->Name);
}
if (L->Next == 0) {
break;
#include "symtab.h"
#include "toklist.h"
#include "ulabel.h"
+#include "macro.h"
+static ExprNode* FuncDefinedMacro (void)
+/* Handle the .DEFINEDMACRO builtin function */
+{
+ Macro* Mac = 0;
+
+ /* Check if the identifier is a macro */
+
+ if (CurTok.Tok == TOK_IDENT) {
+ Mac = FindMacro (&CurTok.SVal);
+ } else {
+ Error ("Identifier expected.");
+ }
+ /* Skip the name */
+ NextTok ();
+
+ return GenLiteralExpr (Mac != 0);
+}
+
+
+
ExprNode* FuncHiByte (void)
/* Handle the .HIBYTE builtin function */
{
+static ExprNode* FuncIsMnemonic (void)
+/* Handle the .ISMNEMONIC, .ISMNEM builtin function */
+{
+ int Instr = -1;
+
+ /* Check for a macro or an instruction depending on UbiquitousIdents */
+
+ if (CurTok.Tok == TOK_IDENT) {
+ if (UbiquitousIdents) {
+ /* Macros CAN be instructions, so check for them first */
+ if (FindMacro (&CurTok.SVal) == 0) {
+ Instr = FindInstruction (&CurTok.SVal);
+ }
+ }
+ else {
+ /* Macros and symbols may NOT use the names of instructions, so just check for the instruction */
+ Instr = FindInstruction (&CurTok.SVal);
+ }
+ }
+ else {
+ Error ("Identifier expected.");
+ }
+ /* Skip the name */
+ NextTok ();
+
+ return GenLiteralExpr (Instr > 0);
+}
+
+
+
ExprNode* FuncLoByte (void)
/* Handle the .LOBYTE builtin function */
{
+static ExprNode* FuncAddrSize (void)
+/* Handle the .ADDRSIZE function */
+{
+ StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
+ SymEntry* Sym;
+ int AddrSize;
+ int NoScope;
+
+
+ /* Assume we don't know the size */
+ AddrSize = 0;
+
+ /* Check for a cheap local which needs special handling */
+ if (CurTok.Tok == TOK_LOCAL_IDENT) {
+
+ /* Cheap local symbol */
+ Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
+ if (Sym == 0) {
+ Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
+ } else {
+ AddrSize = Sym->AddrSize;
+ }
+
+ /* Remember and skip SVal, terminate ScopeName so it is empty */
+ SB_Copy (&Name, &CurTok.SVal);
+ NextTok ();
+ SB_Terminate (&ScopeName);
+
+ } else {
+
+ /* Parse the scope and the name */
+ SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
+
+ /* Check if the parent scope is valid */
+ if (ParentScope == 0) {
+ /* No such scope */
+ SB_Done (&ScopeName);
+ SB_Done (&Name);
+ return GenLiteral0 ();
+ }
+
+ /* If ScopeName is empty, no explicit scope was specified. We have to
+ ** search upper scope levels in this case.
+ */
+ NoScope = SB_IsEmpty (&ScopeName);
+
+ /* If we did find a scope with the name, read the symbol defining the
+ ** size, otherwise search for a symbol entry with the name and scope.
+ */
+ if (NoScope) {
+ Sym = SymFindAny (ParentScope, &Name);
+ } else {
+ Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
+ }
+ /* If we found the symbol retrieve the size, otherwise complain */
+ if (Sym) {
+ AddrSize = Sym->AddrSize;
+ } else {
+ Error ("Unknown symbol or scope: `%m%p%m%p'", &ScopeName, &Name);
+ }
+
+ }
+
+ if (AddrSize == 0) {
+ Warning (1, "Unknown address size: `%m%p%m%p'", &ScopeName, &Name);
+ }
+
+ /* Free the string buffers */
+ SB_Done (&ScopeName);
+ SB_Done (&Name);
+
+ /* Return the size. */
+
+ return GenLiteralExpr (AddrSize);
+}
+
+
+
static ExprNode* FuncSizeOf (void)
/* Handle the .SIZEOF function */
{
N = Function (FuncBankByte);
break;
+ case TOK_ADDRSIZE:
+ N = Function (FuncAddrSize);
+ break;
+
+ case TOK_ASIZE:
+ if (GetCPU () != CPU_65816) {
+ N = GenLiteralExpr (8);
+ } else {
+ N = GenLiteralExpr (ExtBytes[AM65I_IMM_ACCU] * 8);
+ }
+ NextTok ();
+ break;
+
case TOK_BLANK:
N = Function (FuncBlank);
break;
N = Function (FuncDefined);
break;
+ case TOK_DEFINEDMACRO:
+ N = Function (FuncDefinedMacro);
+ break;
+
case TOK_HIBYTE:
N = Function (FuncHiByte);
break;
N = Function (FuncHiWord);
break;
+ case TOK_ISMNEMONIC:
+ N = Function (FuncIsMnemonic);
+ break;
+
+ case TOK_ISIZE:
+ if (GetCPU () != CPU_65816) {
+ N = GenLiteralExpr (8);
+ } else {
+ N = GenLiteralExpr (ExtBytes[AM65I_IMM_INDEX] * 8);
+ }
+ NextTok ();
+ break;
+
case TOK_LOBYTE:
N = Function (FuncLoByte);
break;
"c_comments",
"force_range",
"underline_in_numbers",
+ "addrsize",
};
case FEAT_C_COMMENTS: CComments = 1; break;
case FEAT_FORCE_RANGE: ForceRange = 1; break;
case FEAT_UNDERLINE_IN_NUMBERS: UnderlineInNumbers= 1; break;
+ case FEAT_ADDRSIZE: AddrSize = 1; break;
default: /* Keep gcc silent */ break;
}
FEAT_C_COMMENTS,
FEAT_FORCE_RANGE,
FEAT_UNDERLINE_IN_NUMBERS,
+ FEAT_ADDRSIZE,
/* Special value: Number of features available */
FEAT_COUNT
+static void WriteEscaped (FILE* F, const char* Name)
+/* Write a file name to a dependency file escaping spaces */
+{
+ while (*Name) {
+ if (*Name == ' ') {
+ /* Escape spaces */
+ fputc ('\\', F);
+ }
+ fputc (*Name, F);
+ ++Name;
+ }
+}
+
+
+
static void WriteDep (FILE* F, FileType Types)
/* Helper function. Writes all file names that match Types to the output */
{
fputc (' ', F);
}
- /* Print the dependency */
+ /* Print the dependency escaping spaces */
Filename = GetStrBuf (E->Name);
- fprintf (F, "%*s", SB_GetLen (Filename), SB_GetConstBuf (Filename));
+ WriteEscaped (F, SB_GetConstBuf (Filename));
}
}
}
/* Print the output file followed by a tab char */
- fprintf (F, "%s:\t", OutFile);
+ WriteEscaped (F, OutFile);
+ fputs (":\t", F);
/* Write out the dependencies for the output file */
WriteDep (F, Types);
unsigned char CComments = 0; /* Allow C like comments */
unsigned char ForceRange = 0; /* Force values into expected range */
unsigned char UnderlineInNumbers = 0; /* Allow underlines in numbers */
+unsigned char AddrSize = 0; /* Allow .ADDRSIZE function */
+
extern unsigned char CComments; /* Allow C like comments */
extern unsigned char ForceRange; /* Force values into expected range */
extern unsigned char UnderlineInNumbers; /* Allow underlines in numbers */
+extern unsigned char AddrSize; /* Allow .ADDRSIZE function */
+
{ "ROR", 0x000006F, 0x62, 1, PutAll },
{ "RTI", 0x0000001, 0x40, 0, PutAll },
{ "RTS", 0x0000001, 0x60, 0, PutAll },
- { "SBC", 0x080A66C, 0xe0, 0, PutAll },
{ "SAX", 0x0000001, 0x22, 0, PutAll },
{ "SAY", 0x0000001, 0x42, 0, PutAll },
+ { "SBC", 0x080A66C, 0xe0, 0, PutAll },
{ "SEC", 0x0000001, 0x38, 0, PutAll },
{ "SED", 0x0000001, 0xf8, 0, PutAll },
{ "SEI", 0x0000001, 0x78, 0, PutAll },
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
-/* Define style macros disabled if != 0 */
+/* Define-style macros disabled if != 0 */
static unsigned DisableDefines = 0;
EnterRawTokenMode ();
NextTok ();
- /* If we have a DEFINE style macro, we may have parameters in braces,
- ** otherwise we may have parameters without braces.
+ /* If we have a DEFINE-style macro, we may have parameters in parentheses;
+ ** otherwise, we may have parameters without parentheses.
*/
if (Style == MAC_STYLE_CLASSIC) {
HaveParams = 1;
}
}
- /* For class macros, we expect a separator token, for define style macros,
+ /* For classic macros, we expect a separator token, for define-style macros,
** we expect the closing paren.
*/
if (Style == MAC_STYLE_CLASSIC) {
}
/* Preparse the macro body. We will read the tokens until we reach end of
- ** file, or a .endmacro (or end of line for DEFINE style macros) and store
- ** them into an token list internal to the macro. For classic macros, there
- ** the .LOCAL command is detected and removed at this time.
+ ** file, or a .endmacro (or end of line for DEFINE-style macros) and store
+ ** them into a token list internal to the macro. For classic macros,
+ ** the .LOCAL command is detected and removed, at this time.
*/
while (1) {
FreeTokNode (Mac->Final);
Mac->Final = 0;
- /* Problem: When a .define style macro is expanded within the call
+ /* Problem: When a .define-style macro is expanded within the call
** of a classic one, the latter may be terminated and removed while
- ** the expansion of the .define style macro is still active. Because
+ ** the expansion of the .define-style macro is still active. Because
** line info slots are "stacked", this runs into a CHECK FAILED. For
- ** now, we will fix that by removing the .define style macro expansion
+ ** now, we will fix that by removing the .define-style macro expansion
** immediately, once the final token is placed. The better solution
** would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
** to be called in FIFO order, but this is a bigger change.
static void StartExpClassic (MacExp* E)
/* Start expanding a classic macro */
{
- token_t Term;
+ token_t Term;
/* Skip the macro name */
NextTok ();
- /* Read the actual parameters */
- while (!TokIsSep (CurTok.Tok)) {
+ /* Does this invocation have any arguments? */
+ if (!TokIsSep (CurTok.Tok)) {
- TokNode* Last;
+ /* Read the actual parameters */
+ while (1) {
+ TokNode* Last;
- /* Check for maximum parameter count */
- if (E->ParamCount >= E->M->ParamCount) {
- ErrorSkip ("Too many macro parameters");
- break;
- }
+ /* Check for maximum parameter count */
+ if (E->ParamCount >= E->M->ParamCount) {
+ ErrorSkip ("Too many macro parameters");
+ break;
+ }
- /* The macro may optionally be enclosed in curly braces */
- Term = GetTokListTerm (TOK_COMMA);
+ /* The macro argument optionally may be enclosed in curly braces */
+ Term = GetTokListTerm (TOK_COMMA);
- /* Read tokens for one parameter, accept empty params */
- Last = 0;
- while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
+ /* Read tokens for one parameter, accept empty params */
+ Last = 0;
+ while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
+ TokNode* T;
- TokNode* T;
+ /* Check for end of file */
+ if (CurTok.Tok == TOK_EOF) {
+ Error ("Unexpected end of file");
+ FreeMacExp (E);
+ return;
+ }
- /* Check for end of file */
- if (CurTok.Tok == TOK_EOF) {
- Error ("Unexpected end of file");
- FreeMacExp (E);
- return;
- }
+ /* Get the next token in a node */
+ T = NewTokNode ();
- /* Get the next token in a node */
- T = NewTokNode ();
+ /* Insert it into the list */
+ if (Last == 0) {
+ E->Params [E->ParamCount] = T;
+ } else {
+ Last->Next = T;
+ }
+ Last = T;
- /* Insert it into the list */
- if (Last == 0) {
- E->Params [E->ParamCount] = T;
- } else {
- Last->Next = T;
+ /* And skip it... */
+ NextTok ();
}
- Last = T;
- /* And skip it... */
- NextTok ();
- }
+ /* One parameter more */
+ ++E->ParamCount;
- /* One parameter more */
- ++E->ParamCount;
+ /* If the macro argument was enclosed in curly braces, end-of-line
+ ** is an error. Skip the closing curly brace.
+ */
+ if (Term == TOK_RCURLY) {
+ if (CurTok.Tok == TOK_SEP) {
+ Error ("End of line encountered within macro argument");
+ break;
+ }
+ NextTok ();
+ }
- /* If the macro argument was enclosed in curly braces, end-of-line
- ** is an error. Skip the closing curly brace.
- */
- if (Term == TOK_RCURLY) {
- if (CurTok.Tok == TOK_SEP) {
- Error ("End of line encountered within macro argument");
+ /* Check for a comma */
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
break;
}
- NextTok ();
- }
-
- /* Check for a comma */
- if (CurTok.Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
}
}
static void StartExpDefine (MacExp* E)
-/* Start expanding a DEFINE style macro */
+/* Start expanding a DEFINE-style macro */
{
- /* A define style macro must be called with as many actual parameters
+ /* A define-style macro must be called with as many actual parameters
** as there are formal ones. Get the parameter count.
*/
unsigned Count = E->M->ParamCount;
/* Read the actual parameters */
while (Count--) {
+ TokNode* Last;
- TokNode* Last;
-
- /* The macro may optionally be enclosed in curly braces */
+ /* The macro argument optionally may be enclosed in curly braces */
token_t Term = GetTokListTerm (TOK_COMMA);
/* Check if there is really a parameter */
/* Read tokens for one parameter */
Last = 0;
do {
-
TokNode* T;
/* Get the next token in a node */
}
/* Macro expansion will overwrite the current token. This is a problem
- ** for define style macros since these are called from the scanner level.
+ ** for define-style macros since these are called from the scanner level.
** To avoid it, remember the current token and re-insert it, once macro
** expansion is done.
*/
Macro* FindDefine (const StrBuf* Name)
-/* Try to find the define style macro with the given name and return it. If no
-** such macro was found, return NULL.
+/* Try to find the define-style macro with the given name; and, return it.
+** If no such macro was found, return NULL.
*/
{
Macro* M;
void DisableDefineStyleMacros (void)
-/* Disable define style macros until EnableDefineStyleMacros is called */
+/* Disable define-style macros until EnableDefineStyleMacros() is called */
{
++DisableDefines;
}
void EnableDefineStyleMacros (void)
-/* Re-enable define style macros previously disabled with
-** DisableDefineStyleMacros.
+/* Re-enable define-style macros previously disabled with
+** DisableDefineStyleMacros().
*/
{
PRECONDITION (DisableDefines > 0);
NewSymbol ("__SIM65C02__", 1);
break;
+ case TGT_OSIC1P:
+ NewSymbol ("__OSIC1P__", 1);
+ break;
+
+ case TGT_PCENGINE:
+ NewSymbol ("__PCE__", 1);
+ break;
+
default:
AbEnd ("Invalid target name: `%s'", Sys);
{ ccNone, DoA16 },
{ ccNone, DoA8 },
{ ccNone, DoAddr }, /* .ADDR */
+ { ccNone, DoUnexpected }, /* .ADDRSIZE */
{ ccNone, DoAlign },
{ ccNone, DoASCIIZ },
+ { ccNone, DoUnexpected }, /* .ASIZE */
{ ccNone, DoAssert },
{ ccNone, DoAutoImport },
{ ccNone, DoUnexpected }, /* .BANK */
{ ccNone, DoDebugInfo },
{ ccNone, DoDefine },
{ ccNone, DoUnexpected }, /* .DEFINED */
+ { ccNone, DoUnexpected }, /* .DEFINEDMACRO */
{ ccNone, DoDelMac },
{ ccNone, DoDestructor },
{ ccNone, DoDWord },
{ ccNone, DoIncBin },
{ ccNone, DoInclude },
{ ccNone, DoInterruptor },
+ { ccNone, DoUnexpected }, /* .ISIZE */
+ { ccNone, DoUnexpected }, /* .ISMNEMONIC */
{ ccNone, DoInvalid }, /* .LEFT */
{ ccNone, DoLineCont },
{ ccNone, DoList },
const char* Key; /* MUST be first field */
token_t Tok;
} DotKeywords [] = {
- { ".A16", TOK_A16 },
- { ".A8", TOK_A8 },
- { ".ADDR", TOK_ADDR },
- { ".ALIGN", TOK_ALIGN },
- { ".AND", TOK_BOOLAND },
- { ".ASCIIZ", TOK_ASCIIZ },
- { ".ASSERT", TOK_ASSERT },
- { ".AUTOIMPORT", TOK_AUTOIMPORT },
- { ".BANK", TOK_BANK },
- { ".BANKBYTE", TOK_BANKBYTE },
- { ".BANKBYTES", TOK_BANKBYTES },
- { ".BITAND", TOK_AND },
- { ".BITNOT", TOK_NOT },
- { ".BITOR", TOK_OR },
- { ".BITXOR", TOK_XOR },
- { ".BLANK", TOK_BLANK },
- { ".BSS", TOK_BSS },
- { ".BYT", TOK_BYTE },
- { ".BYTE", TOK_BYTE },
- { ".CASE", TOK_CASE },
- { ".CHARMAP", TOK_CHARMAP },
- { ".CODE", TOK_CODE },
- { ".CONCAT", TOK_CONCAT },
- { ".CONDES", TOK_CONDES },
- { ".CONST", TOK_CONST },
- { ".CONSTRUCTOR", TOK_CONSTRUCTOR },
- { ".CPU", TOK_CPU },
- { ".DATA", TOK_DATA },
- { ".DBG", TOK_DBG },
- { ".DBYT", TOK_DBYT },
- { ".DEBUGINFO", TOK_DEBUGINFO },
- { ".DEF", TOK_DEFINED },
- { ".DEFINE", TOK_DEFINE },
- { ".DEFINED", TOK_DEFINED },
- { ".DELMAC", TOK_DELMAC },
- { ".DELMACRO", TOK_DELMAC },
- { ".DESTRUCTOR", TOK_DESTRUCTOR },
- { ".DWORD", TOK_DWORD },
- { ".ELSE", TOK_ELSE },
- { ".ELSEIF", TOK_ELSEIF },
- { ".END", TOK_END },
- { ".ENDENUM", TOK_ENDENUM },
- { ".ENDIF", TOK_ENDIF },
- { ".ENDMAC", TOK_ENDMACRO },
- { ".ENDMACRO", TOK_ENDMACRO },
- { ".ENDPROC", TOK_ENDPROC },
- { ".ENDREP", TOK_ENDREP },
- { ".ENDREPEAT", TOK_ENDREP },
- { ".ENDSCOPE", TOK_ENDSCOPE },
- { ".ENDSTRUCT", TOK_ENDSTRUCT },
- { ".ENDUNION", TOK_ENDUNION },
- { ".ENUM", TOK_ENUM },
- { ".ERROR", TOK_ERROR },
- { ".EXITMAC", TOK_EXITMACRO },
- { ".EXITMACRO", TOK_EXITMACRO },
- { ".EXPORT", TOK_EXPORT },
- { ".EXPORTZP", TOK_EXPORTZP },
- { ".FARADDR", TOK_FARADDR },
- { ".FATAL", TOK_FATAL },
- { ".FEATURE", TOK_FEATURE },
- { ".FILEOPT", TOK_FILEOPT },
- { ".FOPT", TOK_FILEOPT },
- { ".FORCEIMPORT", TOK_FORCEIMPORT },
- { ".FORCEWORD", TOK_FORCEWORD },
- { ".GLOBAL", TOK_GLOBAL },
- { ".GLOBALZP", TOK_GLOBALZP },
- { ".HIBYTE", TOK_HIBYTE },
- { ".HIBYTES", TOK_HIBYTES },
- { ".HIWORD", TOK_HIWORD },
- { ".I16", TOK_I16 },
- { ".I8", TOK_I8 },
- { ".IDENT", TOK_MAKEIDENT },
- { ".IF", TOK_IF },
- { ".IFBLANK", TOK_IFBLANK },
- { ".IFCONST", TOK_IFCONST },
- { ".IFDEF", TOK_IFDEF },
- { ".IFNBLANK", TOK_IFNBLANK },
- { ".IFNCONST", TOK_IFNCONST },
- { ".IFNDEF", TOK_IFNDEF },
- { ".IFNREF", TOK_IFNREF },
- { ".IFP02", TOK_IFP02 },
- { ".IFP816", TOK_IFP816 },
- { ".IFPC02", TOK_IFPC02 },
- { ".IFPSC02", TOK_IFPSC02 },
- { ".IFREF", TOK_IFREF },
- { ".IMPORT", TOK_IMPORT },
- { ".IMPORTZP", TOK_IMPORTZP },
- { ".INCBIN", TOK_INCBIN },
- { ".INCLUDE", TOK_INCLUDE },
- { ".INTERRUPTOR", TOK_INTERRUPTOR },
- { ".LEFT", TOK_LEFT },
- { ".LINECONT", TOK_LINECONT },
- { ".LIST", TOK_LIST },
- { ".LISTBYTES", TOK_LISTBYTES },
- { ".LOBYTE", TOK_LOBYTE },
- { ".LOBYTES", TOK_LOBYTES },
- { ".LOCAL", TOK_LOCAL },
- { ".LOCALCHAR", TOK_LOCALCHAR },
- { ".LOWORD", TOK_LOWORD },
- { ".MAC", TOK_MACRO },
- { ".MACPACK", TOK_MACPACK },
- { ".MACRO", TOK_MACRO },
- { ".MATCH", TOK_MATCH },
- { ".MAX", TOK_MAX },
- { ".MID", TOK_MID },
- { ".MIN", TOK_MIN },
- { ".MOD", TOK_MOD },
- { ".NOT", TOK_BOOLNOT },
- { ".NULL", TOK_NULL },
- { ".OR", TOK_BOOLOR },
- { ".ORG", TOK_ORG },
- { ".OUT", TOK_OUT },
- { ".P02", TOK_P02 },
- { ".P816", TOK_P816 },
- { ".PAGELEN", TOK_PAGELENGTH },
- { ".PAGELENGTH", TOK_PAGELENGTH },
- { ".PARAMCOUNT", TOK_PARAMCOUNT },
- { ".PC02", TOK_PC02 },
- { ".POPCPU", TOK_POPCPU },
- { ".POPSEG", TOK_POPSEG },
- { ".PROC", TOK_PROC },
- { ".PSC02", TOK_PSC02 },
- { ".PUSHCPU", TOK_PUSHCPU },
- { ".PUSHSEG", TOK_PUSHSEG },
- { ".REF", TOK_REFERENCED },
- { ".REFERENCED", TOK_REFERENCED },
- { ".RELOC", TOK_RELOC },
- { ".REPEAT", TOK_REPEAT },
- { ".RES", TOK_RES },
- { ".RIGHT", TOK_RIGHT },
- { ".RODATA", TOK_RODATA },
- { ".SCOPE", TOK_SCOPE },
- { ".SEGMENT", TOK_SEGMENT },
- { ".SET", TOK_SET },
- { ".SETCPU", TOK_SETCPU },
- { ".SHL", TOK_SHL },
- { ".SHR", TOK_SHR },
- { ".SIZEOF", TOK_SIZEOF },
- { ".SMART", TOK_SMART },
- { ".SPRINTF", TOK_SPRINTF },
- { ".STRAT", TOK_STRAT },
- { ".STRING", TOK_STRING },
- { ".STRLEN", TOK_STRLEN },
- { ".STRUCT", TOK_STRUCT },
- { ".TAG", TOK_TAG },
- { ".TCOUNT", TOK_TCOUNT },
- { ".TIME", TOK_TIME },
- { ".UNDEF", TOK_UNDEF },
- { ".UNDEFINE", TOK_UNDEF },
- { ".UNION", TOK_UNION },
- { ".VERSION", TOK_VERSION },
- { ".WARNING", TOK_WARNING },
- { ".WORD", TOK_WORD },
- { ".XMATCH", TOK_XMATCH },
- { ".XOR", TOK_BOOLXOR },
- { ".ZEROPAGE", TOK_ZEROPAGE },
+ { ".A16", TOK_A16 },
+ { ".A8", TOK_A8 },
+ { ".ADDR", TOK_ADDR },
+ { ".ADDRSIZE", TOK_ADDRSIZE },
+ { ".ALIGN", TOK_ALIGN },
+ { ".AND", TOK_BOOLAND },
+ { ".ASCIIZ", TOK_ASCIIZ },
+ { ".ASIZE", TOK_ASIZE },
+ { ".ASSERT", TOK_ASSERT },
+ { ".AUTOIMPORT", TOK_AUTOIMPORT },
+ { ".BANK", TOK_BANK },
+ { ".BANKBYTE", TOK_BANKBYTE },
+ { ".BANKBYTES", TOK_BANKBYTES },
+ { ".BITAND", TOK_AND },
+ { ".BITNOT", TOK_NOT },
+ { ".BITOR", TOK_OR },
+ { ".BITXOR", TOK_XOR },
+ { ".BLANK", TOK_BLANK },
+ { ".BSS", TOK_BSS },
+ { ".BYT", TOK_BYTE },
+ { ".BYTE", TOK_BYTE },
+ { ".CASE", TOK_CASE },
+ { ".CHARMAP", TOK_CHARMAP },
+ { ".CODE", TOK_CODE },
+ { ".CONCAT", TOK_CONCAT },
+ { ".CONDES", TOK_CONDES },
+ { ".CONST", TOK_CONST },
+ { ".CONSTRUCTOR", TOK_CONSTRUCTOR },
+ { ".CPU", TOK_CPU },
+ { ".DATA", TOK_DATA },
+ { ".DBG", TOK_DBG },
+ { ".DBYT", TOK_DBYT },
+ { ".DEBUGINFO", TOK_DEBUGINFO },
+ { ".DEF", TOK_DEFINED },
+ { ".DEFINE", TOK_DEFINE },
+ { ".DEFINED", TOK_DEFINED },
+ { ".DEFINEDMACRO", TOK_DEFINEDMACRO },
+ { ".DELMAC", TOK_DELMAC },
+ { ".DELMACRO", TOK_DELMAC },
+ { ".DESTRUCTOR", TOK_DESTRUCTOR },
+ { ".DWORD", TOK_DWORD },
+ { ".ELSE", TOK_ELSE },
+ { ".ELSEIF", TOK_ELSEIF },
+ { ".END", TOK_END },
+ { ".ENDENUM", TOK_ENDENUM },
+ { ".ENDIF", TOK_ENDIF },
+ { ".ENDMAC", TOK_ENDMACRO },
+ { ".ENDMACRO", TOK_ENDMACRO },
+ { ".ENDPROC", TOK_ENDPROC },
+ { ".ENDREP", TOK_ENDREP },
+ { ".ENDREPEAT", TOK_ENDREP },
+ { ".ENDSCOPE", TOK_ENDSCOPE },
+ { ".ENDSTRUCT", TOK_ENDSTRUCT },
+ { ".ENDUNION", TOK_ENDUNION },
+ { ".ENUM", TOK_ENUM },
+ { ".ERROR", TOK_ERROR },
+ { ".EXITMAC", TOK_EXITMACRO },
+ { ".EXITMACRO", TOK_EXITMACRO },
+ { ".EXPORT", TOK_EXPORT },
+ { ".EXPORTZP", TOK_EXPORTZP },
+ { ".FARADDR", TOK_FARADDR },
+ { ".FATAL", TOK_FATAL },
+ { ".FEATURE", TOK_FEATURE },
+ { ".FILEOPT", TOK_FILEOPT },
+ { ".FOPT", TOK_FILEOPT },
+ { ".FORCEIMPORT", TOK_FORCEIMPORT },
+ { ".FORCEWORD", TOK_FORCEWORD },
+ { ".GLOBAL", TOK_GLOBAL },
+ { ".GLOBALZP", TOK_GLOBALZP },
+ { ".HIBYTE", TOK_HIBYTE },
+ { ".HIBYTES", TOK_HIBYTES },
+ { ".HIWORD", TOK_HIWORD },
+ { ".I16", TOK_I16 },
+ { ".I8", TOK_I8 },
+ { ".IDENT", TOK_MAKEIDENT },
+ { ".IF", TOK_IF },
+ { ".IFBLANK", TOK_IFBLANK },
+ { ".IFCONST", TOK_IFCONST },
+ { ".IFDEF", TOK_IFDEF },
+ { ".IFNBLANK", TOK_IFNBLANK },
+ { ".IFNCONST", TOK_IFNCONST },
+ { ".IFNDEF", TOK_IFNDEF },
+ { ".IFNREF", TOK_IFNREF },
+ { ".IFP02", TOK_IFP02 },
+ { ".IFP816", TOK_IFP816 },
+ { ".IFPC02", TOK_IFPC02 },
+ { ".IFPSC02", TOK_IFPSC02 },
+ { ".IFREF", TOK_IFREF },
+ { ".IMPORT", TOK_IMPORT },
+ { ".IMPORTZP", TOK_IMPORTZP },
+ { ".INCBIN", TOK_INCBIN },
+ { ".INCLUDE", TOK_INCLUDE },
+ { ".INTERRUPTOR", TOK_INTERRUPTOR },
+ { ".ISIZE", TOK_ISIZE },
+ { ".ISMNEM", TOK_ISMNEMONIC },
+ { ".ISMNEMONIC", TOK_ISMNEMONIC },
+ { ".LEFT", TOK_LEFT },
+ { ".LINECONT", TOK_LINECONT },
+ { ".LIST", TOK_LIST },
+ { ".LISTBYTES", TOK_LISTBYTES },
+ { ".LOBYTE", TOK_LOBYTE },
+ { ".LOBYTES", TOK_LOBYTES },
+ { ".LOCAL", TOK_LOCAL },
+ { ".LOCALCHAR", TOK_LOCALCHAR },
+ { ".LOWORD", TOK_LOWORD },
+ { ".MAC", TOK_MACRO },
+ { ".MACPACK", TOK_MACPACK },
+ { ".MACRO", TOK_MACRO },
+ { ".MATCH", TOK_MATCH },
+ { ".MAX", TOK_MAX },
+ { ".MID", TOK_MID },
+ { ".MIN", TOK_MIN },
+ { ".MOD", TOK_MOD },
+ { ".NOT", TOK_BOOLNOT },
+ { ".NULL", TOK_NULL },
+ { ".OR", TOK_BOOLOR },
+ { ".ORG", TOK_ORG },
+ { ".OUT", TOK_OUT },
+ { ".P02", TOK_P02 },
+ { ".P816", TOK_P816 },
+ { ".PAGELEN", TOK_PAGELENGTH },
+ { ".PAGELENGTH", TOK_PAGELENGTH },
+ { ".PARAMCOUNT", TOK_PARAMCOUNT },
+ { ".PC02", TOK_PC02 },
+ { ".POPCPU", TOK_POPCPU },
+ { ".POPSEG", TOK_POPSEG },
+ { ".PROC", TOK_PROC },
+ { ".PSC02", TOK_PSC02 },
+ { ".PUSHCPU", TOK_PUSHCPU },
+ { ".PUSHSEG", TOK_PUSHSEG },
+ { ".REF", TOK_REFERENCED },
+ { ".REFERENCED", TOK_REFERENCED },
+ { ".RELOC", TOK_RELOC },
+ { ".REPEAT", TOK_REPEAT },
+ { ".RES", TOK_RES },
+ { ".RIGHT", TOK_RIGHT },
+ { ".RODATA", TOK_RODATA },
+ { ".SCOPE", TOK_SCOPE },
+ { ".SEGMENT", TOK_SEGMENT },
+ { ".SET", TOK_SET },
+ { ".SETCPU", TOK_SETCPU },
+ { ".SHL", TOK_SHL },
+ { ".SHR", TOK_SHR },
+ { ".SIZEOF", TOK_SIZEOF },
+ { ".SMART", TOK_SMART },
+ { ".SPRINTF", TOK_SPRINTF },
+ { ".STRAT", TOK_STRAT },
+ { ".STRING", TOK_STRING },
+ { ".STRLEN", TOK_STRLEN },
+ { ".STRUCT", TOK_STRUCT },
+ { ".TAG", TOK_TAG },
+ { ".TCOUNT", TOK_TCOUNT },
+ { ".TIME", TOK_TIME },
+ { ".UNDEF", TOK_UNDEF },
+ { ".UNDEFINE", TOK_UNDEF },
+ { ".UNION", TOK_UNION },
+ { ".VERSION", TOK_VERSION },
+ { ".WARNING", TOK_WARNING },
+ { ".WORD", TOK_WORD },
+ { ".XMATCH", TOK_XMATCH },
+ { ".XOR", TOK_BOOLXOR },
+ { ".ZEROPAGE", TOK_ZEROPAGE },
};
R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
sizeof (DotKeywords [0]), CmpDotKeyword);
if (R != 0) {
+
+ /* By default, disable any somewhat experiemental DotKeyword. */
+
+ switch (R->Tok) {
+
+ case TOK_ADDRSIZE:
+ /* Disallow .ADDRSIZE function by default */
+ if (AddrSize == 0) {
+ return TOK_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
return R->Tok;
+
} else {
return TOK_NONE;
}
break;
}
DVal = DigitVal (Buf[I]);
- if (DVal > Base) {
+ if (DVal >= Base) {
Error ("Invalid digits in number");
CurTok.IVal = 0;
break;
/* Line continuation? */
if (LineCont) {
NextChar ();
+ /* Next char should be a LF, if not, will result in an error later */
if (C == '\n') {
- /* Handle as white space */
+ /* Ignore the '\n' */
NextChar ();
- C = ' ';
goto Again;
+ } else {
+ /* Make it clear what the problem is: */
+ Error ("EOL expected.");
}
}
break;
}
}
- /* If the symbol was already declared as a condes, check if the new
- ** priority value is the same as the old one.
+ /* If the symbol already was declared as a condes of this type,
+ ** check if the new priority value is the same as the old one.
*/
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
if (S->ConDesPrio[Type] != Prio) {
/* Set the symbol data */
S->Flags |= (SF_EXPORT | SF_REFERENCED);
- /* In case we have no line info for the definition, record it now */
- if (CollCount (&S->DefLines) == 0) {
- GetFullLineInfo (&S->DefLines);
- }
+ /* Remember the line info for this reference */
+ CollAppend (&S->RefLines, GetAsmLineInfo ());
}
while (S) {
/* Ignore unused symbols */
- if ((S->Flags & SF_UNUSED) != 0) {
+ if ((S->Flags & SF_UNUSED) == 0) {
fprintf (F,
- "%m%-24p %s %s %s %s %s\n",
- GetSymName (S),
+ "%-24s %s %s %s %s %s\n",
+ SB_GetConstBuf (GetSymName (S)),
(S->Flags & SF_DEFINED)? "DEF" : "---",
(S->Flags & SF_REFERENCED)? "REF" : "---",
(S->Flags & SF_IMPORT)? "IMP" : "---",
TOK_A16 = TOK_FIRSTPSEUDO,
TOK_A8,
TOK_ADDR,
+ TOK_ADDRSIZE,
TOK_ALIGN,
TOK_ASCIIZ,
+ TOK_ASIZE,
TOK_ASSERT,
TOK_AUTOIMPORT,
TOK_BANK,
TOK_DEBUGINFO,
TOK_DEFINE,
TOK_DEFINED,
+ TOK_DEFINEDMACRO,
TOK_DELMAC,
TOK_DESTRUCTOR,
TOK_DWORD,
TOK_INCBIN,
TOK_INCLUDE,
TOK_INTERRUPTOR,
+ TOK_ISIZE,
+ TOK_ISMNEMONIC,
TOK_LEFT,
TOK_LINECONT,
TOK_LIST,
/* */
/* */
/* */
-/* (C) 2001-2012, Ullrich von Bassewitz */
+/* (C) 2001-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include "codeseg.h"
#include "datatype.h"
#include "error.h"
+#include "global.h"
#include "reginfo.h"
#include "symtab.h"
#include "codeinfo.h"
** Search for it in the list of builtin functions.
*/
if (Name[0] == '_') {
-
/* Search in the symbol table, skip the leading underscore */
SymEntry* E = FindGlobalSym (Name+1);
- /* Did we find it in the top level table? */
+ /* Did we find it in the top-level table? */
if (E && IsTypeFunc (E->Type)) {
-
FuncDesc* D = E->V.F.Func;
- /* A function may use the A or A/X registers if it is a fastcall
- ** function. If it is not a fastcall function but a variadic one,
- ** it will use the Y register (the parameter size is passed here).
- ** In all other cases, no registers are used. However, we assume
- ** that any function will destroy all registers.
+ /* A variadic function will use the Y register (the parameter list
+ ** size is passed there). A fastcall function will use the A or A/X
+ ** registers. In all other cases, no registers are used. However,
+ ** we assume that any function will destroy all registers.
*/
- if (IsQualFastcall (E->Type) && D->ParamCount > 0) {
- /* Will use registers depending on the last param */
- unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type);
- if (LastParamSize == 1) {
- *Use = REG_A;
- } else if (LastParamSize == 2) {
- *Use = REG_AX;
- } else {
- *Use = REG_EAX;
- }
- } else if ((D->Flags & FD_VARIADIC) != 0) {
+ if ((D->Flags & FD_VARIADIC) != 0) {
*Use = REG_Y;
+ } else if (D->ParamCount > 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (E->Type) :
+ !IsQualCDecl (E->Type))) {
+ /* Will use registers depending on the last param. */
+ switch (CheckedSizeOf (D->LastParam->Type)) {
+ case 1u:
+ *Use = REG_A;
+ break;
+ case 2u:
+ *Use = REG_AX;
+ break;
+ default:
+ *Use = REG_EAX;
+ }
} else {
/* Will not use any registers */
*Use = REG_NONE;
-unsigned OptShift2(CodeSeg* S)
-/* A call to the asrax1 routines may get replaced by something simpler, if
-** X is not used later:
+unsigned OptShift2 (CodeSeg* S)
+/* The sequence
+**
+** bpl L
+** dex
+** L: jsr asraxN
+**
+** might be replaced by N copies of
**
** cmp #$80
** ror a
+**
+** if X is not used later (X is assumed to be zero on entry).
+** If the sequence is followed immediately by another
+**
+** jsr asraxN
+**
+** then their shifts are combined.
*/
{
unsigned Changes = 0;
- unsigned I;
+ unsigned I = 0;
/* Walk over the entries */
- I = 0;
while (I < CS_GetEntryCount (S)) {
-
unsigned Shift;
- unsigned Count;
+ unsigned Count, Count2;
+ unsigned K;
+ CodeEntry* L[4];
/* Get next entry */
- CodeEntry* E = CS_GetEntry (S, I);
+ L[0] = CS_GetEntry (S, I);
/* Check for the sequence */
- if (E->OPC == OP65_JSR &&
- (Shift = GetShift (E->Arg)) != SHIFT_NONE &&
- SHIFT_TYPE (Shift) == SHIFT_TYPE_ASR &&
- (Count = SHIFT_COUNT (Shift)) > 0 &&
- Count * 100 <= S->CodeSizeFactor &&
- !RegXUsed (S, I+1)) {
-
- CodeEntry* X;
- unsigned J = I+1;
+ if ((L[0]->OPC == OP65_BPL || L[0]->OPC == OP65_BCC) &&
+ L[0]->JumpTo != 0 &&
+ CS_GetEntries (S, L+1, I+1, 3) &&
+ L[1]->OPC == OP65_DEX &&
+ L[0]->JumpTo->Owner == L[2] &&
+ !CS_RangeHasLabel (S, I, 2) &&
+ L[2]->OPC == OP65_JSR &&
+ SHIFT_TYPE (Shift = GetShift (L[2]->Arg)) == SHIFT_TYPE_ASR &&
+ (Count = SHIFT_COUNT (Shift)) > 0) {
- /* Generate the replacement sequence */
- while (Count--) {
- /* cmp #$80 */
- X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, E->LI);
- CS_InsertEntry (S, X, J++);
+ if (L[3]->OPC == OP65_JSR &&
+ SHIFT_TYPE (Shift = GetShift (L[3]->Arg)) == SHIFT_TYPE_ASR &&
+ (Count2 = SHIFT_COUNT (Shift)) > 0) {
- /* ror a */
- X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI);
- CS_InsertEntry (S, X, J++);
+ /* Found a second jsr asraxN */
+ Count += Count2;
+ K = 4;
+ } else {
+ K = 3;
}
+ if (Count * 100 <= S->CodeSizeFactor &&
+ !RegXUsed (S, I+K)) {
- /* Delete the call to asrax */
- CS_DelEntry (S, I);
+ CodeEntry* X;
+ unsigned J = I+K;
- /* Remember, we had changes */
- ++Changes;
+ /* Generate the replacement sequence */
+ do {
+ /* cmp #$80 */
+ X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, L[2]->LI);
+ CS_InsertEntry (S, X, J++);
+
+ /* ror a */
+ X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
+ CS_InsertEntry (S, X, J++);
+ } while (--Count);
+
+ /* Remove the bpl/dex/jsr */
+ CS_DelEntries (S, I, K);
+
+ /* Remember, we had changes */
+ ++Changes;
+ }
}
/* Next entry */
++I;
-
}
/* Return the number of changes made */
(Shift = GetShift (L[2]->Arg)) != SHIFT_NONE &&
SHIFT_DIR (Shift) == SHIFT_DIR_RIGHT &&
(Count = SHIFT_COUNT (Shift)) > 0) {
-
+
/* Add the replacement insn instead */
CodeEntry* X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
CS_InsertEntry (S, X, I+3);
CS_InsertEntry (S, X, I+4);
}
- /* Remove the bcs/dex/jsr */
+ /* Remove the bcc/inx/jsr */
CS_DelEntries (S, I, 3);
/* Remember, we had changes */
** L1:
*/
-unsigned OptShift2(CodeSeg* S);
-/* A call to the asrax1 routines may get replaced by something simpler, if
-** X is not used later:
+unsigned OptShift2 (CodeSeg* S);
+/* The sequence
+**
+** bpl L
+** dex
+** L: jsr asraxN
+**
+** might be replaced by N copies of
**
** cmp #$80
** ror a
+**
+** if X is not used later (X is assumed to be zero on entry).
*/
unsigned OptShift3 (CodeSeg* S);
InsertEntry (D, X, D->IP++);
/* Lhs load entries can be removed */
- if (LoadX->AM != AM65_IMM) {
- D->Lhs.X.Flags |= LI_REMOVE;
- }
- if (LoadA->AM != AM65_IMM) {
- D->Lhs.A.Flags |= LI_REMOVE;
- }
+ D->Lhs.X.Flags |= LI_REMOVE;
+ D->Lhs.A.Flags |= LI_REMOVE;
} else if ((D->Rhs.A.Flags & (LI_DIRECT | LI_RELOAD_Y)) == LI_DIRECT &&
(D->Rhs.X.Flags & (LI_DIRECT | LI_RELOAD_Y)) == LI_DIRECT) {
InsertEntry (D, X, D->IP++);
/* Rhs load entries can be removed */
- if (LoadX->AM != AM65_IMM) {
- D->Rhs.X.Flags |= LI_REMOVE;
- }
- if (LoadA->AM != AM65_IMM) {
- D->Rhs.A.Flags |= LI_REMOVE;
- }
+ D->Rhs.X.Flags |= LI_REMOVE;
+ D->Rhs.A.Flags |= LI_REMOVE;
} else if ((D->Rhs.A.Flags & LI_DIRECT) != 0 &&
(D->Rhs.X.Flags & LI_DIRECT) != 0) {
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Recursive call */
PrintType (F, T + 1);
if (T->A.L == UNSPECIFIED) {
- fprintf (F, "[]");
+ fprintf (F, " []");
} else {
- fprintf (F, "[%ld]", T->A.L);
+ fprintf (F, " [%ld]", T->A.L);
}
return;
case T_TYPE_PTR:
/* Recursive call */
PrintType (F, T + 1);
- fprintf (F, "*");
+ fprintf (F, " *");
return;
case T_TYPE_FUNC:
fprintf (F, "function returning ");
case T_VOID:
return 0; /* Assume voids have size zero */
+ /* Beware: There's a chance that this triggers problems in other parts
+ of the compiler. The solution is to fix the callers, because calling
+ SizeOf() with a function type as argument is bad. */
+ case T_FUNC:
+ return 0; /* Size of function is unknown */
+
case T_SCHAR:
case T_UCHAR:
return SIZEOF_CHAR;
return SIZEOF_INT;
case T_PTR:
- case T_FUNC: /* Maybe pointer to function */
return SIZEOF_PTR;
case T_LONG:
** will return. Otherwise it will return the base element type, which means
** the element type that is not an array.
*/
-{
+{
while (IsTypeArray (T)) {
++T;
}
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
# define IsQualCDecl(T) (((T)->C & T_QUAL_CDECL) != 0)
#endif
+#if defined(HAVE_INLINE)
+INLINE int IsQualCConv (const Type* T)
+/* Return true if the given type has a calling convention qualifier */
+{
+ return (T->C & T_QUAL_CCONV) != 0;
+}
+#else
+# define IsQualCConv(T) (((T)->C & T_QUAL_CCONV) != 0)
+#endif
+
int IsVariadicFunc (const Type* T) attribute ((const));
/* Return true if this is a function type or pointer to function type with
** variable parameter list
/* */
/* */
/* */
-/* (C) 1998-2013, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
-/* Parse a type specificier */
+/* Parse a type specifier */
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
/* Parse initialization of variables. Return the number of data bytes. */
T = DataType;
while (T->C != T_END) {
if (IsTypePtr (T)) {
-
- /* Fastcall qualifier on the pointer? */
- if (IsQualFastcall (T)) {
- /* Pointer to function which is not fastcall? */
- if (IsTypeFunc (T+1) && !IsQualFastcall (T+1)) {
- /* Move the fastcall qualifier from the pointer to
- ** the function.
- */
- T[0].C &= ~T_QUAL_FASTCALL;
- T[1].C |= T_QUAL_FASTCALL;
+ /* Calling convention qualifier on the pointer? */
+ if (IsQualCConv (T)) {
+ /* Pull the convention off of the pointer */
+ Q = T[0].C & T_QUAL_CCONV;
+ T[0].C &= ~T_QUAL_CCONV;
+
+ /* Pointer to a function which doesn't have an explicit convention? */
+ if (IsTypeFunc (T + 1)) {
+ if (IsQualCConv (T + 1)) {
+ if ((T[1].C & T_QUAL_CCONV) == Q) {
+ Warning ("Pointer duplicates function's calling convention");
+ } else {
+ Error ("Function's and pointer's calling conventions are different");
+ }
+ } else {
+ if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) {
+ Error ("Variadic-function pointers cannot be __fastcall__");
+ } else {
+ /* Move the qualifier from the pointer to the function. */
+ T[1].C |= Q;
+ }
+ }
} else {
- Error ("Invalid `_fastcall__' qualifier for pointer");
+ Error ("Not pointer to a function; can't use a calling convention");
}
}
if (Q == T_QUAL_NONE) {
/* No address size qualifiers specified */
if (IsTypeFunc (T+1)) {
- /* Pointer to function. Use the qualifier from the function
- ** or the default if the function don't has one.
+ /* Pointer to function. Use the qualifier from the function,
+ ** or the default if the function doesn't have one.
*/
Q = (T[1].C & T_QUAL_ADDRSIZE);
if (Q == T_QUAL_NONE) {
T[0].C |= Q;
} else {
/* We have address size qualifiers. If followed by a function,
- ** apply these also to the function.
+ ** apply them to the function also.
*/
if (IsTypeFunc (T+1)) {
TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE);
static int ParseFieldWidth (Declaration* Decl)
-/* Parse an optional field width. Returns -1 if no field width is speficied,
+/* Parse an optional field width. Returns -1 if no field width is specified,
** otherwise the width of the field.
*/
{
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
-/* Parse a type specificier */
+/* Parse a type specifier */
{
ident Ident;
SymEntry* Entry;
static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Recursively process declarators. Build a type array in reverse order. */
{
- /* Read optional function or pointer qualifiers. These modify the
- ** identifier or token to the right. For convenience, we allow the fastcall
- ** qualifier also for pointers here. If it is a pointer-to-function, the
- ** qualifier will later be transfered to the function itself. If it's a
+ /* Read optional function or pointer qualifiers. They modify the
+ ** identifier or token to the right. For convenience, we allow a calling
+ ** convention also for pointers here. If it's a pointer-to-function, the
+ ** qualifier later will be transfered to the function itself. If it's a
** pointer to something else, it will be flagged as an error.
*/
- TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_FASTCALL);
+ TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV);
/* Pointer to something */
if (CurTok.Tok == TOK_STAR) {
/* Skip the star */
NextToken ();
- /* Allow const, restrict and volatile qualifiers */
+ /* Allow const, restrict, and volatile qualifiers */
Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT);
- /* Parse the type, the pointer points to */
+ /* Parse the type that the pointer points to */
Declarator (Spec, D, Mode);
/* Add the type */
/* We cannot specify fastcall for variadic functions */
if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) {
- Error ("Variadic functions cannot be `__fastcall__'");
+ Error ("Variadic functions cannot be __fastcall__");
Qualifiers &= ~T_QUAL_FASTCALL;
}
/* expr.c
**
-** Ullrich von Bassewitz, 21.06.1998
+** 1998-06-21, Ullrich von Bassewitz
+** 2015-06-26, Greg King
*/
/* Generator attributes */
#define GEN_NOPUSH 0x01 /* Don't push lhs */
#define GEN_COMM 0x02 /* Operator is commutative */
+#define GEN_NOFUNC 0x04 /* Not allowed for function pointers */
/* Map a generator function and its attributes to a token */
typedef struct {
/* Handle function pointers transparently */
IsFuncPtr = IsTypeFuncPtr (Expr->Type);
if (IsFuncPtr) {
-
- /* Check wether it's a fastcall function that has parameters */
- IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0);
+ /* Check whether it's a fastcall function that has parameters */
+ IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && Func->ParamCount > 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (Expr->Type + 1) :
+ !IsQualCDecl (Expr->Type + 1));
/* Things may be difficult, depending on where the function pointer
** resides. If the function pointer is an expression of some sort
}
/* If we didn't inline the function, get fastcall info */
- IsFastcall = IsQualFastcall (Expr->Type);
+ IsFastcall = (Func->Flags & FD_VARIADIC) == 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (Expr->Type) :
+ !IsQualCDecl (Expr->Type));
}
/* Parse the parameter list */
} else {
Error ("Illegal indirection");
}
- /* The * operator yields an lvalue */
- ED_MakeLVal (Expr);
+ /* If the expression points to an array, then don't convert the
+ ** address -- it already is the location of the first element.
+ */
+ if (!IsTypeArray (Expr->Type)) {
+ /* The * operator yields an lvalue */
+ ED_MakeLVal (Expr);
+ }
}
break;
Tok = CurTok.Tok;
NextToken ();
+ /* If lhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr->Type)) {
+ Expr->Type = PointerTo (Expr->Type);
+ }
+
/* Get the lhs on stack */
GetCodePos (&Mark1);
ltype = TypeOf (Expr->Type);
/* Get the right hand side */
MarkedExprWithCheck (hienext, &Expr2);
+ /* If rhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr2.Type)) {
+ Expr2.Type = PointerTo (Expr2.Type);
+ }
+
/* Check for a constant expression */
rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
if (!rconst) {
LoadExpr (CF_NONE, &Expr2);
}
+ /* Some operations aren't allowed on function pointers */
+ if ((Gen->Flags & GEN_NOFUNC) != 0) {
+ /* Output only one message even if both sides are wrong */
+ if (IsTypeFuncPtr (Expr->Type)) {
+ Error ("Invalid left operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ } else if (IsTypeFuncPtr (Expr2.Type)) {
+ Error ("Invalid right operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ }
+ }
+
/* Make sure, the types are compatible */
if (IsClassInt (Expr->Type)) {
if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
*/
Type* left = Indirect (Expr->Type);
Type* right = Indirect (Expr2.Type);
- if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
- /* Incomatible pointers */
+ if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
+ /* Incompatible pointers */
Error ("Incompatible types");
}
} else if (!ED_IsNullPtr (&Expr2)) {
Type* lhst; /* Type of left hand side */
Type* rhst; /* Type of right hand side */
-
/* Skip the PLUS token */
NextToken ();
flags = CF_PTR;
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
/* Left is int, right is pointer, must scale lhs */
- g_tosint (TypeOf (rhst)); /* Make sure, TOS is int */
+ g_tosint (TypeOf (lhst)); /* Make sure TOS is int */
g_swap (CF_INT); /* Swap TOS and primary */
g_scale (CF_INT, CheckedPSizeOf (rhst));
/* Operate on pointers, result type is a pointer */
/* Condition codes not set */
ED_MarkAsUntested (Expr);
-
}
int rscale; /* Scale factor for the result */
+ /* lhs cannot be function or pointer to function */
+ if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
+ Error ("Invalid left operand for binary operator `-'");
+ /* Make it pointer to char to avoid further errors */
+ Expr->Type = type_uchar;
+ }
+
/* Skip the MINUS token */
NextToken ();
/* Parse the right hand side */
MarkedExprWithCheck (hie9, &Expr2);
+ /* rhs cannot be function or pointer to function */
+ if (IsTypeFunc (Expr2.Type) || IsTypeFuncPtr (Expr2.Type)) {
+ Error ("Invalid right operand for binary operator `-'");
+ /* Make it pointer to char to avoid further errors */
+ Expr2.Type = type_uchar;
+ }
+
/* Check for a constant rhs expression */
if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
/* Handle greater-than type comparators */
{
static const GenDesc hie6_ops [] = {
- { TOK_LT, GEN_NOPUSH, g_lt },
- { TOK_LE, GEN_NOPUSH, g_le },
- { TOK_GE, GEN_NOPUSH, g_ge },
- { TOK_GT, GEN_NOPUSH, g_gt },
- { TOK_INVALID, 0, 0 }
+ { TOK_LT, GEN_NOPUSH | GEN_NOFUNC, g_lt },
+ { TOK_LE, GEN_NOPUSH | GEN_NOFUNC, g_le },
+ { TOK_GE, GEN_NOPUSH | GEN_NOFUNC, g_ge },
+ { TOK_GT, GEN_NOPUSH | GEN_NOFUNC, g_gt },
+ { TOK_INVALID, 0, 0 }
};
hie_compare (hie6_ops, Expr, ShiftExpr);
}
/* */
/* */
/* */
-/* (C) 2000-2012, Ullrich von Bassewitz */
+/* (C) 2000-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
*/
if (D->ParamCount > 0 || (D->Flags & FD_VARIADIC) != 0) {
g_importmainargs ();
+
+ /* The start-up code doesn't fast-call main(). */
+ Func->Type->C |= T_QUAL_CDECL;
}
/* Determine if this is a main function in a C99 environment that
PushLiteralPool (Func);
/* If this is a fastcall function, push the last parameter onto the stack */
- if (IsQualFastcall (Func->Type) && D->ParamCount > 0) {
-
+ if ((D->Flags & FD_VARIADIC) == 0 && D->ParamCount > 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (Func->Type) :
+ !IsQualCDecl (Func->Type))) {
unsigned Flags;
- /* Fastcall functions may never have an ellipsis or the compiler is buggy */
- CHECK ((D->Flags & FD_VARIADIC) == 0);
-
/* Generate the push */
if (IsTypeFunc (D->LastParam->Type)) {
/* Pointer to function */
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
unsigned char AddSource = 0; /* Add source lines as comments */
+unsigned char AutoCDecl = 0; /* Make functions default to __cdecl__ */
unsigned char DebugInfo = 0; /* Add debug info to the obj */
unsigned char PreprocessOnly = 0; /* Just preprocess the input */
unsigned char DebugOptOutput = 0; /* Output debug stuff */
/* */
/* */
/* */
-/* (C) 1998-2012, Ullrich von Bassewitz */
+/* (C) 1998-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Options */
extern unsigned char AddSource; /* Add source lines as comments */
+extern unsigned char AutoCDecl; /* Make functions default to __cdecl__ */
extern unsigned char DebugInfo; /* Add debug info to the obj */
extern unsigned char PreprocessOnly; /* Just preprocess the input */
extern unsigned char DebugOptOutput; /* Output debug stuff */
/* */
/* */
/* */
-/* (C) 2000-2013, Ullrich von Bassewitz */
+/* (C) 2000-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
"\n"
"Long options:\n"
" --add-source\t\t\tInclude source as comment\n"
+ " --all-cdecl\t\t\tMake functions default to __cdecl__\n"
" --bss-name seg\t\tSet the name of the BSS segment\n"
" --check-stack\t\t\tGenerate stack overflow checks\n"
" --code-name seg\t\tSet the name of the CODE segment\n"
DefineNumericMacro ("__SIM65C02__", 1);
break;
+ case TGT_OSIC1P:
+ DefineNumericMacro ("__OSIC1P__", 1);
+ break;
+
+ case TGT_PCENGINE:
+ DefineNumericMacro ("__PCE__", 1);
+ break;
+
default:
AbEnd ("Unknown target system type %d", Target);
}
+static void OptAllCDecl (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
+/* Make functions default to cdecl instead of fastcall. */
+{
+ AutoCDecl = 1;
+}
+
+
+
static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --bss-name option */
{
/* Program long options */
static const LongOpt OptTab[] = {
{ "--add-source", 0, OptAddSource },
+ { "--all-cdecl", 0, OptAllCDecl },
{ "--bss-name", 1, OptBssName },
{ "--check-stack", 0, OptCheckStack },
{ "--code-name", 1, OptCodeName },
/* Remove a new style C comment from line. */
{
/* Beware: Because line continuation chars are handled when reading
- ** lines, we may only skip til the end of the source line, which
+ ** lines, we may only skip until the end of the source line, which
** may not be the same as the end of the input line. The end of the
** source line is denoted by a lf (\n) character.
*/
/* Print the assembler name if we have one */
if (E->AsmName) {
fprintf (F, " AsmName: %s\n", E->AsmName);
- }
+ }
/* Print the flags */
SymFlags = E->Flags;
- fprintf (F, " Flags: ");
+ fprintf (F, " Flags:");
for (I = 0; I < sizeof (Flags) / sizeof (Flags[0]) && SymFlags != 0; ++I) {
if ((SymFlags & Flags[I].Val) == Flags[I].Val) {
SymFlags &= ~Flags[I].Val;
- fprintf (F, "%s ", Flags[I].Name);
+ fprintf (F, " %s", Flags[I].Name);
}
}
if (SymFlags != 0) {
- fprintf (F, "%04X", SymFlags);
+ fprintf (F, " 0x%05X", SymFlags);
}
fprintf (F, "\n");
}
}
+ /* If a static declaration follows a non-static declaration, then
+ ** warn about the conflict. (It will compile a public declaration.)
+ */
+ if ((Flags & SC_EXTERN) == 0 && (Entry->Flags & SC_EXTERN) != 0) {
+ Warning ("static declaration follows non-static declaration of `%s'.", Name);
+ }
+
+ /* An extern declaration must not change the current linkage. */
+ if (IsFunc || (Flags & (SC_EXTERN | SC_DEF)) == SC_EXTERN) {
+ Flags &= ~SC_EXTERN;
+ }
+
+ /* If a public declaration follows a static declaration, then
+ ** warn about the conflict. (It will compile a public declaration.)
+ */
+ if ((Flags & SC_EXTERN) != 0 && (Entry->Flags & SC_EXTERN) == 0) {
+ Warning ("public declaration follows static declaration of `%s'.", Name);
+ }
+
/* Add the new flags */
Entry->Flags |= Flags;
/* */
/* */
/* */
-/* (C) 1998-2008 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2015, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* cc65 */
#include "funcdesc.h"
+#include "global.h"
#include "symtab.h"
#include "typecmp.h"
return;
}
}
+
+ if (LeftType == T_TYPE_FUNC) {
+ /* If a calling convention wasn't set explicitly,
+ ** then assume the default one.
+ */
+ if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
+ LeftQual |= (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
+ }
+ if ((RightQual & T_QUAL_CCONV) == T_QUAL_NONE) {
+ RightQual |= (AutoCDecl || IsVariadicFunc (rhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
+ }
+ }
+
if (LeftQual != RightQual) {
/* On the first indirection level, different qualifiers mean
- ** that the types are still compatible. On the second level,
- ** this is a (maybe minor) error, so we create a special
- ** return code, since a qualifier is dropped from a pointer.
- ** Starting from the next level, the types are incompatible
- ** if the qualifiers differ.
+ ** that the types still are compatible. On the second level,
+ ** that is a (maybe minor) error. We create a special return-code
+ ** if a qualifier is dropped from a pointer. But, different calling
+ ** conventions are incompatible. Starting from the next level,
+ ** the types are incompatible if the qualifiers differ.
*/
+ /* (Debugging statement) */
/* printf ("Ind = %d %06X != %06X\n", Indirections, LeftQual, RightQual); */
switch (Indirections) {
-
case 0:
SetResult (Result, TC_STRICT_COMPATIBLE);
break;
case 1:
- /* A non const value on the right is compatible to a
+ /* A non-const value on the right is compatible to a
** const one to the left, same for volatile.
*/
if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
} else {
SetResult (Result, TC_STRICT_COMPATIBLE);
}
- break;
+
+ if (LeftType != T_TYPE_FUNC || (LeftQual & T_QUAL_CCONV) == (RightQual & T_QUAL_CCONV)) {
+ break;
+ }
+ /* else fall through */
default:
SetResult (Result, TC_INCOMPATIBLE);
/* Check for special type elements */
switch (LeftType) {
-
case T_TYPE_PTR:
++Indirections;
break;
#if defined(NEED_SPAWN)
-# if defined(SPAWN_AMIGA)
+# if defined(_AMIGA)
# include "spawn-amiga.inc"
# else
# include "spawn-unix.inc"
/* Mode argument for spawn. This value is ignored by the function and only
- * provided for DOS/Windows compatibility.
- */
+** provided for DOS/Windows compatibility.
+*/
#ifndef P_WAIT
#define P_WAIT 0
#endif
int spawnvp (int Mode attribute ((unused)),
const char* File attribute ((unused)),
char* const argv [])
-/* Execute the given program searching and wait til it terminates. The Mode
- * argument is ignored (compatibility only). The result of the function is
- * the return code of the program. The function will terminate the program
- * on errors.
- */
+/* Execute the given program searching and wait until it terminates. The Mode
+** argument is ignored (compatibility only). The result of the function is
+** the return code of the program. The function will terminate the program
+** on errors.
+*/
{
int Status;
StrBuf Command = AUTO_STRBUF_INITIALIZER;
/* Mode argument for spawn. This value is ignored by the function and only
- * provided for DOS/Windows compatibility.
- */
+** provided for DOS/Windows compatibility.
+*/
#ifndef P_WAIT
#define P_WAIT 0
#endif
int spawnvp (int Mode attribute ((unused)), const char* File, char* const argv [])
-/* Execute the given program searching and wait til it terminates. The Mode
- * argument is ignored (compatibility only). The result of the function is
- * the return code of the program. The function will terminate the program
- * on errors.
- */
+/* Execute the given program searching and wait until it terminates. The Mode
+** argument is ignored (compatibility only). The result of the function is
+** the return code of the program. The function will terminate the program
+** on errors.
+*/
{
int Status = 0;
}
/* Only the father goes here, we place a return here regardless of that
- * to avoid compiler warnings.
- */
+ ** to avoid compiler warnings.
+ */
return WEXITSTATUS (Status);
}
-void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName)
+void InitCmdLine (int* aArgCount, char*** aArgVec, const char* aProgName)
/* Initialize command line parsing. aArgVec is the argument array terminated by
** a NULL pointer (as usual), ArgCount is the number of valid arguments in the
** array. Both arguments are remembered in static storage.
int I;
/* Get the program name from argv[0] but strip a path */
- if (*(aArgVec)[0] == 0) {
+ if ((*aArgVec)[0] == 0) {
/* Use the default name given */
ProgName = aProgName;
} else {
** special handling for arguments preceeded by the '@' sign - these are
** actually files containing arguments.
*/
- for (I = 0; I < *aArgCount; ++I) {
+ for (I = 0; I <= *aArgCount; ++I) {
/* Get the next argument */
char* Arg = (*aArgVec)[I];
}
/* Store the new argument list in a safe place... */
- ArgCount = L.Count;
+ ArgCount = L.Count - 1;
ArgVec = L.Vec;
/* ...and pass back the changed data also */
- *aArgCount = L.Count;
+ *aArgCount = L.Count - 1;
*aArgVec = L.Vec;
}
-void InitCmdLine (int* aArgCount, char** aArgVec[], const char* aProgName);
+void InitCmdLine (int* aArgCount, char*** aArgVec, const char* aProgName);
/* Initialize command line parsing. aArgVec is the argument array terminated by
** a NULL pointer (as usual), ArgCount is the number of valid arguments in the
** array. Both arguments are remembered in static storage.
/* */
/* */
/* */
-/* (C) 2000-2011, Ullrich von Bassewitz */
+/* (C) 2000-2015, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Translation table with direct (no) translation */
-static unsigned char CTNone[256] = {
+static const unsigned char CTNone[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
};
-/* Translation table ISO-8859-1 -> ATASCII */
-static const unsigned char CTAtari [256] = {
+/* Translation table ISO-8859-1 -> AtASCII */
+static const unsigned char CTAtari[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0xFD,0x08,0x7F,0x9B,0x0B,0x7D,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
};
-/* Translation table ISO-8859-1 -> PETSCII */
-static const unsigned char CTPET [256] = {
+/* Translation table ISO-8859-1 -> OSASCII */
+static const unsigned char CTOSI[256] = {
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7D,0x7C,0x7F,0x7E,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
+};
+
+/* Translation table ISO-8859-1 -> PetSCII */
+static const unsigned char CTPET[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
{ "module", TGT_MODULE },
{ "nes", TGT_NES },
{ "none", TGT_NONE },
+ { "osic1p", TGT_OSIC1P },
+ { "pce", TGT_PCENGINE },
{ "pet", TGT_PET },
{ "plus4", TGT_PLUS4 },
{ "sim6502", TGT_SIM6502 },
{ "plus4", CPU_6502, BINFMT_BINARY, CTPET },
{ "cbm510", CPU_6502, BINFMT_BINARY, CTPET },
{ "cbm610", CPU_6502, BINFMT_BINARY, CTPET },
+ { "osic1p", CPU_6502, BINFMT_BINARY, CTOSI },
{ "pet", CPU_6502, BINFMT_BINARY, CTPET },
{ "bbc", CPU_6502, BINFMT_BINARY, CTNone },
{ "apple2", CPU_6502, BINFMT_BINARY, CTNone },
{ "lynx", CPU_65C02, BINFMT_BINARY, CTNone },
{ "sim6502", CPU_6502, BINFMT_BINARY, CTNone },
{ "sim65c02", CPU_65C02, BINFMT_BINARY, CTNone },
+ { "pce", CPU_HUC6280, BINFMT_BINARY, CTNone },
};
/* Target system */
TGT_PLUS4,
TGT_CBM510,
TGT_CBM610,
+ TGT_OSIC1P,
TGT_PET,
TGT_BBC,
TGT_APPLE2,
TGT_LYNX,
TGT_SIM6502,
TGT_SIM65C02,
+ TGT_PCENGINE,
TGT_COUNT /* Number of target systems */
} target_t;
#define VER_MAJOR 2U
-#define VER_MINOR 14U
+#define VER_MINOR 15U
/* */
/* */
/* */
-/* (C) 2000-2006 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
+attr_t GetAttr (unsigned Addr)
+/* Return the attribute for the given address */
+{
+ /* Check the given address */
+ AddrCheck (Addr);
+
+ /* Return the attribute */
+ return AttrTab[Addr];
+}
+
+
+
int SegmentDefined (unsigned Start, unsigned End)
/* Return true if the atSegment bit is set somewhere in the given range */
{
-int HaveSegmentChange (unsigned Addr)
-/* Return true if the segment change attribute is set for the given address */
+int IsSegmentEnd (unsigned Addr)
+/* Return true if a segment ends at the given address */
{
- /* Check the given address */
- AddrCheck (Addr);
+ return (GetAttr (Addr) & atSegmentEnd) != 0x0000;
+}
- /* Return the attribute */
- return (AttrTab[Addr] & atSegmentChange) != 0;
+
+
+int IsSegmentStart (unsigned Addr)
+/* Return true if a segment starts at the given address */
+{
+ return (GetAttr (Addr) & atSegmentStart) != 0x0000;
}
-attr_t GetAttr (unsigned Addr)
-/* Return the attribute for the given address */
-{
- /* Check the given address */
- AddrCheck (Addr);
-
- /* Return the attribute */
- return AttrTab[Addr];
-}
-
-
-
attr_t GetStyleAttr (unsigned Addr)
/* Return the style attribute for the given address */
{
/* */
/* */
/* */
-/* (C) 2000-2006 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
typedef enum attr_t {
/* Styles */
- atDefault = 0x0000, /* Default style */
- atCode = 0x0001,
- atIllegal = 0x0002,
- atByteTab = 0x0003, /* Same as illegal */
- atDByteTab = 0x0004,
- atWordTab = 0x0005,
- atDWordTab = 0x0006,
- atAddrTab = 0x0007,
- atRtsTab = 0x0008,
- atTextTab = 0x0009,
- atSkip = 0x000A, /* Skip code completely */
+ atDefault = 0x0000, /* Default style */
+ atCode = 0x0001,
+ atIllegal = 0x0002,
+ atByteTab = 0x0003, /* Same as illegal */
+ atDByteTab = 0x0004,
+ atWordTab = 0x0005,
+ atDWordTab = 0x0006,
+ atAddrTab = 0x0007,
+ atRtsTab = 0x0008,
+ atTextTab = 0x0009,
+ atSkip = 0x000A, /* Skip code completely */
/* Label flags */
- atNoLabel = 0x0000, /* No label for this address */
- atExtLabel = 0x0010, /* External label */
- atIntLabel = 0x0020, /* Internally generated label */
- atDepLabel = 0x0040, /* Dependent label */
- atUnnamedLabel = 0x0080, /* Unnamed label */
+ atNoLabel = 0x0000, /* No label for this address */
+ atExtLabel = 0x0010, /* External label */
+ atIntLabel = 0x0020, /* Internally generated label */
+ atDepLabel = 0x0040, /* Dependent label */
+ atUnnamedLabel = 0x0080, /* Unnamed label */
- atLabelDefined = 0x0100, /* True if we defined the label */
+ atLabelDefined = 0x0100, /* True if we defined the label */
- atStyleMask = 0x000F, /* Output style */
- atLabelMask = 0x00F0, /* Label information */
+ atStyleMask = 0x000F, /* Output style */
+ atLabelMask = 0x00F0, /* Label information */
/* Segment */
- atSegment = 0x0100, /* Code is in a segment */
- atSegmentChange = 0x0200, /* Either segment start or segment end */
+ atSegment = 0x0100, /* Code is in a segment */
+ atSegmentEnd = 0x0200, /* Segment end */
+ atSegmentStart = 0x0400, /* Segment start */
} attr_t;
void AddrCheck (unsigned Addr);
/* Check if the given address has a valid range */
+attr_t GetAttr (unsigned Addr);
+/* Return the attribute for the given address */
+
int SegmentDefined (unsigned Start, unsigned End);
/* Return true if the atSegment bit is set somewhere in the given range */
-int HaveSegmentChange (unsigned Addr);
-/* Return true if the segment change attribute is set for the given address */
+int IsSegmentEnd (unsigned Addr);
+/* Return true if a segment ends at the given address */
+
+int IsSegmentStart (unsigned Addr);
+/* Return true if a segment starts at the given address */
unsigned GetGranularity (attr_t Style);
/* Get the granularity for the given style */
void MarkAddr (unsigned Addr, attr_t Attr);
/* Mark an address with an attribute */
-attr_t GetAttr (unsigned Addr);
-/* Return the attribute for the given address */
-
attr_t GetStyleAttr (unsigned Addr);
/* Return the style attribute for the given address */
/* End of attrtab.h */
-
#endif
/* */
/* */
/* */
-/* (C) 2000-2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
attr_t Attr;
if (MustDefLabel(PC+Count)) {
break;
- }
+ }
Attr = GetAttr (PC+Count);
if ((Attr & atStyleMask) != Style) {
break;
}
- if ((Attr & atSegmentChange)) {
+ if ((Attr & (atSegmentStart | atSegmentEnd))) {
break;
}
++Count;
/* */
/* */
/* */
-/* (C) 2000-2011, Ullrich von Bassewitz */
+/* (C) 2000-2014, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
if (Start < 0) {
InfoError ("Start address is missing");
}
- if (Start == End) {
- InfoError ("Segment is empty");
- }
if (Start > End) {
InfoError ("Start address of segment is greater than end address");
}
/* Check that segments do not overlap */
if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
- InfoError ("Segments cannot overlap");
+ InfoError ("Segments must not overlap");
}
/* Remember the segment data */
/* */
/* */
/* */
-/* (C) 1998-2011, Ullrich von Bassewitz */
+/* (C) 1998-2014, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include "opctable.h"
#include "output.h"
#include "scanner.h"
+#include "segment.h"
static void OneOpcode (unsigned RemainingBytes)
/* Disassemble one opcode */
{
+ unsigned I;
+
/* Get the opcode from the current address */
unsigned char OPC = GetCodeByte (PC);
/* Get the output style for the current PC */
attr_t Style = GetStyleAttr (PC);
+ /* If a segment begins here, then name that segment.
+ ** Note that the segment is named even if its code is being skipped,
+ ** because some of its later code might not be skipped.
+ */
+ if (IsSegmentStart (PC)) {
+ StartSegment (GetSegmentStartName (PC), GetSegmentAddrSize (PC));
+ }
+
/* If we have a label at this address, output the label and an attached
** comment, provided that we aren't in a skip area.
*/
** - ...if we have enough bytes remaining for the code at this address.
** - ...if the current instruction is valid for the given CPU.
** - ...if there is no label somewhere between the instruction bytes.
- ** If any of these conditions is false, switch to data mode.
+ ** - ...if there is no segment change between the instruction bytes.
+ ** If any one of those conditions is false, switch to data mode.
*/
if (Style == atDefault) {
if (D->Size > RemainingBytes) {
Style = atIllegal;
MarkAddr (PC, Style);
} else {
- unsigned I;
- for (I = 1; I < D->Size; ++I) {
- if (HaveLabel (PC+I) || HaveSegmentChange (PC+I)) {
+ for (I = PC + D->Size; --I > PC; ) {
+ if (HaveLabel (I) || IsSegmentStart (I)) {
+ Style = atIllegal;
+ MarkAddr (PC, Style);
+ break;
+ }
+ }
+ for (I = 0; I < D->Size - 1u; ++I) {
+ if (IsSegmentEnd (PC + I)) {
Style = atIllegal;
MarkAddr (PC, Style);
break;
*/
if (D->Size <= RemainingBytes) {
/* Output labels within the next insn */
- unsigned I;
for (I = 1; I < D->Size; ++I) {
ForwardLabel (I);
}
DataByteLine (1);
++PC;
break;
+ }
+ /* Change back to the default CODE segment if
+ ** a named segment stops at the current address.
+ */
+ for (I = D->Size; I >= 1; --I) {
+ if (IsSegmentEnd (PC - I)) {
+ EndSegment ();
+ break;
+ }
}
}
/* */
/* */
/* */
-/* (C) 2000-2009, Ullrich von Bassewitz */
+/* (C) 2000-2014, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
static unsigned Line = 0; /* Current line on page */
static unsigned Page = 1; /* Current output page */
+static const char* SegmentName = 0; /* Name of current segment */
+
/*****************************************************************************/
-void StartSegment (const char* Name, unsigned AddrSize)
-/* Start a segment */
-{
- if (Pass == PassCount) {
- Output (".segment");
- Indent (ACol);
- if (AddrSize == ADDR_SIZE_DEFAULT) {
- Output ("\"%s\"", Name);
- } else {
- Output ("\"%s\": %s", Name, AddrSizeToStr (AddrSize));
- }
- LineFeed ();
- }
-}
-
-
-
void DataByteLine (unsigned ByteCount)
/* Output a line with bytes */
{
+void StartSegment (const char* Name, unsigned AddrSize)
+/* Start a segment */
+{
+ if (Pass == PassCount) {
+ LineFeed ();
+ Output (".segment");
+ Indent (ACol);
+ SegmentName = Name;
+ Output ("\"%s\"", Name);
+ if (AddrSize != ADDR_SIZE_DEFAULT) {
+ Output (": %s", AddrSizeToStr (AddrSize));
+ }
+ LineFeed ();
+ LineFeed ();
+ }
+}
+
+
+
+void EndSegment (void)
+/* End a segment */
+{
+ LineFeed ();
+ Output ("; End of \"%s\" segment", SegmentName);
+ LineFeed ();
+ SeparatorLine ();
+ Output (".code");
+ LineFeed ();
+ LineFeed ();
+}
+
+
+
void UserComment (const char* Comment)
/* Output a comment line */
{
/* */
/* */
/* */
-/* (C) 2000-2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
void DefConst (const char* Name, const char* Comment, unsigned Addr);
/* Define an address constant */
-
-void StartSegment (const char* Name, unsigned AddrSize);
-/* Start a segment */
-
-void EndSegment (void);
-/* End a segment */
void OneDataByte (void);
/* Output a .byte line with the current code byte */
void SeparatorLine (void);
/* Print a separator line */
+void StartSegment (const char* Name, unsigned AddrSize);
+/* Start a segment */
+
+void EndSegment (void);
+/* End a segment */
+
void UserComment (const char* Comment);
/* Output a comment line */
/* End of output.h */
-
#endif
/* */
/* */
/* */
-/* (C) 2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2007-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
typedef struct Segment Segment;
struct Segment {
Segment* NextStart; /* Pointer to next segment */
- Segment* NextEnd; /* Pointer to next segment */
unsigned long Start;
- unsigned long End;
unsigned AddrSize;
char Name[1]; /* Name, dynamically allocated */
};
-/* Tables containing the segments. A segment is inserted using it's hash
-** value. Collision is done by single linked lists.
+/* Table containing the segments. A segment is inserted using its hash
+** value. Collisions are handled by single-linked lists.
*/
static Segment* StartTab[HASH_SIZE]; /* Table containing segment starts */
-static Segment* EndTab[HASH_SIZE]; /* Table containing segment ends */
/* Fill in the data */
S->Start = Start;
- S->End = End;
S->AddrSize = ADDR_SIZE_ABS;
memcpy (S->Name, Name, Len + 1);
- /* Insert the segment into the hash tables */
+ /* Insert the segment into the hash table */
S->NextStart = StartTab[Start % HASH_SIZE];
StartTab[Start % HASH_SIZE] = S;
- S->NextEnd = EndTab[End % HASH_SIZE];
- EndTab[End % HASH_SIZE] = S;
/* Mark start and end of the segment */
- MarkAddr (Start, atSegmentChange);
- MarkAddr (End, atSegmentChange);
+ MarkAddr (Start, atSegmentStart);
+ MarkAddr (End, atSegmentEnd);
/* Mark the addresses within the segment */
MarkRange (Start, End, atSegment);
}
+
+
+
+char* GetSegmentStartName (unsigned Addr)
+/* Return the name of the segment which starts at the given address */
+{
+ Segment* S = StartTab[Addr % HASH_SIZE];
+
+ /* Search the collision list for the exact address */
+ while (S != 0) {
+ if (S->Start == Addr) {
+ return S->Name;
+ }
+ S = S->NextStart;
+ }
+
+ return 0;
+}
+
+
+
+unsigned GetSegmentAddrSize (unsigned Addr)
+/* Return the address size of the segment which starts at the given address */
+{
+ Segment* S = StartTab[Addr % HASH_SIZE];
+
+ /* Search the collision list for the exact address */
+ while (S != 0) {
+ if (S->Start == Addr) {
+ return S->AddrSize;
+ }
+ S = S->NextStart;
+ }
+
+ return 0;
+}
/* */
/* */
/* */
-/* (C) 2007 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2007-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
void AddAbsSegment (unsigned Start, unsigned End, const char* Name);
/* Add an absolute segment to the segment table */
+char* GetSegmentStartName (unsigned Addr);
+/* Return the name of the segment which starts at the given address */
+
+unsigned GetSegmentAddrSize (unsigned Addr);
+/* Return the address size of the segment which starts at the given address */
-/* End of segment.h */
+/* End of segment.h */
#endif
ExecCmd (&Args, MainCmds, sizeof (MainCmds) / sizeof (MainCmds[0]));
}
- /* Loop til program end */
+ /* Loop until program end */
while (!Terminate) {
/* Output a prompt, then read the input */
unsigned CfgProcess (void)
-/* Process the config file after reading in object files and libraries. This
-** includes postprocessing of the config file data but also assigning segments
-** and defining segment/memory area related symbols. The function will return
-** the number of memory area overflows (so zero means anything went ok).
+/* Process the config file, after reading in object files and libraries. This
+** includes postprocessing of the config file data; but also assigning segments,
+** and defining segment/memory-area related symbols. The function will return
+** the number of memory area overflows (so, zero means everything went OK).
** In case of overflows, a short mapfile can be generated later, to ease the
-** task of rearranging segments for the user.
+** user's task of re-arranging segments.
*/
{
unsigned Overflows = 0;
/* Postprocess segments */
ProcessSegments ();
- /* Walk through each of the memory sections. Add up the sizes and check
+ /* Walk through each of the memory sections. Add up the sizes; and, check
** for an overflow of the section. Assign the start addresses of the
- ** segments while doing this.
+ ** segments while doing that.
*/
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
-
unsigned J;
unsigned long Addr;
/* Remember if this is a relocatable memory area */
M->Relocatable = RelocatableBinFmt (M->F->Format);
- /* Resolve the start address expression, remember the start address
+ /* Resolve the start address expression, remember the start address,
** and mark the memory area as placed.
*/
if (!IsConstExpr (M->StartExpr)) {
/* Walk through the segments in this memory area */
for (J = 0; J < CollCount (&M->SegList); ++J) {
-
/* Get the segment */
SegDesc* S = CollAtUnchecked (&M->SegList, J);
/* Remember the start address before handling this segment */
unsigned long StartAddr = Addr;
- /* Some actions depend on wether this is the load or run memory
+ /* Some actions depend on whether this is the load or run memory
** area.
*/
if (S->Run == M) {
-
/* This is the run (and maybe load) memory area. Handle
** alignment and explict start address and offset.
*/
/* If the first segment placed in the memory area needs
** fill bytes for the alignment, emit a warning, since
- ** this is somewhat suspicious.
+ ** that is somewhat suspicious.
*/
if (M->FillLevel == 0 && NewAddr > Addr) {
CfgWarning (GetSourcePos (S->LI),
/* Use the aligned address */
Addr = NewAddr;
- } else if (S->Flags & (SF_OFFSET | SF_START)) {
+ } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
+ (M->Flags & MF_OVERFLOW) == 0) {
/* Give the segment a fixed starting address */
unsigned long NewAddr = S->Addr;
+
if (S->Flags & SF_OFFSET) {
/* An offset was given, no address, make an address */
NewAddr += M->Start;
}
- if (Addr > NewAddr) {
+ if (NewAddr < Addr) {
/* Offset already too large */
+ ++Overflows;
if (S->Flags & SF_OFFSET) {
- CfgError (GetSourcePos (M->LI),
- "Offset too small in `%s', segment `%s'",
- GetString (M->Name),
- GetString (S->Name));
+ CfgWarning (GetSourcePos (S->LI),
+ "Segment `%s' offset is too small in `%s' by %lu byte%c",
+ GetString (S->Name), GetString (M->Name),
+ Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
} else {
- CfgError (GetSourcePos (M->LI),
- "Start address too low in `%s', segment `%s'",
- GetString (M->Name),
- GetString (S->Name));
+ CfgWarning (GetSourcePos (S->LI),
+ "Segment `%s' start address is too low in `%s' by %lu byte%c",
+ GetString (S->Name), GetString (M->Name),
+ Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
}
+ } else {
+ Addr = NewAddr;
}
- Addr = NewAddr;
}
/* Set the start address of this segment, set the readonly flag
- ** in the segment and and remember if the segment is in a
+ ** in the segment, and remember if the segment is in a
** relocatable file or not.
*/
S->Seg->PC = Addr;
S->Seg->MemArea = M;
} else if (S->Load == M) {
-
- /* This is the load memory area, *and* run and load are
+ /* This is the load memory area; *and*, run and load are
** different (because of the "else" above). Handle alignment.
*/
if (S->Flags & SF_ALIGN_LOAD) {
/* Align the address */
Addr = AlignAddr (Addr, S->LoadAlignment);
}
-
}
- /* If this is the load memory area and the segment doesn't have a
+ /* If this is the load memory area, and the segment doesn't have a
** fill value defined, use the one from the memory area.
*/
if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
S->Seg->FillVal = M->FillVal;
}
- /* Increment the fill level of the memory area and check for an
+ /* Increment the fill level of the memory area; and, check for an
** overflow.
*/
M->FillLevel = Addr + S->Seg->Size - M->Start;
++Overflows;
M->Flags |= MF_OVERFLOW;
CfgWarning (GetSourcePos (M->LI),
- "Memory area overflow in `%s', segment `%s' (%lu bytes)",
- GetString (M->Name), GetString (S->Name),
- M->FillLevel - M->Size);
+ "Segment `%s' overflows memory area `%s' by %lu byte%c",
+ GetString (S->Name), GetString (M->Name),
+ M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
}
/* If requested, define symbols for the start and size of the
((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
M->F->Size += Addr - StartAddr;
}
-
}
- /* If requested, define symbols for start, size and offset of the
+ /* If requested, define symbols for start, size, and offset of the
** memory area
*/
if (M->Flags & MF_DEFINE) {
SB_Done (&Buf);
}
- /* If we didn't have an overflow and are requested to fill the memory
- ** area, acount for that in the file size.
+ /* If we didn't have an overflow, and are requested to fill the memory
+ ** area, account for that in the file size.
*/
if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
M->F->Size += (M->Size - M->FillLevel);
if (MapFileName) {
CreateMapFile (SHORT_MAPFILE);
}
- Error ("Cannot generate output due to memory area overflow%s",
- (MemoryAreaOverflows > 1)? "s" : "");
+ Error ("Cannot generate most of the files due to memory area overflow%c",
+ (MemoryAreaOverflows > 1) ? 's' : ' ');
}
/* Create the output file */
/* Close the file */
fclose (F);
- Print (stdout, 1, "Loaded `%s' at $0200-$%04X\n", ProgramFile, Addr - 1);
+ Print (stderr, 1, "Loaded `%s' at $0200-$%04X\n", ProgramFile, Addr - 1);
}
ExecuteInsn ();
if (MaxCycles && (GetCycles () >= MaxCycles)) {
Error ("Maximum number of cycles reached.");
- exit (-99); /* do not ues EXIT_FAILURE to avoid conflicts with the
+ exit (-99); /* do not use EXIT_FAILURE to avoid conflicts with the
same value being used in a test program */
}
}
unsigned SP = MemReadZPWord (0x00);
unsigned Args = SP - (ArgC + 1) * 2;
- Print (stdout, 2, "PVArgs ($%04X)\n", ArgV);
+ Print (stderr, 2, "PVArgs ($%04X)\n", ArgV);
MemWriteWord (ArgV, Args);
static void PVExit (CPURegs* Regs)
{
- Print (stdout, 1, "PVExit ($%02X)\n", Regs->AC);
+ Print (stderr, 1, "PVExit ($%02X)\n", Regs->AC);
exit (Regs->AC);
}
}
while (Path[I++]);
- Print (stdout, 2, "PVOpen (\"%s\", $%04X)\n", Path, Flags);
+ Print (stderr, 2, "PVOpen (\"%s\", $%04X)\n", Path, Flags);
switch (Flags & 0x03) {
case 0x01:
unsigned FD = GetAX (Regs);
- Print (stdout, 2, "PVClose ($%04X)\n", FD);
+ Print (stderr, 2, "PVClose ($%04X)\n", FD);
RetVal = close (FD);
unsigned Buf = PopParam (2);
unsigned FD = PopParam (2);
- Print (stdout, 2, "PVRead ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
+ Print (stderr, 2, "PVRead ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
Data = xmalloc (Count);
unsigned Buf = PopParam (2);
unsigned FD = PopParam (2);
- Print (stdout, 2, "PVWrite ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
+ Print (stderr, 2, "PVWrite ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
Data = xmalloc (Count);
while (I < Count) {
-# toplevel makefile for the regression tests
+# top-level makefile for the regression tests
-MAKE := make --no-print-dir
+# You can comment this special target when you debug the regression tests.
+# Then, make will give you more progress reports.
+.SILENT:
ifneq ($(shell echo),)
- CMD_EXE = 1
+ CMD_EXE := 1
endif
ifdef CMD_EXE
- RM := del /f
EXE := .exe
- MKDIR = mkdir
- RMDIR = rmdir
+ DEL = -del /f $(subst /,\,$1)
+ MKDIR = mkdir $(subst /,\,$1)
+ RMDIR = -rmdir /s /q $(subst /,\,$1)
else
- RM := rm -f
EXE :=
- MKDIR = mkdir -p
- RMDIR = rmdir
+ DEL = $(RM) $1
+ MKDIR = mkdir $1
+ RMDIR = $(RM) -r $1
endif
WORKDIR := ../testwrk
-.PHONY: dotests clean
+CC := gcc
+
+.PHONY: all dotests continue mostly-clean clean
all: dotests
$(WORKDIR):
- @$(MKDIR) $(WORKDIR)
+ $(call MKDIR,$(WORKDIR))
+
+$(WORKDIR)/bdiff$(EXE): bdiff.c | $(WORKDIR)
+ $(CC) -O2 -o $@ $<
-$(WORKDIR)/bdiff$(EXE): $(WORKDIR)
- @$(CC) -o $(WORKDIR)/bdiff$(EXE) bdiff.c
+.NOTPARALLEL:
-dotests: $(WORKDIR)/bdiff$(EXE)
- @$(MAKE) -C val clean all
- @$(MAKE) -C ref clean all
- @$(MAKE) -C err clean all
- @$(MAKE) -C misc clean all
+dotests: mostly-clean continue
continue: $(WORKDIR)/bdiff$(EXE)
@$(MAKE) -C val all
@$(MAKE) -C err all
@$(MAKE) -C misc all
-clean:
+mostly-clean:
@$(MAKE) -C val clean
@$(MAKE) -C ref clean
@$(MAKE) -C err clean
@$(MAKE) -C misc clean
- @$(RM) $(WORKDIR)/bdiff$(EXE)
- @$(RMDIR) $(WORKDIR)
+
+clean: mostly-clean
+ @$(call DEL,$(WORKDIR)/bdiff$(EXE))
+ @$(call RMDIR,$(WORKDIR))
-
# makefile for the tests that MUST NOT compile
ifneq ($(shell echo),)
- CMD_EXE = 1
+ CMD_EXE := 1
endif
-CC65FLAGS = -t sim6502
-
-CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
-
ifdef CMD_EXE
-RM := del /f
+ NOT := - # Hack
+ DEL = -del /f $(subst /,\,$1)
else
-RM := rm -f
+ NOT := !
+ DEL = $(RM) $1
endif
-WORKDIR := ./../../testwrk
+CC65 := $(if $(wildcard ../../bin/cc65*),../../bin/cc65,cc65)
+
+WORKDIR := ../../testwrk
.PHONY: all clean
-SOURCES := $(wildcard *.c)
-TESTS := $(SOURCES:%.c=$(WORKDIR)/%.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.o.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.os.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.or.prg)
+TESTS := $(patsubst %.c,$(WORKDIR)/%.s,$(wildcard *.c))
all: $(TESTS)
-$(WORKDIR)/%.prg: %.c
- ! $(CL65) $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.o.prg: %.c
- ! $(CL65) -O $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.os.prg: %.c
- ! $(CL65) -Os $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.osi.prg: %.c
- ! $(CL65) -Osi $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.osir.prg: %.c
- ! $(CL65) -Osir $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.oi.prg: %.c
- ! $(CL65) -Oi $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.oir.prg: %.c
- ! $(CL65) -Oir $(CC65FLAGS) $< -o $@
-$(WORKDIR)/%.or.prg: %.c
- ! $(CL65) -Or $(CC65FLAGS) $< -o $@
+$(WORKDIR)/%.s: %.c
+ $(NOT) $(CC65) -o $@ $<
+
clean:
- @$(RM) $(TESTS)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.o)
+ @$(call DEL,$(TESTS))
#include <assert.h>
#include <string.h>
+#include <stdio.h>
typedef unsigned char U8;
char var = 0xf0;
char fn(char bar)
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ ++p; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = &func - p; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = func - p; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = (p > &func); /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = (p > func); /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = func - func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = func - &func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = &func - func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = &func - &func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = p - &func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+ n = p - func; /* invalid C */
+
+ return 0;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! global non-static and static conflicts
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+/*
+ see: https://github.com/cc65/cc65/issues/191
+*/
+
+#pragma warn(error, on)
+
+int n;
+static int n; /* should give an error */
+
+int main(void)
+{
+ return n;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! global non-static and static conflicts
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+/*
+ see: https://github.com/cc65/cc65/issues/191
+*/
+
+#pragma warn(error, on)
+
+extern int n;
+static int n; /* should give an error */
+
+int main(void)
+{
+ return n;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! global non-static and static conflicts
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+/*
+ see: https://github.com/cc65/cc65/issues/191
+*/
+
+#pragma warn(error, on)
+
+static int n;
+int n; /* should give an error */
+
+int main(void)
+{
+ return n;
+}
# makefile for the remaining tests that need special care in one way or another
ifneq ($(shell echo),)
- CMD_EXE = 1
+ CMD_EXE := 1
endif
-CC65FLAGS = -t sim6502
-SIM65FLAGS = -x 200000000
-
-CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
-SIM65 := $(if $(wildcard ../../bin/sim65*),../../bin/sim65,sim65)
-
ifdef CMD_EXE
-RM := del /f
+ S := $(subst /,\,/)
+ NOT := - # Hack
+ DEL = -del /f $(subst /,\,$1)
else
-RM := rm -f
+ S := /
+ NOT := !
+ DEL = $(RM) $1
endif
-WORKDIR := ./../../testwrk
+CC65FLAGS := -t sim6502
+SIM65FLAGS := -x 200000000
+
+CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
+SIM65 := $(if $(wildcard ../../bin/sim65*),..$S..$Sbin$Ssim65,sim65)
+WORKDIR := ..$S..$Stestwrk
DIFF := $(WORKDIR)/bdiff
.PHONY: all clean
SOURCES := $(wildcard *.c)
-TESTS := $(SOURCES:%.c=$(WORKDIR)/%.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.o.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.os.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.or.prg)
-
-# FIXME: actually use/build differently optimized programs here
+TESTS := $(foreach option,. .o. .os. .osi. .osir. .oi. .oir. .or.,$(SOURCES:%.c=$(WORKDIR)/%$(option)prg))
all: $(TESTS)
# should compile, but then hangs in an endless loop
$(WORKDIR)/endless%prg: endless.c
- $(CL65) $(CC65FLAGS) $< -o $@
- ! $(SIM65) $(SIM65FLAGS) $@
+ $(CL65) $(subst .,,$(*:.o%=-O%)) $(CC65FLAGS) $< -o $@
+ $(NOT) $(SIM65) $(SIM65FLAGS) $@
-# these need reference data that cant be generated by a host compiled program
+# these need reference data that can't be generated by a host-compiled program,
# in a useful way
$(WORKDIR)/limits%prg: limits.c
- $(CL65) $(CC65FLAGS) $< -o $@
+ $(CL65) $(subst .,,$(*:.o%=-O%)) $(CC65FLAGS) $< -o $@
$(SIM65) $(SIM65FLAGS) $@ > $(WORKDIR)/limits.out
$(DIFF) $(WORKDIR)/limits.out limits.ref
# the rest are tests that fail currently for one reason or another
$(WORKDIR)/fields%prg: fields.c
- @echo "FIXME: " $@ "will currently fail"
- $(CL65) $(CC65FLAGS) $< -o $@
+ @echo "FIXME: " $@ "currently will fail."
+ $(CL65) $(subst .,,$(*:.o%=-O%)) $(CC65FLAGS) $< -o $@
-$(SIM65) $(SIM65FLAGS) $@
$(WORKDIR)/sitest%prg: sitest.c
- @echo "FIXME: " $@ "will currently fail"
- -$(CL65) $(CC65FLAGS) $< -o $@
+ @echo "FIXME: " $@ "currently will fail."
+ -$(CL65) $(subst .,,$(*:.o%=-O%)) $(CC65FLAGS) $< -o $@
+# -$(SIM65) $(SIM65FLAGS) $@
+$(WORKDIR)/cc65141011%prg: cc65141011.c
+ @echo "FIXME: " $@ "currently can fail."
+ $(CL65) $(subst .,,$(*:.o%=-O%)) $(CC65FLAGS) $< -o $@
-$(SIM65) $(SIM65FLAGS) $@
clean:
- @$(RM) $(TESTS)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.o)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.out)
-
-
+ @$(call DEL,$(TESTS))
+ @$(call DEL,$(SOURCES:.c=.o))
+ @$(call DEL,$(SOURCES:%.c=$(WORKDIR)/%.out))
--- /dev/null
+/*
+ !!DESCRIPTION!! equality problem
+ !!ORIGIN!! Testsuite
+ !!LICENCE!! Public Domain
+*/
+
+/*
+ Different results, depending on whether constant is on left or right side.
+
+ The optimizer sometimes makes code that executes the right-side expression
+ as eight bits; but then, tests it against the left-side zero as 16 bits.
+ The high-byte is garbage; therefore, that test might, or might not, work.
+ It depends on the platform and the amount of optimization.
+
+ http://www.cc65.org/mailarchive/2014-10/11680.html
+ http://www.cc65.org/mailarchive/2014-10/11682.html
+ http://www.cc65.org/mailarchive/2014-10/11683.html
+*/
+
+#include <stdio.h>
+
+static unsigned char fails = 4;
+static unsigned char bad[3], good[3];
+
+int main(void)
+{
+ unsigned char joy_state = 0x7e;
+ unsigned a, b;
+
+ /* NOTE: It fails in only the printf() statements, the other stuff
+ below works! */
+ printf("bad: %u, ", 0 == (joy_state & 1) );
+ printf("good: %u\n", (joy_state & 1) == 0 );
+
+ sprintf(bad, "%u", 0 == (joy_state & 1) );
+ sprintf(good, "%u", (joy_state & 1) == 0 );
+
+ printf("bad: %u, ", bad[0] - '0' );
+ printf("good: %u\n", good[0] - '0' );
+
+ fails -= bad[0] - '0';
+ fails -= good[0] - '0';
+
+ if (0 == (joy_state & 1)) fails--;
+ if ((joy_state & 1) == 0) fails--;
+
+ printf("failures: %u\n", fails );
+
+ /* The above printf() returns a value with a zero high-byte.
+ ** Therefore, the next (broken) statement works (by accident).
+ */
+ a = 0 == (joy_state & 1);
+ b = (joy_state & 1) == 0;
+
+ printf("a: %u, ", a );
+ printf("b: %u\n", b );
+
+ return fails;
+}
# compared with reference output
ifneq ($(shell echo),)
- CMD_EXE = 1
+ CMD_EXE := 1
endif
-CC65FLAGS = -t sim6502
-SIM65FLAGS = -x 200000000
-
-CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
-SIM65 := $(if $(wildcard ../../bin/sim65*),../../bin/sim65,sim65)
-
ifdef CMD_EXE
-RM := del /f
+ S := $(subst /,\,/)
+ DEL = -del /f $(subst /,\,$1)
else
-RM := rm -f
+ S := /
+ DEL = $(RM) $1
endif
-WORKDIR := ./../../testwrk
+CC65FLAGS := -t sim6502
+SIM65FLAGS := -x 200000000
+CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
+SIM65 := $(if $(wildcard ../../bin/sim65*),..$S..$Sbin$Ssim65,sim65)
+
+WORKDIR := ..$S..$Stestwrk
DIFF := $(WORKDIR)/bdiff
+CC := gcc
CFLAGS := -O2 -Wall -W -Wextra -fwrapv -fno-strict-overflow
.PHONY: all clean
-REFS := $(patsubst %.c,$(WORKDIR)/%.ref,$(wildcard *.c))
-
SOURCES := $(wildcard *.c)
-TESTS := $(SOURCES:%.c=$(WORKDIR)/%.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.o.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.os.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.or.prg)
+REFS := $(SOURCES:%.c=$(WORKDIR)/%.ref)
+TESTS := $(foreach option,. .o. .os. .osi. .osir. .oi. .oir. .or.,$(SOURCES:%.c=$(WORKDIR)/%$(option)prg))
all: $(REFS) $(TESTS)
$(WORKDIR)/%.ref: %.c
$(CC) $(CFLAGS) $< -o $(WORKDIR)/$*.host
- $(WORKDIR)/$*.host > $@
+ $(WORKDIR)$S$*.host > $@
+
+# Some files have "K & R"-style syntax. Therefore, some forward
+# function-declarations don't match the later function definitions.
+# Those programs fail when fastcall is used; but, the cdecl calling convention
+# tolerates those conflicts. Therefore, make their functions default to cdecl.
+#
+$(WORKDIR)/init%prg: CC65FLAGS += -Wc --all-cdecl
+$(WORKDIR)/switch.%rg: CC65FLAGS += -Wc --all-cdecl
+$(WORKDIR)/yacc.%rg: CC65FLAGS += -Wc --all-cdecl
+$(WORKDIR)/yaccdbg%prg: CC65FLAGS += -Wc --all-cdecl
$(WORKDIR)/%.prg: %.c $(WORKDIR)/%.ref
$(CL65) $(CC65FLAGS) $< -o $@
$(DIFF) $(WORKDIR)/$*.out $(WORKDIR)/$*.ref
clean:
- @$(RM) $(TESTS)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.o)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.out)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.ref)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.host)
+ @$(call DEL,$(TESTS))
+ @$(call DEL,$(SOURCES:.c=.o))
+ @$(call DEL,$(SOURCES:%.c=$(WORKDIR)/%.out))
+ @$(call DEL,$(SOURCES:%.c=$(WORKDIR)/%.ref))
+ @$(call DEL,$(SOURCES:%.c=$(WORKDIR)/%.host))
} else {
/* why not using a function pointer ? */
f = &fact;
- print_num((*(long (*)())f)(n), base);
+ print_num((*(long (*)(int))f)(n), base);
}
printf("\n");
return 0;
# makefile for the regression tests that return an error code on failure
ifneq ($(shell echo),)
- CMD_EXE = 1
+ CMD_EXE := 1
endif
-CC65FLAGS = -t sim6502
-SIM65FLAGS = -x 200000000
-
-CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
-SIM65 := $(if $(wildcard ../../bin/sim65*),../../bin/sim65,sim65)
-
ifdef CMD_EXE
-RM := del /f
+ DEL = -del /f $(subst /,\,$1)
else
-RM := rm -f
+ DEL = $(RM) $1
endif
-WORKDIR := ./../../testwrk
+CC65FLAGS := -t sim6502
+SIM65FLAGS := -x 200000000
+
+CL65 := $(if $(wildcard ../../bin/cl65*),../../bin/cl65,cl65)
+SIM65 := $(if $(wildcard ../../bin/sim65*),../../bin/sim65,sim65)
+
+WORKDIR := ../../testwrk
.PHONY: all clean
SOURCES := $(wildcard *.c)
-TESTS := $(SOURCES:%.c=$(WORKDIR)/%.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.o.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.os.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.osir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oi.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.oir.prg)
-TESTS += $(SOURCES:%.c=$(WORKDIR)/%.or.prg)
+TESTS := $(foreach option,. .o. .os. .osi. .osir. .oi. .oir. .or.,$(SOURCES:%.c=$(WORKDIR)/%$(option)prg))
all: $(TESTS)
+# Some files have "K & R"-style syntax. Therefore, some forward
+# function-declarations don't match the later function definitions.
+# Those programs fail when fastcall is used; but, the cdecl calling convention
+# tolerates those conflicts. Therefore, make their functions default to cdecl.
+#
+$(WORKDIR)/cq4%prg $(WORKDIR)/cq71.%rg $(WORKDIR)/cq81%prg $(WORKDIR)/cq84%prg: CC65FLAGS += -Wc --all-cdecl
+
$(WORKDIR)/%.prg: %.c
$(CL65) $(CC65FLAGS) $< -o $@
$(SIM65) $(SIM65FLAGS) $@
$(SIM65) $(SIM65FLAGS) $@
clean:
- @$(RM) $(TESTS)
- @$(RM) $(SOURCES:%.c=$(WORKDIR)/%.o)
+ @$(call DEL,$(TESTS))
+ @$(call DEL,$(SOURCES:.c=.o))
--- /dev/null
+
+/*
+ !!DESCRIPTION!! Addition tests - mostly int's
+ !!ORIGIN!! SDCC regression tests
+ !!LICENCE!! GPL, read COPYING.GPL
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static unsigned int failures = 0;
+
+/*
+ this test assumes:
+ sizeof(long) == 4
+
+ CAUTION: the wraparound behaviour is actually undefined, to get the "expected"
+ behaviour with GCC, use -fwrapv or -fno-strict-overflow
+
+ see: https://gcc.gnu.org/wiki/FAQ#signed_overflow
+*/
+
+#ifdef REFERENCE
+
+/*
+ make sure the reference output uses types with
+ proper size
+*/
+
+#include <stdint.h>
+
+int32_t long0 = 0;
+
+#else
+
+long long0 = 0;
+
+#endif
+
+void print(void)
+{
+#if defined(REFERENCE) && defined(REFCC_SIZEOF_LONG_64BIT)
+ printf("long0: %d\n", long0);
+#else
+ printf("long0: %ld\n", long0);
+#endif
+}
+
+int main(void)
+{
+ long0 = 0x7f000000L;
+ /* wrap around zero */
+ print();
+ long0 = long0 + 0x2000000L;
+ if(long0 != -0x7f000000L) {
+ printf("failed!\n");
+ failures++;
+ }
+ print();
+
+ long0 = 0x7f000000L;
+ /* wrap around zero */
+ print();
+ long0 = long0 + 0x2000000L;
+ print();
+ if(long0 != -0x7f000000L) {
+ printf("failed!\n");
+ failures++;
+ }
+ print();
+
+ return failures;
+}
--- /dev/null
+/*
+** !!DESCRIPTION!! Simple tests about adding pointers and offsets
+** !!ORIGIN!! cc65 regression tests
+** !!LICENCE!! Public Domain
+** !!AUTHOR!! 2016-01-01, Greg King
+*/
+
+#include <stdio.h>
+
+static unsigned char failures = 0;
+
+static char array[16];
+
+static char *cPtr;
+static int *iPtr;
+static long *lPtr;
+
+/* These functions test: adding an offset variable to a pointer variable. */
+
+static void cPointer_char(void)
+{
+ char *cP = array;
+ char offset = 3;
+
+ cPtr = cP + offset;
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void cPointer_int(void)
+{
+ char *cP = array;
+ int offset = 3;
+
+ cPtr = cP + offset;
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void cPointer_long(void)
+{
+ char *cP = array;
+ long offset = 3;
+
+ cPtr = cP + offset;
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void iPointer_char(void)
+{
+ int *iP = (int *)array;
+ char offset = 3;
+
+ iPtr = iP + offset;
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void iPointer_int(void)
+{
+ int *iP = (int *)array;
+ int offset = 3;
+
+ iPtr = iP + offset;
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void iPointer_long(void)
+{
+ int *iP = (int *)array;
+ long offset = 3;
+
+ iPtr = iP + offset;
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void lPointer_char(void)
+{
+ long *lP = (long *)array;
+ char offset = 3;
+
+ lPtr = lP + offset;
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+static void lPointer_int(void)
+{
+ long *lP = (long *)array;
+ int offset = 3;
+
+ lPtr = lP + offset;
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+static void lPointer_long(void)
+{
+ long *lP = (long *)array;
+ long offset = 3;
+
+ lPtr = lP + offset;
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+/* These functions test: adding a pointer variable to an offset variable. */
+
+static void char_cPointer(void)
+{
+ char *cP = array;
+ char offset = 3;
+
+ cPtr = offset + cP;
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void int_cPointer(void)
+{
+ char *cP = array;
+ int offset = 3;
+
+ cPtr = offset + cP;
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void long_cPointer(void)
+{
+ char *cP = array;
+ long offset = 3;
+
+ cPtr = (offset + cP);
+ if (cPtr != (void *)&array[3]) {
+ ++failures;
+ }
+}
+
+static void char_iPointer(void)
+{
+ int *iP = (int *)array;
+ char offset = 3;
+
+ iPtr = offset + iP;
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void int_iPointer(void)
+{
+ int *iP = (int *)array;
+ int offset = 3;
+
+ iPtr = offset + iP;
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void long_iPointer(void)
+{
+ int *iP = (int *)array;
+ long offset = 3;
+
+ iPtr = (offset + iP);
+ if (iPtr != (void *)&array[6]) {
+ ++failures;
+ }
+}
+
+static void char_lPointer(void)
+{
+ long *lP = (long *)array;
+ char offset = 3;
+
+ lPtr = offset + lP;
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+static void int_lPointer(void)
+{
+ long *lP = (long *)array;
+ int offset = 3;
+
+ lPtr = offset + lP;
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+static void long_lPointer(void)
+{
+ long *lP = (long *)array;
+ long offset = 3;
+
+ lPtr = (offset + lP);
+ if (lPtr != (void *)&array[12]) {
+ ++failures;
+ }
+}
+
+int main(void)
+{
+ cPointer_char();
+ cPointer_int();
+ cPointer_long();
+
+ iPointer_char();
+ iPointer_int();
+ iPointer_long();
+
+ lPointer_char();
+ lPointer_int();
+ lPointer_long();
+
+ char_cPointer();
+ int_cPointer();
+ long_cPointer();
+
+ char_iPointer();
+ int_iPointer();
+ long_iPointer();
+
+ char_lPointer();
+ int_lPointer();
+ long_lPointer();
+
+ if (failures != 0) {
+ printf("add5: failures: %u\n", failures);
+ }
+ return failures;
+}
--- /dev/null
+
+/*
+ !!DESCRIPTION!! Cast to char
+ !!ORIGIN!! Piotr Fusik
+ !!LICENCE!! PD
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static unsigned int failures = 0;
+
+int f1(int i, int j) {
+ return (signed char) (i + 1) == j;
+}
+
+int f2(int i, int j) {
+ return (unsigned char) (i + 1) == j;
+}
+
+int f3(int i, int j) {
+ return (char) (i + 1) == j;
+}
+
+int main(void)
+{
+ printf("f1: got :%04x ", f1(0x1234, 0x35));
+ if(f1(0x1234, 0x35) == 0) {
+ printf("- failed");
+ failures++;
+ }
+ printf("\n");
+
+ printf("f2: got :%04x ", f2(0x1234, 0x35));
+ if(f2(0x1234, 0x35) == 0) {
+ printf("- failed");
+ failures++;
+ }
+ printf("\n");
+
+ printf("f3: got :%04x ", f3(0x1234, 0x35));
+ if(f3(0x1234, 0x35) == 0) {
+ printf("- failed");
+ failures++;
+ }
+ printf("\n");
+
+ return failures;
+}
--- /dev/null
+
+/*
+ !!DESCRIPTION!! forgetting to emit labels
+ !!ORIGIN!! Testsuite
+ !!LICENCE!! Public Domain
+*/
+
+/*
+ http://www.cc65.org/mailarchive/2014-10/11673.html
+ http://www.cc65.org/mailarchive/2014-10/11675.html
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct udata {
+ int (*u_sigvec[16])();
+ int u_argn;
+ int u_argn1;
+};
+
+struct udata udata;
+
+#define sig (int)udata.u_argn
+#define func (int (*)())udata.u_argn1
+
+int _signal(void)
+{
+ if (func != 0) {
+ goto nogood;
+ }
+ udata.u_sigvec[sig] = func;
+ return 0;
+
+nogood:
+ return (-1);
+}
+
+int main(int n,char **args)
+{
+ _signal();
+ printf("it works\n");
+
+ return 0;
+}
--- /dev/null
+
+/*
+ !!DESCRIPTION!! struct base address dereferencing bug
+ !!ORIGIN!! Testsuite
+ !!LICENCE!! Public Domain
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct yywork
+{
+ char verify, advance;
+} yycrank[] =
+{
+ {0,0}
+};
+
+struct yysvf
+{
+ struct yywork *yystoff;
+} yysvec[1];
+
+unsigned char fails = 0;
+
+int main(int n, char **args)
+{
+ struct yysvf *yystate = yysvec;
+ struct yywork *yyt;
+
+ yystate->yystoff = yycrank;
+ yyt = yystate->yystoff;
+
+ if(yyt == yycrank) {
+ printf("yyt == yycrank (ok)\n");
+ } else {
+ printf("yyt != yycrank (fail)\n");
+ ++fails;
+ }
+
+ if(yyt == yystate->yystoff) {
+ printf("yyt == yystate->yystoff (ok)\n");
+ } else {
+ printf("yyt != yystate->yystoff (fail)\n");
+ ++fails;
+ }
+
+ if(yycrank == yystate->yystoff) {
+ printf("yycrank == yystate->yystoff (ok)\n");
+ } else {
+ printf("yycrank != yystate->yystoff (fail)\n");
+ ++fails;
+ }
+
+ printf("fails: %d\n", fails);
+ return fails;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! function pointer bugs
+ !!ORIGIN!! testsuite
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg
+*/
+
+/*
+ see: http://www.cc65.org/mailarchive/2015-03/11726.html
+ and: http://www.cc65.org/mailarchive/2015-03/11734.html
+*/
+
+static int func(void) {return 0;}
+static int (*p)(void);
+static int n;
+
+int main(void) {
+
+ p = func;
+ n = (p == &func);
+ n = (p == func);
+
+/* the following are not valid C and should go into seperate tests that MUST fail */
+/*
+ ++p;
+ n = (p > &func);
+ n = (p > func);
+ n = func - func;
+ n = func - &func;
+ n = &func - func;
+ n = &func - &func;
+ n = p - &func;
+ n = p - func;
+ n = &func - p;
+ n = func - p;
+*/
+ return 0;
+}
--- /dev/null
+/*
+** !!DESCRIPTION!! Simple tests of pointer-to-array dereferences
+** !!ORIGIN!! cc65 regression tests
+** !!LICENCE!! Public Domain
+** !!AUTHOR!! 2015-06-29, Greg King
+*/
+
+#include <stdio.h>
+
+static unsigned char failures = 0;
+static size_t Size;
+
+typedef unsigned char array_t[4][4];
+
+static array_t table = {
+ {12, 13, 14, 15},
+ { 8, 9, 10, 11},
+ { 4, 5, 6, 7},
+ { 0, 1, 2, 3}
+};
+static array_t *tablePtr = &table;
+
+static unsigned (*vector)[2];
+
+static unsigned char y = 0, x;
+
+int main(void)
+{
+ /* The indirection must convert the expression-type (from Pointer into
+ ** Array); but, it must not convert the value, because it already points
+ ** to the start of the array.
+ */
+ /* (Note: I reduce output clutter by using a variable to prevent
+ ** compiler warnings about constant comparisons and unreachable code.
+ */
+ if ((Size = sizeof *tablePtr) != sizeof table) {
+ ++failures;
+ }
+ if (*tablePtr != table) {
+ ++failures;
+ }
+
+ /* Test fetching. */
+ do {
+ x = 0;
+ do {
+ if ((*tablePtr)[y][x] != table[y][x]) {
+ ++failures;
+ printf("(*tableptr)[%u][%u] (%u) != table[%u][%u] (%u).\n",
+ y, x, (*tablePtr)[y][x],
+ y, x, table[y][x]);
+ }
+ } while (++x < sizeof table[0]);
+ } while (++y < sizeof table / sizeof table[0]);
+
+ vector = (unsigned (*)[])table[1];
+ if ((*vector)[1] != 0x0B0A) {
+ ++failures;
+ }
+
+ /* Test storing. */
+ (*tablePtr)[2][1] = 42;
+ if (table[2][1] != 42) {
+ ++failures;
+ printf("table[2][1] == %u (should have changed from 5 to 42).\n",
+ table[2][1]);
+ }
+ x = 3;
+ y = 1;
+ (*tablePtr)[y][x] = 83;
+ if (table[1][3] != 83) {
+ ++failures;
+ printf("table[y][x] == %u (should have changed from 11 to 83).\n",
+ table[1][3]);
+ }
+
+ /* Test triple indirection. It should compile to two indirection
+ ** operations.
+ */
+ --***tablePtr;
+ if (**table != 11) {
+ ++failures;
+ printf("**table == %u (should have changed from 12 to 11).\n",
+ table[0][0]);
+ }
+
+ if (failures != 0) {
+ printf("failures: %u\n", failures);
+ }
+ return failures;
+}
*/
#include <stdio.h>
-#include <limits.h>
+
+#define NO_IMPLICIT_FUNCPTR_CONV
unsigned char success=0;
unsigned char failures=0;
--- /dev/null
+/*
+ !!DESCRIPTION!! Optimized-shift signed ints right by a constant; and, assign to chars.
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+#include <stdio.h>
+
+static unsigned char failures = 0;
+static unsigned char n = 0;
+
+/* This number must be read from a variable because
+** we want this program, not cc65, to do the shift.
+*/
+static const signed int aint0 = 0xAAC0;
+
+static signed char achar0, achar1;
+
+static void check(void)
+{
+ if ((unsigned char)achar0 != (unsigned char)achar1)
+ ++failures;
+}
+
+static void shift_right_0(void)
+{
+ achar0 = aint0 >> 0;
+ check();
+}
+
+static void shift_right_1(void)
+{
+ achar0 = aint0 >> 1;
+ check();
+}
+
+static void shift_right_2(void)
+{
+ achar0 = aint0 >> 2;
+ check();
+}
+
+static void shift_right_3(void)
+{
+ achar0 = aint0 >> 3;
+ check();
+}
+
+static void shift_right_4(void)
+{
+ achar0 = aint0 >> 4;
+ check();
+}
+
+static void shift_right_5(void)
+{
+ achar0 = aint0 >> 5;
+ check();
+}
+
+static void shift_right_6(void)
+{
+ achar0 = aint0 >> 6;
+ check();
+}
+
+static void shift_right_7(void)
+{
+ achar0 = aint0 >> 7;
+ check();
+}
+
+static void shift_right_8(void)
+{
+ achar0 = aint0 >> 8;
+ check();
+}
+
+static void shift_right_9(void)
+{
+ achar0 = aint0 >> 9;
+ check();
+}
+
+static void shift_right_10(void)
+{
+ achar0 = aint0 >> 10;
+ check();
+}
+
+static void shift_right_11(void)
+{
+ achar0 = aint0 >> 11;
+ check();
+}
+
+static void shift_right_12(void)
+{
+ achar0 = aint0 >> 12;
+ check();
+}
+
+static void shift_right_13(void)
+{
+ achar0 = aint0 >> 13;
+ check();
+}
+
+static void shift_right_14(void)
+{
+ achar0 = aint0 >> 14;
+ check();
+}
+
+static void shift_right_15(void)
+{
+ achar0 = aint0 >> 15;
+ check();
+}
+
+const struct {
+ signed char achar;
+ void (*func)(void);
+} tests[] = {
+ {0xC0, shift_right_0},
+ {0x60, shift_right_1},
+ {0xB0, shift_right_2},
+ {0x58, shift_right_3},
+ {0xAC, shift_right_4},
+ {0x56, shift_right_5},
+ {0xAB, shift_right_6},
+ {0x55, shift_right_7},
+ {0xAA, shift_right_8},
+ {0xD5, shift_right_9},
+ {0xEA, shift_right_10},
+ {0xF5, shift_right_11},
+ {0xFA, shift_right_12},
+ {0xFD, shift_right_13},
+ {0xFE, shift_right_14},
+ {0xFF, shift_right_15}
+};
+
+int main(void)
+{
+ do {
+ achar1 = tests[n].achar;
+ tests[n].func();
+ } while (++n < sizeof tests / sizeof tests[0]);
+
+ if (failures) {
+ printf("rotate8: failures: %u (of %u).\n",
+ failures, sizeof tests / sizeof tests[0]);
+ }
+ return failures;
+}
--- /dev/null
+/*
+ !!DESCRIPTION!! global non-static and static conflicts
+ !!ORIGIN!! cc65 regression tests
+ !!LICENCE!! Public Domain
+ !!AUTHOR!! Greg King
+*/
+
+/*
+ see: https://github.com/cc65/cc65/issues/191
+*/
+
+#pragma warn(error, on)
+
+static int n = 0;
+extern int n; /* should not give an error */
+
+int main(void)
+{
+ return n;
+}
--- /dev/null
+; Test ca65's handling of the .paramcount read-only variable.
+; .paramcount should see all given arguments, even when they are empty.
+
+.macro push r1, r2, r3, r4, r5, r6
+ .out .sprintf(" .paramcount = %u", .paramcount)
+.if .paramcount <> 0
+.ifblank r1
+ .warning "r1 is blank!"
+.exitmacro
+.endif
+ lda r1
+ pha
+
+ push r2, r3, r4, r5, r6
+.endif
+.endmacro
+
+ push 1, , {}
+ push 1, ,
+ push 1
--- /dev/null
+*.o
+em-test-*
--- /dev/null
+/*
+ * conio api test program
+ *
+ * keys:
+ *
+ * 1...0 change text color
+ * F5/F6 change border color
+ * F7/F8 change background color
+ *
+ */
+
+
+#include <conio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <joystick.h>
+
+static char grid[5][5] = {
+ { CH_ULCORNER, CH_HLINE, CH_TTEE, CH_HLINE, CH_URCORNER },
+ { CH_VLINE, ' ', CH_VLINE, ' ', CH_VLINE },
+ { CH_LTEE, CH_HLINE, CH_CROSS, CH_HLINE, CH_RTEE },
+ { CH_VLINE, ' ', CH_VLINE, ' ', CH_VLINE },
+ { CH_LLCORNER, CH_HLINE, CH_BTEE, CH_HLINE, CH_LRCORNER },
+};
+
+void main(void)
+{
+ int i, j, n;
+ unsigned char xsize, ysize, tcol, bgcol, bcol, inpos = 0;
+
+ clrscr();
+ screensize(&xsize, &ysize);
+ cputs("cc65 conio test\n\rInput: [ ]");
+
+ cputsxy(0, 2, "Colors:" );
+ tcol = textcolor(0); /* remember original textcolor */
+ bgcol = bgcolor(0); /* remember original background color */
+ bcol = bordercolor(0); /* remember original border color */
+ bgcolor(bgcol);bordercolor(bcol);
+ for (i = 0; i < 3; ++i) {
+ gotoxy(i,3 + i);
+ for (j = 0; j < 16; ++j) {
+ textcolor(j);
+ cputc('X');
+ }
+ }
+ textcolor(tcol);
+
+ cprintf("\n\n\r Screensize is: %dx%d", xsize, ysize);
+
+ chlinexy(0,6,xsize);
+ cvlinexy(0,6,3);
+ chlinexy(0,8,xsize);
+ cvlinexy(xsize-1,6,3);
+ cputcxy(0,6,CH_ULCORNER);
+ cputcxy(xsize-1,6,CH_URCORNER);
+ cputcxy(0,8,CH_LLCORNER);
+ cputcxy(xsize-1,8,CH_LRCORNER);
+
+ for (i = 0; i < 5; ++i) {
+ gotoxy(xsize - 5,i);
+ for (j = 0; j < 5; ++j) {
+ cputc(grid[i][j]);
+ }
+ }
+
+ gotoxy(0,ysize - 2 - ((256 + xsize) / xsize));
+ revers(1);
+ for (i = 0; i < xsize; ++i) {
+ cputc('0' + i % 10);
+ }
+ revers(0);
+ for (i = 0; i < 256; ++i) {
+ if ((i != '\n') && (i != '\r')) {
+ cputc(i);
+ } else {
+ cputc(' ');
+ }
+ }
+ while(wherex() > 0) {
+ cputc('#');
+ }
+ revers(1);
+ for (i = 0; i < xsize; ++i) {
+ cputc('0' + i % 10);
+ }
+ revers(0);
+
+ cursor(1);
+ for (;;) {
+
+ gotoxy(8, 2);
+ j = n & 1;
+ revers(j);
+ cputc(j ? 'R' : ' ');
+ revers(j ^ 1);
+ cputs(" revers");
+ revers(0);
+
+#if defined(__NES__) || defined(__PCE__)
+
+ joy_install(joy_static_stddrv);
+ while (!joy_read(JOY_1)) ;
+ joy_uninstall();
+
+#else
+
+ gotoxy(8 + inpos,1);
+ i = cgetc();
+ if ((i >= '0') && (i<='9')) {
+ textcolor(i - '0');
+ } else if (i == CH_CURS_LEFT) {
+ inpos = (inpos - 1) & 7;
+ } else if (i == CH_CURS_RIGHT) {
+ inpos = (inpos + 1) & 7;
+ } else if (i == CH_F5) {
+ bgcol = (bgcol + 1) & 0x0f;
+ bordercolor(bgcol);
+ } else if (i == CH_F6) {
+ bgcol = (bgcol - 1) & 0x0f;
+ bordercolor(bgcol);
+ } else if (i == CH_F7) {
+ bgcol = (bgcol + 1) & 0x0f;
+ bgcolor(bgcol);
+ } else if (i == CH_F8) {
+ bgcol = (bgcol - 1) & 0x0f;
+ bgcolor(bgcol);
+ } else {
+ cputc(i);
+ inpos = (inpos + 1) & 7;
+ }
+
+#endif
+
+ ++n;
+ }
+}
#include <conio.h>
#include <em.h>
-
-#if defined(__C64__)
-#define DRIVERNAME "c64-ram.emd"
-#elif defined(__C128__)
-#define DRIVERNAME "c128-ram.emd"
-#elif defined(__C16__)
-#define DRIVERNAME "c16-ram.emd"
-#elif defined(__CBM510__)
-#define DRIVERNAME "cbm510-ram.emd"
-#elif defined(__CBM610__)
-#define DRIVERNAME "cbm610-ram.emd"
-#elif defined(__APPLE2ENH__)
-#define DRIVERNAME "a2e.auxmem.emd"
-#elif defined(__APPLE2__)
-#define DRIVERNAME "a2.auxmem.emd"
-#elif defined(__ATARIXL__)
-#define DRIVERNAME "atrx130.emd"
-#elif defined(__ATARI__)
-#define DRIVERNAME "atr130.emd"
-#else
-#define DRIVERNAME "unknown"
-#error "Unknown target system"
-#endif
-
-
#define FORCE_ERROR1 0
#define FORCE_ERROR2 0
-
#define PAGE_SIZE 128 /* Size in words */
#define BUF_SIZE (PAGE_SIZE + PAGE_SIZE/2)
static unsigned buf[BUF_SIZE];
}
}
+typedef struct emd_test_s {
+ char key;
+ char *displayname;
+ char *drivername;
+} emd_test_t;
+
+static emd_test_t drivers[] = {
+
+#if defined(__APPLE2__)
+ { '0', "Apple II auxiliary memory", "a2.auxmem.emd" },
+#endif
+
+#if defined(__APPLE2ENH__)
+ { '0', "Apple II auxiliary memory", "a2e.auxmem.emd" },
+#endif
+
+#if defined(__ATARI__)
+ { '0', "Atari 130XE memory", "atr130.emd" },
+#endif
+
+#if defined(__ATARIXL__)
+ { '0', "Atari 130XE memory", "atrx130.emd" },
+#endif
+
+#if defined(__C16__)
+ { '0', "C16 RAM above $8000", "c16-ram.emd" },
+#endif
+
+#if defined(__C64__)
+ { '0', "C64 RAM above $D000", "c64-ram.emd" },
+ { '1', "C64 256K", "c64-c256k.emd" },
+ { '2', "Double Quick Brown Box", "c64-dqbb.emd" },
+ { '3', "GEORAM", "c64-georam.emd" },
+ { '4', "Isepic", "c64-isepic.emd" },
+ { '5', "RamCart", "c64-ramcart.emd" },
+ { '6', "REU", "c64-reu.emd" },
+ { '7', "C128 VDC (in C64 mode)", "c64-vdc.emd" },
+ { '8', "C64DTV himem", "dtv-himem.emd" },
+#endif
+
+#if defined(__C128__)
+ { '0', "C128 RAM in bank 1", "c128-ram.emd" },
+ { '1', "C128 RAM in banks 1, 2 & 3", "c128-ram2.emd" },
+ { '2', "GEORAM", "c128-georam.emd" },
+ { '3', "RamCart", "c128-ramcart.emd" },
+ { '4', "REU", "c128-reu.emd" },
+ { '5', "VDC", "c128-vdc.emd" },
+#endif
+
+#if defined(__CBM510__)
+ { '0', "CBM5x0 RAM in bank 2", "cbm510-ram.emd" },
+#endif
+#if defined(__CBM610__)
+ { '0', "CBM6x0/7x0 RAM in bank 2", "cbm610-ram.emd" },
+#endif
+
+ { 0, NULL, NULL }
+};
int main (void)
{
unsigned PageCount;
unsigned char X, Y;
struct em_copy c;
+ unsigned index;
+ signed char valid_key = -1;
+ char key;
+
+ clrscr ();
+ cputs ("Which RAM exp to test?\r\n\r\n");
+ for (index = 0; drivers[index].key; ++index) {
+ cprintf("%c: %s\r\n", drivers[index].key, drivers[index].displayname);
+ }
+
+ while (valid_key < 0) {
+ key = cgetc();
+ for (index = 0; drivers[index].key && valid_key < 0; ++index) {
+ if (key == drivers[index].key) {
+ valid_key = index;
+ }
+ }
+ }
clrscr ();
- Res = em_load_driver (DRIVERNAME);
+ Res = em_load_driver (drivers[valid_key].drivername);
if (Res != EM_ERR_OK) {
cprintf ("Error in em_load_driver: %u\r\n", Res);
cprintf ("os: %u, %s\r\n", _oserror, _stroserror (_oserror));
--- /dev/null
+.PHONY: all clean test
+
+all: conio.pce
+
+conio.pce: conio.c
+ ../../../bin/cl65 -t pce conio.c --mapfile conio.map -o conio.pce
+
+clean:
+ $(RM) conio.o conio.pce conio.map
+
+test: conio.pce
+ mednafen -force_module pce conio.pce
--- /dev/null
+#include <conio.h>
+#include <time.h>
+#include <joystick.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int datavar = 10;
+
+void main(void)
+{
+ int stackvar = 42;
+ int i, j;
+ clock_t clk;
+ char* p;
+ unsigned char xsize, ysize, n, nn;
+
+ joy_install(&joy_static_stddrv);
+
+ clrscr();
+ screensize(&xsize, &ysize);
+
+ cputs("hello world");
+ cputsxy(0, 2, "colors:" );
+ for (i = 0; i < 16; ++i) {
+ textcolor(i);
+ cputc('X');
+ }
+ textcolor(1);
+
+ gotoxy(0,4);
+ cprintf("datavar: %02x\n\r", datavar);
+ cprintf("stackvar: %02x\n\r", stackvar);
+
+ j = joy_count();
+ gotoxy(0,9);
+ cprintf("Found %d Joysticks.", j);
+
+ for (i = 0; i < 4; ++i) {
+ gotoxy(0, 16 + i);
+ p = malloc(16);
+ memcpy(p, "0123456789abcdef", 16);
+ cprintf("alloc'ed at: %04p - %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", p,
+ p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],
+ p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]
+ );
+ }
+ memcpy(p, main, 0); /* test that a zero length doesn't copy 64K */
+
+ gotoxy(0,ysize - 1);
+ for (i = 0; i < xsize; ++i) {
+ cputc('0' + i % 10);
+ }
+
+ gotoxy(0,ysize - 2 - ((256 + xsize) / xsize));
+ for (i = 0; i < xsize; ++i) {
+ cputc('0' + i % 10);
+ }
+ for (i = 0; i < (xsize * 5); ++i) {
+ cputc('#');
+ }
+ gotoxy(0,ysize - 1 - ((256 + xsize) / xsize));
+ for (i = 0; i < 256; ++i) {
+ if ((i != '\n') && (i != '\r')) {
+ cputc(i);
+ }
+ }
+
+ i = get_tv();
+ gotoxy(30,0);
+ cputs("TV Mode: ");
+ switch(i) {
+ case TV_NTSC:
+ cputs("NTSC");
+ break;
+ case TV_PAL:
+ cputs("PAL");
+ break;
+ case TV_OTHER:
+ cputs("OTHER");
+ break;
+ }
+ cprintf(" %dx%d", xsize, ysize);
+
+ for(;;) {
+ gotoxy(13,4);
+ cprintf("%02x", datavar);
+ gotoxy(13,5);
+ cprintf("%02x", stackvar);
+ ++datavar; ++stackvar;
+
+ gotoxy(0,7);
+ clk = clock();
+ cprintf("clock: %08lx", clk);
+
+ for (i = 0; i < 4; ++i) {
+ gotoxy(0, 11 + i);
+ j = joy_read (i);
+ cprintf ("pad %d: %02x %-6s%-6s%-6s%-6s%-6s%-6s%-6s%-6s",
+ i, j,
+ (j & joy_masks[JOY_UP])? " up " : " ---- ",
+ (j & joy_masks[JOY_DOWN])? " down " : " ---- ",
+ (j & joy_masks[JOY_LEFT])? " left " : " ---- ",
+ (j & joy_masks[JOY_RIGHT])? "right " : " ---- ",
+ (j & joy_masks[JOY_FIRE])? " fire " : " ---- ",
+ (j & joy_masks[JOY_FIRE2])? "fire2 " : " ---- ",
+ (j & joy_masks[JOY_SELECT])? "select" : " ---- ",
+ (j & joy_masks[JOY_RUN])? " run " : " ---- ");
+ }
+
+ gotoxy(xsize - 10, 3);
+ nn = (n >> 5) & 1;
+ revers(nn);
+ cputc(nn ? 'R' : ' ');
+ cputs(" revers");
+ revers(0);
+
+ if ((n & 0x1f) == 0x00) {
+ nn = p[15];
+ ((char*)memmove(p + 1, p, 15))[-1] = nn;
+ gotoxy(22, 19);
+ cprintf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ p[0],p[1],p[ 2],p[ 3],p[ 4],p[ 5],p[ 6],p[ 7],
+ p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]);
+ }
+
+ waitvblank();
+ ++n;
+ }
+}
--- /dev/null
+/*
+** Test a function that formats and writes characters into a string buffer.
+** This program does not test formatting. It tests some behaviors that are
+** specific to the buffer. It tests that certain conditions are handled
+** properly.
+**
+** 2015-07-17, Greg King
+*/
+
+#include <conio.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char format[] = "1234567890\nabcdefghijklmnopqrstuvwxyz\n%u\n%s\n\n";
+#define FORMAT_SIZE (sizeof format - 2u - 2u - 1u)
+
+#define arg1 12345u
+#define ARG1_SIZE (5u)
+
+static const char arg2[] = "!@#$%^&*()-+";
+#define ARG2_SIZE (sizeof arg2 - 1u)
+
+#define STRING_SIZE (FORMAT_SIZE + ARG1_SIZE + ARG2_SIZE)
+
+static char buf[256];
+static int size;
+
+
+static void fillbuf(void)
+{
+ memset(buf, 0xFF, sizeof buf - 1u);
+ buf[sizeof buf - 1u] = '\0';
+}
+
+
+unsigned char main(void)
+{
+ static unsigned char failures = 0;
+
+ /* Show what sprintf() should create. */
+
+ if ((size = printf(format, arg1, arg2)) != STRING_SIZE) {
+ ++failures;
+ printf("printf() gave the wrong size: %d.\n", size);
+ }
+
+ /* Test the normal behavior of sprintf(). */
+
+ fillbuf();
+ size = sprintf(buf, format, arg1, arg2);
+ fputs(buf, stdout);
+ if (size != STRING_SIZE) {
+ ++failures;
+ printf("sprintf() gave the wrong size: %d.\n", size);
+ }
+
+ /* Test the normal behavior of snprintf(). */
+
+ fillbuf();
+ size = snprintf(buf, sizeof buf, format, arg1, arg2);
+ fputs(buf, stdout);
+ if (size != STRING_SIZE) {
+ ++failures;
+ printf("snprintf(sizeof buf) gave the wrong size:\n %d.\n", size);
+ }
+
+ /* Does snprintf() return the full-formatted size even when the buffer
+ ** is short? Does it write beyond the end of that buffer?
+ */
+
+ fillbuf();
+ size = snprintf(buf, STRING_SIZE - 5u, format, arg1, arg2);
+ if (size != STRING_SIZE) {
+ ++failures;
+ printf("snprintf(STRING_SIZE-5) gave the wrong size:\n %d.\n", size);
+ }
+ if (buf[STRING_SIZE - 5u - 1u] != '\0' || buf[STRING_SIZE - 5u] != 0xFF) {
+ ++failures;
+ printf("snprintf(STRING_SIZE-5) wrote beyond\n the end of the buffer.\n");
+ }
+
+ /* Does snprintf() detect a buffer size that is too big? */
+
+ fillbuf();
+ errno = 0;
+ size = snprintf(buf, 0x8000, format, arg1, arg2);
+ if (size >= 0) {
+ ++failures;
+ printf("snprintf(0x8000) didn't give an error:\n %d; errno=%d.\n", size, errno);
+ } else {
+ printf("snprintf(0x8000) did give an error:\n errno=%d.\n", errno);
+ }
+ if (buf[0] != 0xFF) {
+ ++failures;
+ printf("snprintf(0x8000) wrote into the buffer.\n");
+ }
+
+ /* snprintf() must measure the length of the formatted output even when the
+ ** buffer size is zero. But, it must not touch the buffer.
+ */
+
+ fillbuf();
+ size = snprintf(buf, 0, format, arg1, arg2);
+ if (size != STRING_SIZE) {
+ ++failures;
+ printf("snprintf(0) gave the wrong size:\n %d.\n", size);
+ }
+ if (buf[0] != 0xFF) {
+ ++failures;
+ printf("snprintf(0) wrote into the buffer.\n");
+ }
+
+ /* Does sprintf() detect a zero buffer-pointer? */
+
+ errno = 0;
+ size = sprintf(NULL, format, arg1, arg2);
+ if (size >= 0) {
+ ++failures;
+ printf("sprintf(NULL) didn't give an error:\n %d; errno=%d.\n", size, errno);
+ } else {
+ printf("sprintf(NULL) did give an error:\n errno=%d.\n", errno);
+ }
+
+ /* snprintf() must measure the length of the formatted output even when the
+ ** buffer size is zero. A zero pointer is not an error, in that case.
+ */
+
+ size = snprintf(NULL, 0, format, arg1, arg2);
+ if (size != STRING_SIZE) {
+ ++failures;
+ printf("snprintf(NULL,0) gave the wrong size:\n %d.\n", size);
+ }
+
+ if (failures != 0) {
+ printf("There were %u", failures);
+ } else {
+ printf("There were no");
+ }
+ printf(" failures.\nTap a key. ");
+ cgetc();
+
+ return failures;
+}