Blob Blame History Raw
From d78133e1f00be19929ca6ee920c30f782c502e8b Mon Sep 17 00:00:00 2001
From: Greg King <gregdk@users.sf.net>
Date: Sat, 16 Nov 2019 13:11:40 -0500
Subject: [PATCH 095/170] Updated cx16 to match the Commander X16 ROMs and
 emulator, release 34.

---
 asminc/cbm_kernal.inc                         |   4 +-
 asminc/cx16.inc                               |  87 ++++++++-----
 cfg/cx16-asm.cfg                              |   3 +-
 cfg/cx16-bank.cfg                             |   2 +-
 cfg/cx16.cfg                                  |   2 +-
 doc/cx16.sgml                                 |  50 ++++---
 include/cx16.h                                |  23 +++-
 libsrc/cx16/break.s                           |  21 ++-
 libsrc/cx16/conio.s                           |   9 --
 libsrc/cx16/cpeekc.s                          |   2 +-
 libsrc/cx16/cpeekrevers.s                     |   2 +-
 libsrc/cx16/cputc.s                           |   4 +-
 libsrc/cx16/crt0.s                            |  22 ++--
 libsrc/cx16/devnum.s                          |   8 --
 libsrc/cx16/exec.c                            | 122 ++++++++++++++++++
 libsrc/cx16/execvars.s                        |  16 +++
 libsrc/cx16/filevars.s                        |  39 ++++++
 libsrc/cx16/getdevice.s                       |  67 ++++++++++
 libsrc/cx16/gotox.s                           |  13 ++
 libsrc/cx16/gotoxy.s                          |  18 +++
 libsrc/cx16/gotoy.s                           |  13 ++
 libsrc/cx16/joy/{cx16-stdjoy.s => cx16-std.s} |  76 ++++++-----
 libsrc/cx16/joy_stat_stddrv.s                 |   7 +-
 libsrc/cx16/joy_stddrv.s                      |   4 +-
 libsrc/cx16/joyref.s                          |  20 +++
 libsrc/cx16/kbhit.s                           |   6 +-
 libsrc/cx16/kernal.s                          |   5 +-
 libsrc/cx16/libref.s                          |   4 +-
 libsrc/cx16/mainargs.s                        |   8 +-
 libsrc/cx16/set_tv.s                          |  16 +--
 libsrc/cx16/status.s                          |  16 ++-
 libsrc/cx16/tgi_stat_stddrv.s                 |  11 ++
 libsrc/cx16/tgi_stddrv.s                      |  13 ++
 libsrc/cx16/videomode.s                       |  48 ++++---
 libsrc/cx16/waitvsync.s                       |   2 +-
 libsrc/cx16/wherex.s                          |  15 +++
 libsrc/cx16/wherey.s                          |  15 +++
 37 files changed, 609 insertions(+), 184 deletions(-)
 delete mode 100644 libsrc/cx16/conio.s
 delete mode 100644 libsrc/cx16/devnum.s
 create mode 100644 libsrc/cx16/exec.c
 create mode 100644 libsrc/cx16/execvars.s
 create mode 100644 libsrc/cx16/filevars.s
 create mode 100644 libsrc/cx16/getdevice.s
 create mode 100644 libsrc/cx16/gotox.s
 create mode 100644 libsrc/cx16/gotoxy.s
 create mode 100644 libsrc/cx16/gotoy.s
 rename libsrc/cx16/joy/{cx16-stdjoy.s => cx16-std.s} (58%)
 create mode 100644 libsrc/cx16/joyref.s
 create mode 100644 libsrc/cx16/tgi_stat_stddrv.s
 create mode 100644 libsrc/cx16/tgi_stddrv.s
 create mode 100644 libsrc/cx16/wherex.s
 create mode 100644 libsrc/cx16/wherey.s

diff --git a/asminc/cbm_kernal.inc b/asminc/cbm_kernal.inc
index 6e1e1604..a38836ce 100644
--- a/asminc/cbm_kernal.inc
+++ b/asminc/cbm_kernal.inc
@@ -7,18 +7,20 @@
 .if .def(__CX16__)
   ; CX16 extended jump table
   GETJOY       := $FF06
+  MOUSE        := $FF09
+  SCRMOD       := $FF5F
 .endif
 
 .if .def(__C128__)
   ; C128 extended jump table
   C64MODE      := $FF4D
+  SWAPPER      := $FF5F
   SETBNK       := $FF68
 .endif
 
 .if .def(__C128__) || .def(__CX16__)
   ; Extended jump table
   CLSALL       := $FF4A
-  SWAPPER      := $FF5F
   JSRFAR       := $FF6E
   INDFET       := $FF74
   INDSTA       := $FF77
diff --git a/asminc/cx16.inc b/asminc/cx16.inc
index 5b46908d..1c22c99b 100644
--- a/asminc/cx16.inc
+++ b/asminc/cx16.inc
@@ -44,42 +44,55 @@
 ; ---------------------------------------------------------------------------
 ; Zero page
 
-; BASIC
-VARTAB          := $2D          ; Pointer to start of BASIC variables
-MEMSIZE         := $37          ; Pointer to highest BASIC RAM location (+1)
-TXTPTR          := $7A          ; Pointer into BASIC source code
-
 ; Kernal
-IN_DEV          := $99          ; Current input device number
-OUT_DEV         := $9A          ; Current output device number
-IMPARM          := $9B          ; Pointer for PRIMM function
-TIME            := $A0          ; 60 Hz. clock
-FNAM_LEN        := $B7          ; Length of filename
-SECADR          := $B9          ; Secondary address
-DEVNUM          := $BA          ; Device number
-FNAM            := $BB          ; Pointer to filename
-KEY_COUNT       := $C6          ; Number of keys in input buffer
-RVS             := $C7          ; Reverse flag
-CURS_FLAG       := $CC          ; 1 = cursor off
-CURS_BLINK      := $CD          ; Blink counter
-CURS_CHAR       := $CE          ; Character under the cursor
-CURS_STATE      := $CF          ; Cursor blink state
-SCREEN_PTR      := $D1          ; Pointer to current row on text screen (16 bits)
-CURS_X          := $D3          ; Cursor column
-CURS_Y          := $D6          ; Cursor row
-LLEN            := $D9          ; Line length
-NLINES          := $DA          ; Number of screen lines
-JOY1            := $EF          ; 3 bytes of NES/SNES gamepad data
-JOY2            := $F2
-FREKZP          := $FB          ; Five unused bytes
+FNAM            := $84          ; Pointer to filename
+KTEMP2          := $86          ; 2 bytes for temporary storage
+SCREEN_PTR      := $88          ; Pointer to current row on text screen (16 bits)
+IMPARM          := $8A          ; Pointer for PRIMM function
+
+; BASIC
+TXTPTR          := $EE          ; Pointer into BASIC source code
 
 ; Page two
 
-BASIC_BUF       := $200         ; Location of command-line
-BASIC_BUF_LEN   = 89            ; Maximum length of command-line
+BASIC_BUF       := $0200        ; Location of command-line
+BASIC_BUF_LEN   = 81            ; Maximum length of command-line
 
-CHARCOLOR       := $286
-CURS_COLOR      := $287         ; Color under the cursor
+CURS_COLOR      := $027E        ; Color under the cursor
+CHARCOLOR       := $0286        ; Cursor's color nybbles (high: background, low: foreground)
+STATUS          := $0287        ; Status from previous I/O operation
+IN_DEV          := $028E        ; Current input device number
+OUT_DEV         := $028F        ; Current output device number
+TIME            := $0292        ; 60 Hz. clock (3 bytes, big-endian)
+FNAM_LEN        := $0298        ; Length of filename
+SECADR          := $029A        ; Secondary address
+DEVNUM          := $029B        ; Device number
+KEY_COUNT       := $029E        ; Number of keys in input buffer
+RVS             := $029F        ; Reverse flag
+CURS_FLAG       := $02A3        ; 1 = cursor off
+CURS_BLINK      := $02A4        ; Blink counter
+CURS_CHAR       := $02A5        ; Character under the cursor
+CURS_STATE      := $02A6        ; Cursor blink state
+CURS_X          := $02A8        ; Cursor column
+CURS_Y          := $02AB        ; Cursor row
+LLEN            := $02AE        ; Line length
+NLINES          := $02AF        ; Number of screen lines
+JOY1            := $02BC        ; 3 bytes of NES/SNES gamepad data
+JOY2            := $02BF
+
+; BASIC
+VARTAB          := $02DD        ; Pointer to start of BASIC variables
+MEMSIZE         := $02E5        ; Pointer to highest BASIC RAM location (+1)
+
+; Kernal mouse
+MSEPAR          := $0371        ; mouse: $8x=sprite on, 1/2: scale
+MOUSEL          := $0372        ; min. x co-ordinate
+MOUSER          := $0374        ; max. x co-ordinate
+MOUSET          := $0376        ; min. y co-ordinate
+MOUSEB          := $0378        ; max. y co-ordinate
+MOUSEX          := $037A        ; x co-ordinate
+MOUSEY          := $037C        ; y co-ordinate
+MOUSEBT         := $037E        ; buttons (bits 2: middle, 1: right, 0: left)
 
 ; ---------------------------------------------------------------------------
 ; Vector and other locations
@@ -122,6 +135,12 @@ NMIVec          := $0318
   INC8192       =       14 << 4
   INC16384      =       15 << 4
   .endenum
+  .enum                         ; Interrupt request flags
+  VERT_SYNC     =       %00000001
+  RASTER        =       %00000010
+  SPR_COLLIDED  =       %00000100
+  UART_IRQ      =       %00001000
+  .endenum
   ; Internal RAM and registers
   VRAM          :=      $000000
   .scope        COMPOSER        ; Display composer
@@ -263,7 +282,7 @@ NMIVec          := $0318
   .endscope
 .endscope
 
-; 65c22
+; 65C22
 .struct VIA1                    ; Versatile Interface Adapter
         .org    $9F60
   PRB   .byte                   ; ROM bank, IEC  (Port Register B)
@@ -281,10 +300,10 @@ NMIVec          := $0318
   PRA2  .byte                   ; RAM bank  (Port Register A without handshaking)
 .endstruct
 
-; 65c22
+; 65C22
 .struct VIA2
         .org    $9F70
-  PRB   .byte
+  PRB   .byte                   ; Mouse communication ?
   PRA   .byte                   ; NES controller communication
   DDRB  .byte
   DDRA  .byte
diff --git a/cfg/cx16-asm.cfg b/cfg/cx16-asm.cfg
index 53f6da17..4228f6da 100644
--- a/cfg/cx16-asm.cfg
+++ b/cfg/cx16-asm.cfg
@@ -6,12 +6,13 @@ SYMBOLS {
     __HIMEM__:    type = weak, value = $9F00;
 }
 MEMORY {
-    ZP:       file = "", start = $0004,  size = $0090 - $0004, define = yes;
+    ZP:       file = "", start = $0002,  size = $0080 - $0002, define = yes;
     LOADADDR: file = %O, start = %S - 2, size = $0002;
     MAIN:     file = %O, start = %S,     size = __HIMEM__ - %S;
 }
 SEGMENTS {
     ZEROPAGE: load = ZP,       type = zp;
+    EXTZP:    load = ZP,       type = zp, optional = yes;
     LOADADDR: load = LOADADDR, type = ro;
     EXEHDR:   load = MAIN,     type = ro, optional = yes;
     LOWCODE:  load = MAIN,     type = ro, optional = yes;
diff --git a/cfg/cx16-bank.cfg b/cfg/cx16-bank.cfg
index 52438fba..ff5dded3 100644
--- a/cfg/cx16-bank.cfg
+++ b/cfg/cx16-bank.cfg
@@ -11,7 +11,7 @@ SYMBOLS {
     __BANKRAMSIZE__:  type = weak,   value = $2000; # 8K banked RAM
 }
 MEMORY {
-    ZP:         file = "", define = yes,  start = $0004,                size = $0090 - $0004;
+    ZP:         file = "", define = yes,  start = $0002,                size = $0080 - $0002;
     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__ - __HEADER_LAST__;
diff --git a/cfg/cx16.cfg b/cfg/cx16.cfg
index f912e0f8..c72f6c35 100644
--- a/cfg/cx16.cfg
+++ b/cfg/cx16.cfg
@@ -8,7 +8,7 @@ SYMBOLS {
     __HIMEM__:        type = weak,   value = $9F00;
 }
 MEMORY {
-    ZP:       file = "", define = yes, start = $0004,                size = $0090 - $0004;
+    ZP:       file = "", define = yes, start = $0002,                size = $0080 - $0002;
     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__ - __HEADER_LAST__;
diff --git a/doc/cx16.sgml b/doc/cx16.sgml
index b739e6a9..16e43db9 100644
--- a/doc/cx16.sgml
+++ b/doc/cx16.sgml
@@ -17,14 +17,14 @@ compiler.
 <sect>Overview<p>
 
 The Commander X16 is a modern small computer with firmware that is based on
-the ROMs in Commodore's VIC-20 and 64C.  It has a couple of the I/O chips that
-are in the VIC-20.
+the ROMs in Commodore's VIC-20 and 64C.  It has a couple of I/O chips
+(WDC65C22 VIA) that are like the ones in the VIC-20.
 
 This file contains an overview of the CX16 run-time system as it comes with the
-cc65 C compiler. It describes the memory layout, CX16-specific header files,
+cc65 C compiler.  It describes the memory layout, CX16-specific header files,
 available drivers, and any pitfalls specific to that platform.
 
-Please note that CX16-specific functions just are mentioned here; they are
+Please note that CX16-specific functions just are mentioned here; they might be
 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
@@ -35,19 +35,20 @@ information.
 <sect>Binary format<p>
 
 The standard binary output format generated by the linker for the CX16 target
-is a machine language program with a one-line BASIC stub which calls the
-machine language part via SYS. That means that a program can be loaded as a
-BASIC program, and started with RUN. It is, of course, possible to change that
-behaviour by using a modified start-up file and linker config.
+is a machine language program that's prepended with a 16-bit load address and a
+one-line BASIC stub which calls the machine language part via SYS.  That means
+that a program can be loaded as a BASIC program, and started with RUN.  It is,
+of course, possible to change that behaviour by using a modified program-header
+file and linker config.
 
 
 
 <sect>Memory layout<p>
 
-cc65-generated programs with the default setup run with the I/O area and the
-Kernal ROM visible.  That means that Kernal entry points can be called directly.
-The usable memory ranges are &dollar;0800 - &dollar;9EFF and &dollar;A000 -
-&dollar;BFFF.
+cc65-generated programs with the default setup run with the I/O area, RAM bank
+zero, and the Kernal ROM visible.  That means that Kernal entry points can be
+called directly. The usable memory ranges are &dollar;0800 - &dollar;9EFF and
+&dollar;A000 - &dollar;BFFF.
 
 Special locations:
 
@@ -76,6 +77,9 @@ The ld65 linker comes with a default config. file for the Commander X16, which
 is used via <tt/-t cx16/. The cx16 package comes with additional secondary
 linker config. files which are used via <tt/-t cx16 -C &lt;configfile&gt;/.
 
+Those files use 126 bytes in the zero page.  (The rest of page zero is reserved
+for Kernal and BASIC.)
+
 
 <sect1>Default config. file (<tt/cx16.cfg/)<p>
 
@@ -138,6 +142,8 @@ url="funcref.html" name="function reference"> for declarations and usage.
 <item>get_ostype()
 <item>set_tv()
 <item>videomode()
+<item>vpeek()
+<item>vpoke()
 <item>waitvsync()
 </itemize>
 
@@ -157,6 +163,7 @@ declarations and usage.
 <item>cbm_k_ckout()
 <item>cbm_k_close()
 <item>cbm_k_clrch()
+<item>cbm_k_getin()
 <item>cbm_k_load()
 <item>cbm_k_open()
 <item>cbm_k_readst()
@@ -217,13 +224,13 @@ No extended memory drivers are available currently for the CX16.
 <sect1>Joystick drivers<p>
 
 The default drivers, <tt/joy_stddrv (joy_static_stddrv)/,
-point to <tt/cX16-stdjoy.joy (cx16_stdjoy_joy)/.
+point to <tt/cX16-std.joy (cx16_std_joy)/.
 
 <descrip>
-  <tag><tt/cX16-stdjoy.joy (cX16_stdjoy_joy)/</tag>
-  Supports up to two NES and SNES controllers connected to the joystick ports
+  <tag><tt/cX16-std.joy (cX16_std_joy)/</tag>
+  Supports up to two NES (and SNES) controllers connected to the joystick ports
   of the CX16.  It reads the four directions, and the A, B, Select, and Start
-  buttons.  Button A is the primary fire button.
+  buttons.  Buttons A and B are the primary and secondary fire buttons.
 </descrip><p>
 
 
@@ -248,9 +255,16 @@ any time.  Some changes could make old programs fail to work.
 <sect>Other hints<p>
 
 
+<sect1>STOP and RUN codes<p>
+
+The <tt/Esc/ key acts as Commodore's <tt/STOP/ key -- or, you can press the
+<tt/Ctrl/ key and the <tt/C/ key together.  Pressing the <tt/Shift/ and the
+<tt/Esc/ keys together will type Commodore's <tt/RUN/ key.
+
+
 <sect1>Escape code<p>
 
-For an Esc, press <tt/Ctrl/ and the <tt/[/ key.
+For an <tt/Esc/, press the <tt/Ctrl/ key and the <tt/[/ key together.
 
 
 <sect1>Passing arguments to the program<p>
@@ -274,7 +288,7 @@ supported directly by BASIC, the following syntax was chosen:
 
 <sect1>Program return code<p>
 
-The program return code (low byte) is passed back to BASIC by use of the
+The program return code (low byte) is passed back to BASIC by the use of its
 <tt/ST/ variable.
 
 
diff --git a/include/cx16.h b/include/cx16.h
index a2f52850..a6f1b78f 100644
--- a/include/cx16.h
+++ b/include/cx16.h
@@ -100,6 +100,9 @@
 #define JOY_FIRE2_MASK  JOY_BTN_2_MASK
 #define JOY_FIRE2(v)    ((v) & JOY_FIRE2_MASK)
 
+/* Additional mouse button mask */
+#define MOUSE_BTN_MIDDLE     0x02
+
 /* get_tv() return codes
 ** set_tv() argument codes
 */
@@ -113,10 +116,12 @@
 #define TV_RGB2         7
 
 /* Video mode defines */
-#define VIDEOMODE_40x30         40u
-#define VIDEOMODE_80x60         80u
+#define VIDEOMODE_40x30         0x00
+#define VIDEOMODE_80x60         0x02
 #define VIDEOMODE_40COL         VIDEOMODE_40x30
 #define VIDEOMODE_80COL         VIDEOMODE_80x60
+#define VIDEOMODE_320x240       0x80
+#define VIDEOMODE_SWAP          (-1)
 
 
 /* Define hardware */
@@ -157,7 +162,7 @@ struct __emul {
 
 /* The addresses of the static drivers */
 
-extern void cx16_stdjoy_joy[];          /* Referred to by joy_static_stddrv[] */
+extern void cx16_std_joy[];             /* Referred to by joy_static_stddrv[] */
 
 
 
@@ -174,14 +179,20 @@ signed char get_ostype (void);
 ** Positive -- release build
 */
 
+unsigned char get_tv (void);
+/* Return the video type that the machine is using.
+** Return a TV_xx constant.
+*/
+
 void __fastcall__ set_tv (unsigned char type);
 /* Set the video type that the machine will use.
 ** Call with a TV_xx constant.
 */
 
-unsigned char __fastcall__ videomode (unsigned char mode);
-/* Set the video mode, return the old mode. Call with one of the VIDEOMODE_xx
-** constants.
+signed char __fastcall__ videomode (signed char mode);
+/* Set the video mode, return the old mode.
+** Return -1 if Mode isn't valid.
+** Call with one of the VIDEOMODE_xx constants.
 */
 
 unsigned char __fastcall__ vpeek (unsigned long addr);
diff --git a/libsrc/cx16/break.s b/libsrc/cx16/break.s
index ec569b9a..6c79c903 100644
--- a/libsrc/cx16/break.s
+++ b/libsrc/cx16/break.s
@@ -1,6 +1,6 @@
 ;
 ; 1998-09-27, Ullrich von Bassewitz
-; 2019-09-08, Greg King
+; 2019-11-06, Greg King
 ;
 ; void __fastcall__ set_brk (unsigned Addr);
 ; void reset_brk (void);
@@ -30,6 +30,7 @@ uservec:        jmp     $FFFF           ; Patched at runtime
 .code
 
 ; Set the break vector
+
 .proc   _set_brk
 
         sta     uservec+1
@@ -40,9 +41,9 @@ uservec:        jmp     $FFFF           ; Patched at runtime
         bne     L1              ; Jump if we installed the handler already
 
         lda     BRKVec
+        ldx     BRKVec+1
         sta     oldvec
-        lda     BRKVec+1
-        sta     oldvec+1        ; Save the old vector
+        stx     oldvec+1        ; Save the old vector
 
 L1:     lda     #<brk_handler   ; Set the break vector to our routine
         ldx     #>brk_handler
@@ -54,6 +55,7 @@ L1:     lda     #<brk_handler   ; Set the break vector to our routine
 
 
 ; Reset the break vector
+
 .proc   _reset_brk
 
         lda     oldvec
@@ -61,15 +63,15 @@ L1:     lda     #<brk_handler   ; Set the break vector to our routine
         beq     @L9             ; Jump if vector not installed
         sta     BRKVec
         stx     BRKVec+1
+
         lda     #$00
         sta     oldvec          ; Clear the old vector
-        stx     oldvec+1
+        sta     oldvec+1
 @L9:    rts
 
 .endproc
 
 
-
 ; Break handler, called if a break occurs
 
 .proc   brk_handler
@@ -81,14 +83,13 @@ L1:     lda     #<brk_handler   ; Set the break vector to our routine
         pla
         sta     _brk_a
         pla
-        and     #$EF            ; Clear break bit
         sta     _brk_sr
         pla                     ; PC low
         sec
-        sbc     #2              ; Point to start of brk
+        sbc     #<$0002         ; Point to start of BRK
         sta     _brk_pc
         pla                     ; PC high
-        sbc     #0
+        sbc     #>$0002
         sta     _brk_pc+1
 
         jsr     uservec         ; Call the user's routine
@@ -99,11 +100,9 @@ L1:     lda     #<brk_handler   ; Set the break vector to our routine
         pha
         lda     _brk_sr
         pha
-        ldx     _brk_x
         ldy     _brk_y
+        ldx     _brk_x
         lda     _brk_a
         rti                     ; Jump back...
 
 .endproc
-
-
diff --git a/libsrc/cx16/conio.s b/libsrc/cx16/conio.s
deleted file mode 100644
index e760af21..00000000
--- a/libsrc/cx16/conio.s
+++ /dev/null
@@ -1,9 +0,0 @@
-;
-; 2019-09-23, Greg King
-;
-; Low-level stuff for screen output/console input
-;
-
-        .exportzp       CURS_X, CURS_Y
-
-        .include        "cx16.inc"
diff --git a/libsrc/cx16/cpeekc.s b/libsrc/cx16/cpeekc.s
index 2f02623b..f7a7d208 100644
--- a/libsrc/cx16/cpeekc.s
+++ b/libsrc/cx16/cpeekc.s
@@ -19,7 +19,7 @@ _cpeekc:
         sta     VERA::ADDR+1    ; set row number
         stz     VERA::ADDR+2
         lda     CURS_X          ; get character column
-        asl     a
+        asl     a               ; each character has two bytes
         sta     VERA::ADDR
         lda     VERA::DATA0     ; get screen code
         plp
diff --git a/libsrc/cx16/cpeekrevers.s b/libsrc/cx16/cpeekrevers.s
index d67dd295..15131d34 100644
--- a/libsrc/cx16/cpeekrevers.s
+++ b/libsrc/cx16/cpeekrevers.s
@@ -21,7 +21,7 @@ _cpeekrevers:
         sta     VERA::ADDR+1    ; set row number
         stz     VERA::ADDR+2
         lda     CURS_X          ; get character column
-        asl     a
+        asl     a               ; each character has two bytes
         sta     VERA::ADDR
         lda     VERA::DATA0     ; get screen code
         plp
diff --git a/libsrc/cx16/cputc.s b/libsrc/cx16/cputc.s
index cf0a5fa2..11c4f578 100644
--- a/libsrc/cx16/cputc.s
+++ b/libsrc/cx16/cputc.s
@@ -78,7 +78,7 @@ plot:   ldy     CURS_X
 
 
 ; Write one screen-code and color to the video RAM without doing anything else.
-; Return the x position in Y.
+; Return the x position in .Y .
 
 putchar:
         ora     RVS             ; Set revers bit
@@ -90,7 +90,7 @@ putchar:
         sta     VERA::ADDR+2
         ldy     CURS_X          ; Get character column
         tya
-        asl     a
+        asl     a               ; Each character has two bytes
         sta     VERA::ADDR
         stx     VERA::DATA0
         lda     CHARCOLOR
diff --git a/libsrc/cx16/crt0.s b/libsrc/cx16/crt0.s
index 873fd706..bfb4de10 100644
--- a/libsrc/cx16/crt0.s
+++ b/libsrc/cx16/crt0.s
@@ -9,7 +9,6 @@
         .import         zerobss, callmain
         .import         CHROUT
         .import         __MAIN_START__, __MAIN_SIZE__   ; Linker-generated
-        .importzp       ST
 
         .include        "zeropage.inc"
         .include        "cx16.inc"
@@ -36,11 +35,18 @@ Start:  tsx
 
         jsr     callmain
 
-; Back from main() [this is also the exit() entry]. Run the module destructors.
+; Back from main() [this is also the exit() entry].
+
+_exit:
+; Put the program return code into BASIC's status variable.
+
+        sta     STATUS
+
+; Run the module destructors.
 
-_exit:  pha                     ; Save the return code on stack
         jsr     donelib
 
+.if 0   ; We no longer need to preserve zero-page space for cc65's variables.
 ; Copy back the zero-page stuff.
 
         ldx     #zpspace-1
@@ -48,11 +54,7 @@ L2:     lda     zpsave,x
         sta     sp,x
         dex
         bpl     L2
-
-; Place the program return code into BASIC's status variable.
-
-        pla
-        sta     ST
+.endif
 
 ; Restore the system stuff.
 
@@ -88,6 +90,7 @@ init:
         lda     #$00            ; Choose RAM bank zero
         sta     VIA1::PRA2
 
+.if 0   ; We no longer need to preserve zero-page space for cc65's variables.
 ; Save the zero-page locations that we need.
 
         ldx     #zpspace-1
@@ -95,6 +98,7 @@ L1:     lda     sp,x
         sta     zpsave,x
         dex
         bpl     L1
+.endif
 
 ; Set up the stack.
 
@@ -121,4 +125,6 @@ L1:     lda     sp,x
 ramsave:
         .res    1
 spsave: .res    1
+.if 0
 zpsave: .res    zpspace
+.endif
diff --git a/libsrc/cx16/devnum.s b/libsrc/cx16/devnum.s
deleted file mode 100644
index 6a59d6ec..00000000
--- a/libsrc/cx16/devnum.s
+++ /dev/null
@@ -1,8 +0,0 @@
-;
-; 2010-02-14, Oliver Schmidt
-; 2019-09-08, Greg King
-;
-
-        .include        "cx16.inc"
-
-        .exportzp       devnum := DEVNUM
diff --git a/libsrc/cx16/exec.c b/libsrc/cx16/exec.c
new file mode 100644
index 00000000..90af4e40
--- /dev/null
+++ b/libsrc/cx16/exec.c
@@ -0,0 +1,122 @@
+/*
+** Program-chaining function for Commodore platforms.
+**
+** 2019-11-08, Greg King
+**
+** This function exploits the program-chaining feature in Commander X16 BASIC's ROM.
+**
+** CC65's CBM programs have a BASIC program stub.  We start those programs by
+** RUNning that stub; it SYSes to the Machine Language code.  Normally, after
+** the ML code exits, the BASIC ROM continues running the stub.  But, it has
+** no more statements; so, the program stops.
+**
+** This function puts the desired program's name and device number into a LOAD
+** statement.  Then, it points BASIC to that statement, so that the ROM will run
+** that statement after this program quits.  The ROM will load the next program,
+** and will execute it (because the LOAD will be seen in a running program).
+*/
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <device.h>
+
+
+/* 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 CLR:LOAD""+""                    ,01
+** After this function has written into the line, it might look like this:
+**  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 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 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;             /* fake previous line */
+    const struct line* const next;
+    const unsigned line_num;
+    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, 0x9C, ':', 0x93, "\"\"", 0xAA, '\"',
+    "\"                    ",           /* format: "123:1234567890123456\"" */
+    ',', "01"
+};
+#pragma data-name(pop)
+
+/* These values are platform-specific. */
+extern const void* vartab;              /* points to BASIC program variables */
+extern const void* memsize;             /* points to top of BASIC RAM */
+extern const struct line* txtptr;       /* points to BASIC code */
+#pragma zpsym("txtptr")
+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;
+
+    /* Exclude devices that can't load files. */
+    /* (Use hand optimization, to make smaller code.) */
+    dv = getcurrentdevice ();
+    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 doesn't exist. */
+    fd = open (progname, O_RDONLY);
+    if (fd < 0) {
+        return _mappederrno (4);        /* file not found */
+    }
+    close (fd);
+
+    n = 0;
+    do {
+        if ((basic.name[n] = progname[n]) == '\0') {
+            break;
+        }
+    } while (++n < 20);                 /* truncate long names */
+    basic.name[n] = '\"';
+
+    /* 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;
+
+    /* Build the next program's argument list. */
+    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. */
+    txtptr = &basic;
+
+    /* (The return code, in STATUS, will be destroyed by LOAD.
+    ** So, don't bother to set it here.)
+    */
+    exit (__AX__);
+}
diff --git a/libsrc/cx16/execvars.s b/libsrc/cx16/execvars.s
new file mode 100644
index 00000000..2df647a5
--- /dev/null
+++ b/libsrc/cx16/execvars.s
@@ -0,0 +1,16 @@
+;
+; Platform-specific variables for the exec program-chaining function
+;
+
+        .include        "cx16.inc"
+
+; exec() is written in C.
+; Provide the spellings that the C compiler wants to use.
+
+.export _vartab         :=      VARTAB
+.export _memsize        :=      MEMSIZE
+
+.exportzp _txtptr       :=      TXTPTR
+
+.export   _basbuf       :=      BASIC_BUF
+.exportzp _basbuf_len   =       BASIC_BUF_LEN
diff --git a/libsrc/cx16/filevars.s b/libsrc/cx16/filevars.s
new file mode 100644
index 00000000..f3fa6466
--- /dev/null
+++ b/libsrc/cx16/filevars.s
@@ -0,0 +1,39 @@
+;
+; 2002-11-15, Ullrich von Bassewitz
+; 2019-11-08, Greg King
+;
+; Variables used for CBM file I/O
+;
+
+        .export         curunit
+        .constructor    initcurunit, 30
+        .destructor     updatedevnum, 30
+
+        .include        "cx16.inc"
+
+
+.segment "INIT"
+
+curunit:
+        .res    1
+
+
+.segment "ONCE"
+
+.proc   initcurunit
+        lda     DEVNUM
+        bne     L0
+        lda     #8              ; Default is SD card
+        sta     DEVNUM
+L0:     sta     curunit
+        rts
+.endproc
+
+
+.code
+
+.proc   updatedevnum
+        lda     curunit
+        sta     DEVNUM
+        rts
+.endproc
diff --git a/libsrc/cx16/getdevice.s b/libsrc/cx16/getdevice.s
new file mode 100644
index 00000000..9b554900
--- /dev/null
+++ b/libsrc/cx16/getdevice.s
@@ -0,0 +1,67 @@
+;
+; 2012-09-04, Oliver Schmidt
+; 2019-11-08, Greg King
+;
+; unsigned char getfirstdevice (void);
+; unsigned char __fastcall__ getnextdevice (unsigned char device);
+;
+
+        .export         _getfirstdevice
+        .export         _getnextdevice
+        .import         isdisk
+        .import         opencmdchannel
+        .import         closecmdchannel
+        .importzp       tmp2
+
+        .include        "cx16.inc"
+
+;------------------------------------------------------------------------------
+; getfirstdevice()
+
+_getfirstdevice:
+        lda     #$FF
+        ; Fall through
+
+;------------------------------------------------------------------------------
+; getnextdevice()
+
+_getnextdevice:
+        tax
+next:   inx
+        cpx     #$FF
+        beq     done
+
+; [open|close]cmdchannel already call isdisk internally; but, they
+; interpret a non-disk as a no-op, while we need to interpret it
+; as an error here.
+
+        jsr     isdisk
+        bcs     next
+
+; [open|close]cmdchannel don't call into the Kernal, at all, if they
+; only [in|de]crement the reference count of the shared cmdchannel.
+; Therefore, we need to initiate STATUS explicitly here.
+
+        lda     #$00
+        sta     STATUS
+
+        stx     tmp2
+        jsr     opencmdchannel
+        ldx     tmp2
+        jsr     closecmdchannel
+        ldx     tmp2
+
+; As we had to reference ST above anyway, we can do so, as well,
+; here too (instead of calling READST).
+
+        lda     STATUS
+
+; Either the Kernal calls above were successfull, or there was
+; already a cmdchannel to the device open -- which is a pretty
+; good indication of its existence. ;-)
+
+        bmi     next
+
+done:   txa
+        ldx     #$00
+        rts
diff --git a/libsrc/cx16/gotox.s b/libsrc/cx16/gotox.s
new file mode 100644
index 00000000..1cd7c693
--- /dev/null
+++ b/libsrc/cx16/gotox.s
@@ -0,0 +1,13 @@
+;
+; 2019-11-06, Greg King
+;
+; void fastcall gotox (unsigned char x);
+;
+
+        .export         _gotox
+
+        .import         plot
+        .include        "cx16.inc"
+
+_gotox: sta     CURS_X          ; Set new position
+        jmp     plot            ; And activate it
diff --git a/libsrc/cx16/gotoxy.s b/libsrc/cx16/gotoxy.s
new file mode 100644
index 00000000..1c1b60e2
--- /dev/null
+++ b/libsrc/cx16/gotoxy.s
@@ -0,0 +1,18 @@
+;
+; 2019-11-06, Greg King
+;
+; void fastcall gotoxy (unsigned char x, unsigned char y);
+;
+
+        .export         gotoxy, _gotoxy
+
+        .import         popa, plot
+        .include        "cx16.inc"
+
+gotoxy: jsr     popa            ; Get Y
+
+_gotoxy:
+        sta     CURS_Y          ; Set Y
+        jsr     popa            ; Get X
+        sta     CURS_X          ; Set X
+        jmp     plot            ; Set the cursor position
diff --git a/libsrc/cx16/gotoy.s b/libsrc/cx16/gotoy.s
new file mode 100644
index 00000000..487cfa79
--- /dev/null
+++ b/libsrc/cx16/gotoy.s
@@ -0,0 +1,13 @@
+;
+; 2019-11-06, Greg King
+;
+; void gotoy (unsigned char y);
+;
+
+        .export         _gotoy
+
+        .import         plot
+        .include        "cx16.inc"
+
+_gotoy: sta     CURS_Y          ; Set the new position
+        jmp     plot            ; And activate it
diff --git a/libsrc/cx16/joy/cx16-stdjoy.s b/libsrc/cx16/joy/cx16-std.s
similarity index 58%
rename from libsrc/cx16/joy/cx16-stdjoy.s
rename to libsrc/cx16/joy/cx16-std.s
index 8c7ddd2f..b41c6606 100644
--- a/libsrc/cx16/joy/cx16-stdjoy.s
+++ b/libsrc/cx16/joy/cx16-std.s
@@ -1,8 +1,8 @@
 ;
 ; Standard joystick driver for the CX16.
-; May be used multiple times when statically linked to the application.
+; May be installed multiple times when statically linked to the application.
 ;
-; 2019-09-23, Greg King
+; 2019-11-15 Greg King
 ;
 
         .include        "joy-kernel.inc"
@@ -18,7 +18,7 @@
 ; ------------------------------------------------------------------------
 ; Header. Includes jump table
 
-        module_header   _cx16_stdjoy_joy
+        module_header   _cx16_std_joy
 
 ; Driver signature
 
@@ -48,11 +48,10 @@ JOY_COUNT       = 2             ; Number of joysticks we support
 .code
 
 ; ------------------------------------------------------------------------
-; INSTALL routine. Is called after the driver is loaded into memory.
+; 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 a JOY_ERR_xx code in a/x.
-;
+; Must return a JOY_ERR_xx code in .XA .
 
 INSTALL:
         lda     #<JOY_ERR_OK
@@ -60,60 +59,67 @@ INSTALL:
 ;       rts                     ; Run into UNINSTALL instead
 
 ; ------------------------------------------------------------------------
-; UNINSTALL routine. Is called before the driver is removed from memory.
-; Can do clean-up or whatever. Must not return anything.
-;
+; UNINSTALL routine -- is called before the driver is removed from memory.
+; Can do clean-up or whatever.  Shouldn't return anything.
 
 UNINSTALL:
         rts
 
 ; ------------------------------------------------------------------------
-; COUNT: Return the total number of possible joysticks in a/x.
-;
+; COUNT: Return the total number of possible joysticks, in .XA .
 
 COUNT:  lda     #<JOY_COUNT
         ldx     #>JOY_COUNT
         rts
 
 ; ------------------------------------------------------------------------
-; READ: Read a particular joystick passed in A.
-;
-; TODO: Find a way to report the SNES controller's extra four lines.
-;
+; READ: Read a particular joystick passed in .A .
 
-READ:   pha
-        jsr     GETJOY
-        pla
-        bne     pad2
+READ:   php
+        bit     #JOY_COUNT - $01
+        sei
+        bnz     pad2
 
 ; Read game pad 1
 
-pad1:   lda     JOY1 + 1
+pad1:   ldy     JOY1            ; Allow JOY1 to be reread between interrupts
+        sty     JOY1 + 2
+
+        lda     JOY1 + 1
         bit     #%00001110
-        beq     nes1
-        asl     JOY1            ; Get SNES's B button
+        bze     nes1
+
+        asl     JOY1 + 2        ; Get SNES's B button
         ror     a               ; Put it next to the A button
-        asl     JOY1            ; Drop SNES's Y button
-        asl     a               ; Get the B button
-        ror     JOY1
+        asl     JOY1 + 2        ; Drop SNES's Y button
+        asl     a               ; Get back the B button
+        ror     JOY1 + 2
         asl     a               ; Get SNES's A button
-        ror     JOY1            ; Make byte look like NES pad
-nes1:   lda     JOY1
-        eor     #%11111111      ; We don't want the pad's negative logic
+        ror     JOY1 + 2        ; Make byte look like NES pad
+
+nes1:   lda     JOY1 + 2
+        plp
+        eor     #%11111111      ; (The controllers use negative logic)
         rts
 
 ; Read game pad 2
 
-pad2:   lda     JOY2 + 1
+pad2:   ldy     JOY2
+        sty     JOY2 + 2
+
+        lda     JOY2 + 1
         bit     #%00001110
-        beq     nes2
-        asl     JOY2
+        bze     nes2
+
+        asl     JOY2 + 2
         ror     a
-        asl     JOY2
+        asl     JOY2 + 2
         asl     a
-        ror     JOY2
+        ror     JOY2 + 2
         asl     a
-        ror     JOY2
-nes2:   lda     JOY2
+        ror     JOY2 + 2
+
+nes2:   lda     JOY2 + 2
+        plp
         eor     #%11111111
         rts
diff --git a/libsrc/cx16/joy_stat_stddrv.s b/libsrc/cx16/joy_stat_stddrv.s
index 0e1a3e94..08cd2f95 100644
--- a/libsrc/cx16/joy_stat_stddrv.s
+++ b/libsrc/cx16/joy_stat_stddrv.s
@@ -1,10 +1,11 @@
 ;
 ; Address of the static standard joystick driver
 ;
-; 2019-09-19, Greg King
+; 2019-11-10, Greg King
 ;
 ; const void joy_static_stddrv[];
 ;
 
-        .import _cx16_stdjoy_joy
-        .export _joy_static_stddrv := _cx16_stdjoy_joy
+        .import _cx16_std_joy
+
+        .export _joy_static_stddrv := _cx16_std_joy
diff --git a/libsrc/cx16/joy_stddrv.s b/libsrc/cx16/joy_stddrv.s
index 4edf9afc..ff2f54de 100644
--- a/libsrc/cx16/joy_stddrv.s
+++ b/libsrc/cx16/joy_stddrv.s
@@ -1,7 +1,7 @@
 ;
 ; Name of the standard joystick driver
 ;
-; 2019-09-19, Greg King
+; 2019-11-10, Greg King
 ;
 ; const char joy_stddrv[];
 ;
@@ -10,4 +10,4 @@
 
 .rodata
 
-_joy_stddrv:    .asciiz "cx16-stdjoy.joy"
+_joy_stddrv:    .asciiz "cx16-std.joy"
diff --git a/libsrc/cx16/joyref.s b/libsrc/cx16/joyref.s
new file mode 100644
index 00000000..fb21918c
--- /dev/null
+++ b/libsrc/cx16/joyref.s
@@ -0,0 +1,20 @@
+;
+; 2019-11-14, Greg King
+;
+; Link an interrupt handler if joysticks are used by a program.
+;
+
+        .interruptor    joy_libref, 9
+
+        .include        "cbm_kernal.inc"
+        .include        "cx16.inc"
+
+
+joy_libref:
+        lda     VERA::IRQ_FLAGS
+        lsr     a
+        bcc     not_vsync
+        jsr     GETJOY          ; Bit-bang game controllers
+        clc                     ; Let other Jiffy handlers run
+not_vsync:
+        rts
diff --git a/libsrc/cx16/kbhit.s b/libsrc/cx16/kbhit.s
index 8ceba64b..a73533e2 100644
--- a/libsrc/cx16/kbhit.s
+++ b/libsrc/cx16/kbhit.s
@@ -1,5 +1,5 @@
 ;
-; 2019-09-20, Greg King
+; 2019-11-06, Greg King
 ;
 ; unsigned char kbhit (void);
 ; /* Returns non-zero (true) if a typed character is waiting. */
@@ -11,7 +11,7 @@
 
 
 .proc   _kbhit
-        ldx     #>$0000         ; High byte of return
         lda     KEY_COUNT       ; Get number of characters
-        rts
+        tax                     ; High byte of return (only its zero/nonzero ...
+        rts			; ... state matters)
 .endproc
diff --git a/libsrc/cx16/kernal.s b/libsrc/cx16/kernal.s
index faf91385..97443c82 100644
--- a/libsrc/cx16/kernal.s
+++ b/libsrc/cx16/kernal.s
@@ -1,5 +1,5 @@
 ;
-; 2019-09-22, Greg King
+; 2019-11-05, Greg King
 ;
 ; CX16 Kernal functions
 ;
@@ -7,9 +7,10 @@
         .include        "cbm_kernal.inc"
 
         .export         GETJOY
+        .export         MOUSE
+        .export         SCRMOD
 
         .export         CLSALL
-        .export         SWAPPER
         .export         JSRFAR
         .export         INDFET
         .export         INDSTA
diff --git a/libsrc/cx16/libref.s b/libsrc/cx16/libref.s
index 54ebb91d..0d85c7cd 100644
--- a/libsrc/cx16/libref.s
+++ b/libsrc/cx16/libref.s
@@ -1,10 +1,9 @@
 ;
 ; 2013-05-31, Oliver Schmidt
-; 2019-09-22, Greg King
+; 2019-11-14, Greg King
 ;
 
         .export         em_libref
-        .export         joy_libref
         .export         mouse_libref
         .export         ser_libref
         .export         tgi_libref
@@ -12,7 +11,6 @@
         .import         _exit
 
 em_libref       := _exit
-joy_libref      := _exit
 mouse_libref    := _exit
 ser_libref      := _exit
 tgi_libref      := _exit
diff --git a/libsrc/cx16/mainargs.s b/libsrc/cx16/mainargs.s
index fe4a071c..1764b5e2 100644
--- a/libsrc/cx16/mainargs.s
+++ b/libsrc/cx16/mainargs.s
@@ -33,7 +33,7 @@ REM      = $8f                  ; BASIC token-code
 NAME_LEN = 16                   ; Maximum length of command-name
 
 ; Get possible command-line arguments. Goes into the special ONCE segment,
-; which may be reused after the startup code is run
+; which may be reused after the startup code is run.
 
 .segment        "ONCE"
 
@@ -64,7 +64,7 @@ L2:     lda     BASIC_BUF,x
         bne     L2
         ldy     #1 * 2
 
-; Find the next argument
+; Find the next argument.
 
 next:   lda     BASIC_BUF,x
         beq     done            ; End of line reached
@@ -74,7 +74,7 @@ next:   lda     BASIC_BUF,x
 
 ; 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
-; will check now for a quoted argument, in which case we will have to skip this
+; will check now for a quoted argument, in which case, we will have to skip this
 ; first character.
 
 found:  cmp     #'"'            ; Is the argument quoted?
@@ -95,7 +95,7 @@ setterm:sta     term            ; Set end of argument marker
         iny
         inc     __argc          ; Found another arg
 
-; Search for the end of the argument
+; Search for the end of the argument.
 
 argloop:lda     BASIC_BUF,x
         beq     done
diff --git a/libsrc/cx16/set_tv.s b/libsrc/cx16/set_tv.s
index 0cf49aff..8b802f32 100644
--- a/libsrc/cx16/set_tv.s
+++ b/libsrc/cx16/set_tv.s
@@ -1,5 +1,5 @@
 ;
-; 2019-09-20, Greg King
+; 2019-11-06, Greg King
 ;
 ; void __fastcall__ set_tv (unsigned char);
 ; /* Set the video mode the machine will use. */
@@ -12,20 +12,18 @@
 
 .proc   _set_tv
         php
-        pha
         sei                             ; Don't let interrupts interfere
 
         ; Point to the video output register.
 
         stz     VERA::CTRL              ; Use port 0
-        lda     #<VERA::COMPOSER::VIDEO
-        ldx     #>VERA::COMPOSER::VIDEO
-        ldy     #^VERA::COMPOSER::VIDEO
-        sta     VERA::ADDR
-        stx     VERA::ADDR+1
-        sty     VERA::ADDR+2
+        ldx     #<VERA::COMPOSER::VIDEO
+        ldy     #>VERA::COMPOSER::VIDEO
+        stx     VERA::ADDR
+        sty     VERA::ADDR+1
+        ldx     #^VERA::COMPOSER::VIDEO
+        stx     VERA::ADDR+2
 
-        pla
         sta     VERA::DATA0
         plp                             ; Re-enable interrupts
         rts
diff --git a/libsrc/cx16/status.s b/libsrc/cx16/status.s
index 6292dc27..e3446637 100644
--- a/libsrc/cx16/status.s
+++ b/libsrc/cx16/status.s
@@ -1,6 +1,16 @@
 ;
-; 2012-09-30, Oliver Schmidt
-; 2019-09-08, Greg King
+; 2019-11-05, Greg King
 ;
 
-        .exportzp       ST := $90       ; IEC status byte
+        .export         ST: zp
+
+.segment        "EXTZP": zp
+
+; This is a temporary hack.
+
+; A zero-page copy of the IEC status byte.
+; This is needed because the Commander X16's Kernal's status
+; variable was moved out of the zero page.  But, the common
+; CBM file function modules import this as a zero-page variable.
+
+ST:     .res    1
diff --git a/libsrc/cx16/tgi_stat_stddrv.s b/libsrc/cx16/tgi_stat_stddrv.s
new file mode 100644
index 00000000..566a3639
--- /dev/null
+++ b/libsrc/cx16/tgi_stat_stddrv.s
@@ -0,0 +1,11 @@
+;
+; Address of the static standard TGI driver
+;
+; 2019-11-06, Greg King
+;
+; const void tgi_static_stddrv[];
+;
+
+        .import _cx16_640x4c_tgi
+
+        .export _tgi_static_stddrv := _cx16_640x4c_tgi
diff --git a/libsrc/cx16/tgi_stddrv.s b/libsrc/cx16/tgi_stddrv.s
new file mode 100644
index 00000000..0f77e734
--- /dev/null
+++ b/libsrc/cx16/tgi_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard TGI driver
+;
+; 2019-11-06, Greg King
+;
+; const char tgi_stddrv[];
+;
+
+        .export _tgi_stddrv
+
+.rodata
+
+_tgi_stddrv:    .asciiz "cx16-640x4c.tgi"
diff --git a/libsrc/cx16/videomode.s b/libsrc/cx16/videomode.s
index 4582ec1b..e3a777b8 100644
--- a/libsrc/cx16/videomode.s
+++ b/libsrc/cx16/videomode.s
@@ -1,30 +1,44 @@
 ;
-; 2009-09-07, Ullrich von Bassewitz
-; 2019-09-23, Greg King
+; 2019-11-06, Greg King
 ;
-; unsigned __fastcall__ videomode (unsigned Mode);
-; /* Set the video mode, return the old mode. */
+; /* Video mode defines */
+; #define VIDEOMODE_40x30         0x00
+; #define VIDEOMODE_80x60         0x02
+; #define VIDEOMODE_320x240       0x80
+; #define VIDEOMODE_SWAP          (-1)
+;
+; signed char __fastcall__ videomode (signed char Mode);
+; /* Set the video mode, return the old mode.
+; ** Return -1 if Mode isn't valid.
+; ** Call with one of the VIDEOMODE_xx constants.
+; */
 ;
 
         .export         _videomode
-        .import         SWAPPER
 
-        .include        "cx16.inc"
+        .import         SCRMOD
 
 
 .proc   _videomode
-        cmp     LLEN                    ; Do we have this mode already?
-        beq     @L9
-
-        lda     LLEN                    ; Get current mode ...
-        pha                             ; ... and save it
-
-        jsr     SWAPPER                 ; Toggle the mode
-
-        pla                             ; Get old mode into A
+        tax
+        clc                     ; (Get old mode)
+        jsr     SCRMOD
+        pha
+        txa
+
+        sec                     ; (Set new mode)
+        jsr     SCRMOD
+
+        pla                     ; Get back old mode
+        bcs     @L1
+        ldx     #>$0000         ; Clear high byte
+        rts
 
-; Done, old mode is in .A
+; The new mode is invalid.  Go back to the old mode.  Return -1.
 
-@L9:    ldx     #>$0000                 ; Clear high byte
+@L1:    sec
+        jsr     SCRMOD
+        lda     #<-1
+        tax
         rts
 .endproc
diff --git a/libsrc/cx16/waitvsync.s b/libsrc/cx16/waitvsync.s
index 3fb6354f..09d01c6a 100644
--- a/libsrc/cx16/waitvsync.s
+++ b/libsrc/cx16/waitvsync.s
@@ -3,7 +3,7 @@
 ;
 ; void waitvsync (void);
 ;
-; VERA's vertical sync. causes IRQs which increment the jiffy clock.
+; VERA's vertical sync causes IRQs which increment the jiffy clock.
 ;
 
         .export         _waitvsync
diff --git a/libsrc/cx16/wherex.s b/libsrc/cx16/wherex.s
new file mode 100644
index 00000000..56f42359
--- /dev/null
+++ b/libsrc/cx16/wherex.s
@@ -0,0 +1,15 @@
+;
+; 2019-11-06, Greg King
+;
+; unsigned char wherex (void);
+;
+
+        .export         _wherex
+
+        .include        "cx16.inc"
+
+.proc   _wherex
+        lda     CURS_X
+        ldx     #>$0000
+        rts
+.endproc
diff --git a/libsrc/cx16/wherey.s b/libsrc/cx16/wherey.s
new file mode 100644
index 00000000..396a2d14
--- /dev/null
+++ b/libsrc/cx16/wherey.s
@@ -0,0 +1,15 @@
+;
+; 2019-11-06, Greg King
+;
+; unsigned char wherey (void);
+;
+
+        .export         _wherey
+
+        .include        "cx16.inc"
+
+.proc   _wherey
+        lda     CURS_Y
+        ldx     #>$0000
+        rts
+.endproc
-- 
2.26.0