diff --git a/asminc/cbm_kernal.inc b/asminc/cbm_kernal.inc
index 5f41c6267..4d78cf93f 100644
--- a/asminc/cbm_kernal.inc
+++ b/asminc/cbm_kernal.inc
@@ -7,8 +7,13 @@
 
 .if .def(__CX16__)
   ; CX16 extended jump table
+  KBDBUF_PEEK                   := $FEBD
+  KBDBUF_GET_MODIFIERS          := $FEC0
+  KBDBUF_PUT                    := $FEC3
+  I2C_READ_BYTE                 := $FEC6
+  I2C_WRITE_BYTE                := $FEC9
+  CX_MONITOR                    := $FECC
   ENTROPY_GET                   := $FECF
-  KEYBRD_BUF_PUT                := $FED2
   CONSOLE_SET_PAGE_MSG          := $FED5
   CONSOLE_PUT_IMAGE             := $FED8
   CONSOLE_INIT                  := $FEDB
@@ -52,7 +57,7 @@
   CLOCK_GET_DATE_TIME           := $FF50
   JOYSTICK_SCAN                 := $FF53
   JOYSTICK_GET                  := $FF56
-  SCREEN_SET_MODE               := $FF5F
+  SCREEN_MODE                   := $FF5F
   SCREEN_SET_CHARSET            := $FF62
   MOUSE_CONFIG                  := $FF68
   MOUSE_GET                     := $FF6B
diff --git a/asminc/cx16.inc b/asminc/cx16.inc
index 4e5971593..268d701d6 100644
--- a/asminc/cx16.inc
+++ b/asminc/cx16.inc
@@ -1,5 +1,5 @@
 ;
-; CX16 r38 definitions
+; CX16 r39 definitions
 ;
 
 ; ---------------------------------------------------------------------------
@@ -104,6 +104,10 @@ PI
 ; ---------------------------------------------------------------------------
 ; Zero page
 
+; Banking registers
+RAM_BANK        := $00
+ROM_BANK        := $01
+
 ; GEOS and graphics pseudo-registers
 .struct gREG
                 .org    $02
@@ -224,7 +228,7 @@ PI
 ; Kernal
 KTEMP2          := $80          ; 2 bytes for temporary storage
 IMPARM          := $82          ; Pointer for PRIMM function
-FNAM            := $8C          ; Pointer to filename
+FNAM            := $8A          ; Pointer to filename
 
 ; BASIC
 TXTPTR          := $EE          ; Pointer into BASIC source code
@@ -234,14 +238,13 @@ TXTPTR          := $EE          ; Pointer into BASIC source code
 BASIC_BUF       := $0200        ; Location of command-line
 BASIC_BUF_LEN   = 81            ; Maximum length of command-line
 
-SCREEN_MODE     := $0261        ; Current screen mode (set by SCREEN_SET_MODE)
 SCREEN_PTR      := $0262        ; Pointer to current row on text screen (16 bits)
-STATUS          := $0286        ; Status from previous I/O operation
-IN_DEV          := $028A        ; Current input device number
-OUT_DEV         := $028B        ; Current output device number
-FNAM_LEN        := $028E        ; Length of filename
-SECADR          := $0290        ; Secondary address
-DEVNUM          := $0291        ; Device number
+STATUS          := $0289        ; Status from previous I/O operation
+IN_DEV          := $028D        ; Current input device number
+OUT_DEV         := $028E        ; Current output device number
+FNAM_LEN        := $0291        ; Length of filename
+SECADR          := $0293        ; Secondary address
+DEVNUM          := $0294        ; Device number
 CURS_COLOR      := $0373        ; Color under the cursor
 CHARCOLOR       := $0376        ; Cursor's color nybbles (high: background, low: foreground)
 RVS             := $0377        ; Reverse flag
@@ -268,6 +271,42 @@ NMIVec          := $0318
 ; ---------------------------------------------------------------------------
 ; I/O locations
 
+; 65C22 Versatile Interface Adapter
+.struct VIA1                    ; Versatile Interface Adapter
+        .org    $9F00
+  PRB   .byte                   ; mouse, LED, VIC bus  (Port Register B)
+  PRA   .byte                   ; keyboard, controllers  (Port Register A)
+  DDRB  .byte                   ; (Data Direction Register B)
+  DDRA  .byte                   ; (Data Direction Register A)
+  T1    .word                   ; (Timer 1)
+  T1L   .word                   ; (Timer 1 Latch)
+  T2    .word                   ; (Timer 2)
+  SR    .byte                   ; (Shift Register)
+  ACR   .byte                   ; (Auxiliary Control Register)
+  PCR   .byte                   ; (Peripheral Control Register)
+  IFR   .byte                   ; (Interrupt Flags Register)
+  IER   .byte                   ; (Interrupt Enable Register)
+  PRA2  .byte                   ; keyboard, controllers  (PRA without handshake)
+.endstruct
+
+; 65C22 Versatile Interface Adapter
+.struct VIA2
+        .org    $9F10
+  PRB   .byte
+  PRA   .byte
+  DDRB  .byte
+  DDRA  .byte
+  T1    .word
+  T1L   .word
+  T2    .word
+  SR    .byte
+  ACR   .byte
+  PCR   .byte
+  IFR   .byte
+  IER   .byte
+  PRA2  .byte
+.endstruct
+
 ; Video Enhanced Retro Adapter
 ; Has audio and SPI.
 .scope  VERA
@@ -496,44 +535,16 @@ NMIVec          := $0318
   .endstruct
 .endscope
 
-; 65C22
-.struct VIA1                    ; Versatile Interface Adapter
-        .org    $9F60
-  PRB   .byte                   ; ROM bank, IEC  (Port Register B)
-  PRA   .byte                   ; RAM bank  (Port Register A)
-  DDRB  .byte                   ; (Data Direction Register B)
-  DDRA  .byte                   ; (Data Direction Register A)
-  T1    .word                   ; (Timer 1)
-  T1L   .word                   ; (Timer 1 Latch)
-  T2    .word                   ; (Timer 2)
-  SR    .byte                   ; (Shift Register)
-  ACR   .byte                   ; (Auxiliary Control Register)
-  PCR   .byte                   ; (Peripheral Control Register)
-  IFR   .byte                   ; (Interrupt Flags Register)
-  IER   .byte                   ; (Interrupt Enable Register)
-  PRA2  .byte                   ; RAM bank  (Port Register A without handshaking)
+; YM2151 audio chip
+.struct YM2151
+                .org    $9F40
+  .union
+  STATUS        .byte
+  ADDR          .byte
+  .endunion
+  DATA          .byte
 .endstruct
 
-; 65C22
-.struct VIA2
-        .org    $9F70
-  PRB   .byte                   ; Mouse communication ?
-  PRA   .byte                   ; NES controller communication
-  DDRB  .byte
-  DDRA  .byte
-  T1    .word
-  T1L   .word
-  T2    .word
-  SR    .byte
-  ACR   .byte
-  PCR   .byte
-  IFR   .byte
-  IER   .byte
-  PRA2  .byte
-.endstruct
-
-; Real-Time Clock
-
 ; X16 Emulator device
 ; This device doesn't exist on the real machine.
 .struct EMULATOR
@@ -554,8 +565,7 @@ NMIVec          := $0318
 ; ---------------------------------------------------------------------------
 ; Banked RAM and ROM
 
-KEY_COUNT       := $A00A        ; (bank 0) Number of keys in input buffer
-TIMER           := $A037        ; (bank 0) 60 Hz. timer (3 bytes, big-endian)
+TIMER           := $A03B        ; (bank 0) 60 Hz. timer (3 bytes, big-endian)
 
 .struct BANK
         .org    $A000
diff --git a/cfg/cx16-asm.cfg b/cfg/cx16-asm.cfg
index 92c9d96f7..1b1cce8ec 100644
--- a/cfg/cx16-asm.cfg
+++ b/cfg/cx16-asm.cfg
@@ -1,5 +1,3 @@
-# Assembly configuration for R38
-
 FEATURES {
     STARTADDRESS: default = $0801;
 }
diff --git a/doc/cx16.sgml b/doc/cx16.sgml
index 9e743064f..78a51206b 100644
--- a/doc/cx16.sgml
+++ b/doc/cx16.sgml
@@ -200,15 +200,23 @@ access to hardware located in the address space. Some variables are
 structures, accessing the struct fields will access the chip registers.
 
 <descrip>
-  <tag><tt/VERA/</tag>
-  The <tt/VERA/ structure allows access
-  to the Video Enhanced Retro Adapter chip.
+
+  <tag><tt/RAM_BANK/</tag>
+  A register that controls which bank of high RAM is visible in the
+  <tt/BANK_RAM/ window.
+
+  <tag><tt/ROM_BANK/</tag>
+  A register that controls which bank of ROM is active at the moment.
 
   <tag><tt/VIA1, VIA2/</tag>
   Access to the two VIA (Versatile Interface Adapter) chips is available via
   the <tt/VIA1/ and <tt/VIA2/ variables. The structure behind those variables
   is explained in <tt/_6522.h/.
 
+  <tag><tt/VERA/</tag>
+  The <tt/VERA/ structure allows access
+  to the Video Enhanced Retro Adapter chip.
+
   <tag><tt/BANK_RAM/</tag>
   A character array that mirrors the eight-Kibibyte window, at &dollar;A000,
   into banked RAM.
@@ -219,7 +227,7 @@ structures, accessing the struct fields will access the chip registers.
 <sect>Loadable drivers<p>
 
 The names in the parentheses denote the symbols to be used for static linking
-of the drivers.  The names fit into the 8.3 character limit of the SD-Card's
+of the drivers.  The names fit into the old 8.3-character limit of the SD-Card's
 FAT32 file-system.
 
 
@@ -230,7 +238,7 @@ point to <tt/cx320p1.tgi (cx320p1_tgi)/.
 
 <descrip>
   <tag><tt/cx320p1.tgi (cx320p1_tgi)/</tag>
-  This driver features a resolution of 320 across and 200 down with 256 colors,
+  This driver features a resolution of 320 across and 240 down with 256 colors,
   and a slightly adjustable palette (the order of the colors can be changed in
   a way that's compatible with some of the other color drivers).
 </descrip><p>
@@ -248,10 +256,10 @@ point to <tt/cx16-std.joy (cx16_std_joy)/.
 
 <descrip>
   <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 <bf/A/, <bf/B/,
-  <bf/Select/, and <bf/Start/ buttons.  Buttons <bf/A/ and <bf/B/ are
-  the first and second fire buttons.
+  Supports the keyboard emulation of a controller and up to four SNES (and NES)
+  controllers connected to the joystick ports of the CX16.  It reads the four
+  directions, and the <bf/A/, <bf/B/, <bf/Select/, and <bf/Start/ buttons.
+  Buttons <bf/A/ and <bf/B/ are the first and second fire buttons.
 </descrip><p>
 
 
diff --git a/include/cx16.h b/include/cx16.h
index 4100da631..42495c862 100644
--- a/include/cx16.h
+++ b/include/cx16.h
@@ -3,7 +3,7 @@
 /*                                  cx16.h                                   */
 /*                                                                           */
 /*                      CX16 system-specific definitions                     */
-/*                             For prerelease 38                             */
+/*                             For prerelease 39                             */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided "as-is", without any expressed or implied       */
@@ -169,11 +169,16 @@ enum {
 };
 
 /* Video modes for videomode() */
-#define VIDEOMODE_40x30         0x00
-#define VIDEOMODE_80x60         0x02
-#define VIDEOMODE_40COL         VIDEOMODE_40x30
+#define VIDEOMODE_80x60         0x00
+#define VIDEOMODE_80x30         0x01
+#define VIDEOMODE_40x60         0x02
+#define VIDEOMODE_40x30         0x03
+#define VIDEOMODE_40x15         0x04
+#define VIDEOMODE_20x30         0x05
+#define VIDEOMODE_20x15         0x06
 #define VIDEOMODE_80COL         VIDEOMODE_80x60
-#define VIDEOMODE_320x200       0x80
+#define VIDEOMODE_40COL         VIDEOMODE_40x30
+#define VIDEOMODE_320x240       0x80
 #define VIDEOMODE_SWAP          (-1)
 
 /* VERA's address increment/decrement numbers */
@@ -221,6 +226,13 @@ enum {
 
 /* Define hardware. */
 
+#define RAM_BANK        (*(unsigned char *)0x00)
+#define ROM_BANK        (*(unsigned char *)0x01)
+
+#include <_6522.h>
+#define VIA1    (*(volatile struct __6522 *)0x9F00)
+#define VIA2    (*(volatile struct __6522 *)0x9F10)
+
 /* A structure with the Video Enhanced Retro Adapter's external registers */
 struct __vera {
     unsigned short      address;        /* Address for data ports */
@@ -271,12 +283,15 @@ struct __vera {
 };
 #define VERA    (*(volatile struct __vera *)0x9F20)
 
-#include <_6522.h>
-#define VIA1    (*(volatile struct __6522 *)0x9F60)
-#define VIA2    (*(volatile struct __6522 *)0x9F70)
-
-#define RAM_BANK        (VIA1.pra)
-#define ROM_BANK        (VIA1.prb)
+/* Audio chip */
+struct __ym2151 {
+    union {
+        unsigned char   reg;            /* Register number for data */
+        unsigned char   status;         /* Busy flag */
+    };
+    unsigned char       data;
+};
+#define YM2151  (*(volatile struct __ym2151 *)0x9F40)
 
 /* A structure with the x16emu's settings registers */
 struct __emul {
diff --git a/libsrc/cx16/cgetc.s b/libsrc/cx16/cgetc.s
index 2372b431a..b4354197f 100644
--- a/libsrc/cx16/cgetc.s
+++ b/libsrc/cx16/cgetc.s
@@ -1,5 +1,5 @@
 ;
-; 2019-12-22, Greg King
+; 2022-03-29, Greg King
 ;
 ; char cgetc (void);
 ; /* Return a character from the keyboard. */
@@ -13,6 +13,8 @@
         .macpack        generic
 
 
+screen_addr     :=      $1B000  ; VRAM address of text screen
+
 _cgetc: jsr     _kbhit
         bnz     L3              ; Jump if there are already chars waiting
 
@@ -57,8 +59,9 @@ setcursor:
 
         stz     VERA::CTRL      ; Use port 0
         lda     CURS_Y
+        add     #<(>screen_addr)
         sta     VERA::ADDR+1    ; Set row number
-        lda     #VERA::INC1     ; Increment address by one
+        lda     #VERA::INC1 | ^screen_addr      ; Increment address by one
         sta     VERA::ADDR+2
         lda     CURS_X          ; Get character column
         asl     a
diff --git a/libsrc/cx16/cpeekc.s b/libsrc/cx16/cpeekc.s
index 6756d995a..9f4b3b296 100644
--- a/libsrc/cx16/cpeekc.s
+++ b/libsrc/cx16/cpeekc.s
@@ -1,6 +1,6 @@
 ;
 ; 2016-02-28, Groepaz
-; 2020-04-29, Greg King
+; 2022-03-29, Greg King
 ;
 ; char cpeekc (void);
 ; /* Return the character from the current cursor position. */
@@ -9,13 +9,18 @@
         .export         _cpeekc
 
         .include        "cx16.inc"
+        .macpack        generic
 
 
+screen_addr     :=      $1B000  ; VRAM address of text screen
+
 _cpeekc:
         stz     VERA::CTRL      ; use port 0
         lda     CURS_Y
+        add     #<(>screen_addr)
         sta     VERA::ADDR+1    ; set row number
-        stz     VERA::ADDR+2
+        lda     #^screen_addr
+        sta     VERA::ADDR+2
         lda     CURS_X          ; get character column
         asl     a               ; each character has two bytes
         sta     VERA::ADDR
diff --git a/libsrc/cx16/cpeekcolor.s b/libsrc/cx16/cpeekcolor.s
index 9c167b07a..668f2a0da 100644
--- a/libsrc/cx16/cpeekcolor.s
+++ b/libsrc/cx16/cpeekcolor.s
@@ -1,5 +1,5 @@
 ;
-; 2020-04-30, Greg King
+; 2022-03-29, Greg King
 ;
 ; unsigned char cpeekcolor (void);
 ; /* Return the colors from the current cursor position. */
@@ -8,8 +8,11 @@
         .export         _cpeekcolor
 
         .include        "cx16.inc"
+        .macpack        generic
 
 
+screen_addr     :=      $1B000  ; VRAM address of text screen
+
 _cpeekcolor:
         php
         lda     CURS_FLAG       ; is the cursor currently off?
@@ -22,8 +25,10 @@ _cpeekcolor:
 
 @L1:    stz     VERA::CTRL      ; use port 0
         lda     CURS_Y
+        add     #<(>screen_addr)
         sta     VERA::ADDR+1    ; set row number
-        stz     VERA::ADDR+2
+        lda     #^screen_addr
+        sta     VERA::ADDR+2
         lda     CURS_X          ; get character column
         sec                     ; color attribute is second byte
         rol     a
diff --git a/libsrc/cx16/cpeekrevers.s b/libsrc/cx16/cpeekrevers.s
index fd7428779..1d10a2654 100644
--- a/libsrc/cx16/cpeekrevers.s
+++ b/libsrc/cx16/cpeekrevers.s
@@ -1,6 +1,6 @@
 ;
 ; 2016-02-28, Groepaz
-; 2020-04-30, Greg King
+; 2022-03-29, Greg King
 ;
 ; unsigned char cpeekrevers (void);
 ; /* Return the reverse attribute from the current cursor position.
@@ -11,8 +11,11 @@
         .export         _cpeekrevers
 
         .include        "cx16.inc"
+        .macpack        generic
 
 
+screen_addr     :=      $1B000  ; VRAM address of text screen
+
 _cpeekrevers:
         php
         lda     CURS_FLAG       ; is the cursor currently off?
@@ -25,8 +28,10 @@ _cpeekrevers:
 
 @L1:    stz     VERA::CTRL      ; use port 0
         lda     CURS_Y
+        add     #<(>screen_addr)
         sta     VERA::ADDR+1    ; set row number
-        stz     VERA::ADDR+2
+        lda     #^screen_addr
+        sta     VERA::ADDR+2
         lda     CURS_X          ; get character column
         asl     a               ; each character has two bytes
         sta     VERA::ADDR
diff --git a/libsrc/cx16/cputc.s b/libsrc/cx16/cputc.s
index 4a7034e59..22327d25a 100644
--- a/libsrc/cx16/cputc.s
+++ b/libsrc/cx16/cputc.s
@@ -11,8 +11,11 @@
         .import         gotoxy, PLOT
 
         .include        "cx16.inc"
+        .macpack        generic
 
 
+screen_addr     :=      $1B000  ; VRAM address of text screen
+
 ; Move to a cursor position, then print a character.
 
 _cputcxy:
@@ -79,16 +82,17 @@ putchar:
         tax
         stz     VERA::CTRL      ; Use port 0
         lda     CURS_Y
+        add     #<(>screen_addr)
         sta     VERA::ADDR+1    ; Set row number
-        lda     #VERA::INC1     ; Address increments by one
+        lda     #VERA::INC1 | ^screen_addr      ; Address increments by one
         sta     VERA::ADDR+2
         ldy     CURS_X          ; Get character column into .Y
         tya
         asl     a               ; Each character has two bytes
         sta     VERA::ADDR
-        stx     VERA::DATA0
+        stx     VERA::DATA0     ; Put the character
         lda     CHARCOLOR
-        sta     VERA::DATA0
+        sta     VERA::DATA0     ; Put its colors
         rts
 
 
diff --git a/libsrc/cx16/crt0.s b/libsrc/cx16/crt0.s
index be83927fc..e37a64a7c 100644
--- a/libsrc/cx16/crt0.s
+++ b/libsrc/cx16/crt0.s
@@ -1,5 +1,5 @@
 ;
-; Start-up code for cc65 (CX16 r35 version)
+; Start-up code for cc65 (CX16 r39 version)
 ;
 
         .export         _exit
@@ -20,7 +20,7 @@
 .segment        "STARTUP"
 
 Start:  tsx
-        stx     spsave          ; Save the system stack ptr
+        stx     spsave          ; Save the system stack ptr.
 
 ; Save space by putting some of the start-up code in the ONCE segment
 ; which will be re-used by the BSS segment, the heap, and the C stack.
@@ -46,26 +46,14 @@ _exit:
 
         jsr     donelib
 
-.if 0   ; (We don't need to preserve zero-page space for cc65's variables.)
-; Copy back the zero-page stuff.
-
-        ldx     #zpspace-1
-L2:     lda     zpsave,x
-        sta     sp,x
-        dex
-        bpl     L2
-.endif
-
 ; Restore the system stuff.
 
         ldx     spsave
         txs                     ; Restore stack pointer
         ldx     ramsave
-        stx     VIA1::PRA       ; Restore former RAM bank
-        lda     VIA1::PRB
-        and     #<~$07
-        ora     #$04
-        sta     VIA1::PRB       ; Change back to BASIC ROM
+        stx     RAM_BANK        ; Restore former RAM bank
+        lda     #$04
+        sta     ROM_BANK        ; Change back to BASIC ROM
 
 ; Back to BASIC.
 
@@ -79,26 +67,14 @@ L2:     lda     zpsave,x
 init:
 ; Change from BASIC's ROM to Kernal's ROM.
 
-        lda     VIA1::PRB
-        and     #<~$07
-        sta     VIA1::PRB
+        stz     ROM_BANK
 
 ; Change to the second RAM bank.
 
-        lda     VIA1::PRA
+        lda     RAM_BANK
         sta     ramsave         ; Save the current RAM bank number
         lda     #$01
-        sta     VIA1::PRA
-
-.if 0   ; (We don't need to preserve zero-page space for cc65's variables.)
-; Save the zero-page locations that we need.
-
-        ldx     #zpspace-1
-L1:     lda     sp,x
-        sta     zpsave,x
-        dex
-        bpl     L1
-.endif
+        sta     RAM_BANK
 
 ; Set up the stack.
 
@@ -125,6 +101,3 @@ L1:     lda     sp,x
 ramsave:
         .res    1
 spsave: .res    1
-.if 0
-zpsave: .res    zpspace
-.endif
diff --git a/libsrc/cx16/joy/cx16-std.s b/libsrc/cx16/joy/cx16-std.s
index 5c10c0592..a40fcb061 100644
--- a/libsrc/cx16/joy/cx16-std.s
+++ b/libsrc/cx16/joy/cx16-std.s
@@ -2,7 +2,7 @@
 ; Standard joystick driver for the CX16.
 ; May be installed multiple times when statically linked to an application.
 ;
-; 2019-12-24, Greg King
+; 2021-04-07, Greg King
 ;
 
         .include        "joy-kernel.inc"
@@ -41,7 +41,7 @@
 ; ------------------------------------------------------------------------
 ; Constant
 
-JOY_COUNT       = 2             ; Number of joysticks we support
+JOY_COUNT       = $05           ; Number of joysticks we support
 
 ; ------------------------------------------------------------------------
 ; Data.
@@ -51,8 +51,7 @@ JOY_COUNT       = 2             ; Number of joysticks we support
 
 ; ------------------------------------------------------------------------
 ; 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.
+; If possible, check if the hardware is present.
 ; Must return a JOY_ERR_xx code in .XA .
 
 INSTALL:
@@ -77,8 +76,10 @@ COUNT:  lda     #<JOY_COUNT
 ; ------------------------------------------------------------------------
 ; READ: Read a particular joystick passed in .A .
 
-READ:   and     #%00000001
-        jsr     JOYSTICK_GET
+READ:   cmp     #JOY_COUNT
+        blt     :+
+        lda     #$00
+:       jsr     JOYSTICK_GET
         sta     tmp1
         txa
         bit     #%00001110      ; Is it NES or SNES controller?
diff --git a/libsrc/cx16/kbhit.s b/libsrc/cx16/kbhit.s
index d7e22efd1..3cfe351a9 100644
--- a/libsrc/cx16/kbhit.s
+++ b/libsrc/cx16/kbhit.s
@@ -1,5 +1,5 @@
 ;
-; 2020-01-08, Greg King
+; 2022-03-28, Greg King
 ;
 ; unsigned char kbhit (void);
 ; /* Returns non-zero (true) if a typed character is waiting. */
@@ -7,14 +7,11 @@
 
         .export         _kbhit
 
-        .include        "cx16.inc"
+        .import         KBDBUF_PEEK
 
 
 .proc   _kbhit
-        ldy     VIA1::PRA       ; (KEY_COUNT is in RAM bank 0)
-        stz     VIA1::PRA
-        lda     KEY_COUNT       ; Get number of characters
-        sty     VIA1::PRA
-        tax                     ; High byte of return (only its zero/nonzero ...
+        jsr     KBDBUF_PEEK
+        txa                     ; Low byte of return (only its zero/nonzero ...
         rts                     ; ... state matters)
 .endproc
diff --git a/libsrc/cx16/kernal.s b/libsrc/cx16/kernal.s
index a252569e5..40bcfed11 100644
--- a/libsrc/cx16/kernal.s
+++ b/libsrc/cx16/kernal.s
@@ -1,13 +1,18 @@
 ;
-; 2020-04-27, Greg King
+; 2022-03-28, Greg King
 ;
 ; CX16 Kernal functions
 ;
 
         .include        "cbm_kernal.inc"
 
+        .export KBDBUF_PEEK
+        .export KBDBUF_GET_MODIFIERS
+        .export KBDBUF_PUT
+        .export I2C_READ_BYTE
+        .export I2C_WRITE_BYTE
+        .export CX_MONITOR
         .export ENTROPY_GET
-        .export KEYBRD_BUF_PUT
         .export CONSOLE_SET_PAGE_MSG
         .export CONSOLE_PUT_IMAGE
         .export CONSOLE_INIT
@@ -50,7 +55,7 @@
         .export CLOCK_GET_DATE_TIME
         .export JOYSTICK_SCAN
         .export JOYSTICK_GET
-        .export SCREEN_SET_MODE
+        .export SCREEN_MODE
         .export SCREEN_SET_CHARSET
         .export MOUSE_CONFIG
         .export MOUSE_GET
diff --git a/libsrc/cx16/mou/cx16-std.s b/libsrc/cx16/mou/cx16-std.s
index 0d046bbc2..3af7d2eb3 100644
--- a/libsrc/cx16/mou/cx16-std.s
+++ b/libsrc/cx16/mou/cx16-std.s
@@ -1,7 +1,7 @@
 ;
 ; Driver for the Commander X16 Kernal's mouse driver.
 ;
-; 2019-12-25, Greg King
+; 2022-03-28, Greg King
 ;
 
         .include        "zeropage.inc"
@@ -118,7 +118,8 @@ INSTALL:
         dex
         bpl     @L1
 
-        ldx     #$00            ; Don't change sprite's scale
+        sec                     ; Get screen geometry
+        jsr     SCREEN_MODE
         lda     #$01            ; Create sprite
         jsr     MOUSE_CONFIG
 
diff --git a/libsrc/cx16/tgi/cx320p1.s b/libsrc/cx16/tgi/cx320p1.s
index 1ad5c2cbd..2fcd9adf3 100644
--- a/libsrc/cx16/tgi/cx320p1.s
+++ b/libsrc/cx16/tgi/cx320p1.s
@@ -1,8 +1,8 @@
 ;
-; Graphics driver for the 320 pixels across, 200 pixels down, 256 colors mode
+; Graphics driver for the 320 pixels across, 240 pixels down, 256 colors mode
 ; on the Commander X16
 ;
-; 2020-07-02, Greg King <gregdk@users.sf.net>
+; 2022-03-30, Greg King <gregdk@users.sf.net>
 ;
 
         .include        "zeropage.inc"
@@ -39,7 +39,7 @@
         .byte   TGI_API_VERSION         ; TGI API version number
         .addr   $0000                   ; Library reference
         .word   320                     ; X resolution
-        .word   200                     ; Y resolution
+        .word   240                     ; Y resolution
         .byte   <$0100                  ; Number of drawing colors
         .byte   1                       ; Number of screens available
         .byte   8                       ; System font X size
@@ -100,7 +100,7 @@ palette:        .res    $0100
 
 bcolor          :=      palette + 0     ; Background color
 color:          .res    1               ; Stroke and fill index
-mode:           .res    1               ; Old text mode
+text_mode:      .res    1               ; Old text mode
 
 .data
 
@@ -152,13 +152,15 @@ INIT:   stz     error           ; #TGI_ERR_OK
 
 ; Save the current text mode.
 
-        lda     SCREEN_MODE
-        sta     mode
+        sec
+        jsr     SCREEN_MODE
+        sta     text_mode
 
-; Switch into (320 x 200 x 256) graphics mode.
+; Switch into (320 x 240 x 256) graphics mode.
 
         lda     #GRAPH320
-        jmp     SCREEN_SET_MODE
+        clc
+        jmp     SCREEN_MODE
 
 ; ------------------------------------------------------------------------
 ; DONE: Will be called to switch the graphics device back into text mode.
@@ -168,16 +170,9 @@ INIT:   stz     error           ; #TGI_ERR_OK
 ; Must set an error code: NO
 
 DONE:
-; Work around a prerelease 37 Kernal bug.
-; VERA (graphics) layer 0 isn't disabled by SCREEN_SET_MODE.
-
-        stz     VERA::CTRL
-        lda     VERA::DISP::VIDEO
-        and     #<~VERA::DISP::ENABLE::LAYER0
-        sta     VERA::DISP::VIDEO
-
-        lda     mode
-        jmp     SCREEN_SET_MODE
+        lda     text_mode
+        clc
+        jmp     SCREEN_MODE
 
 ; ------------------------------------------------------------------------
 ; GETERROR: Return the error code in .A, and clear it.
diff --git a/libsrc/cx16/videomode.s b/libsrc/cx16/videomode.s
index 8fe797449..998316858 100644
--- a/libsrc/cx16/videomode.s
+++ b/libsrc/cx16/videomode.s
@@ -1,10 +1,15 @@
 ;
-; 2020-01-06, Greg King
+; 2022-03-28, Greg King
 ;
 ; /* Video mode defines */
-; #define VIDEOMODE_40x30         0x00
-; #define VIDEOMODE_80x60         0x02
-; #define VIDEOMODE_320x200       0x80
+; #define VIDEOMODE_80x60         0x00
+; #define VIDEOMODE_80x30         0x01
+; #define VIDEOMODE_40x60         0x02
+; #define VIDEOMODE_40x30         0x03
+; #define VIDEOMODE_40x15         0x04
+; #define VIDEOMODE_20x30         0x05
+; #define VIDEOMODE_20x15         0x06
+; #define VIDEOMODE_320x240       0x80
 ; #define VIDEOMODE_SWAP          (-1)
 ;
 ; signed char __fastcall__ videomode (signed char Mode);
@@ -16,25 +21,26 @@
 
         .export         _videomode
 
-        .import         SCREEN_SET_MODE
-        .include        "cx16.inc"
+        .import         SCREEN_MODE
 
 
 .proc   _videomode
-        ldx     SCREEN_MODE     ; Get old mode
-        phx
-
-        jsr     SCREEN_SET_MODE
+        sec                     ; Get old mode
+        pha
+        jsr     SCREEN_MODE
+        plx
+        pha                     ; Save old mode
+        txa
+        clc                     ; Set new mode
+        jsr     SCREEN_MODE
 
         pla                     ; Get back old mode
         ldx     #>$0000         ; Clear high byte
-        bcs     @L1
-        rts
+        bcc     @L1
 
-; The new mode is invalid.  Go back to the old one.  Return -1.
+; The new mode is invalid.  Return -1.
 
-@L1:    sta     SCREEN_MODE
         dex
         txa
-        rts
+@L1:    rts
 .endproc
diff --git a/libsrc/cx16/waitvsync.s b/libsrc/cx16/waitvsync.s
index 6316a0483..dc0509223 100644
--- a/libsrc/cx16/waitvsync.s
+++ b/libsrc/cx16/waitvsync.s
@@ -1,5 +1,5 @@
 ;
-; 2020-01-08, Greg King
+; 2021-04-01, Greg King
 ;
 ; void waitvsync (void);
 ; /* Wait for the start of the next video field. */
@@ -12,10 +12,10 @@
         .include        "cx16.inc"
 
 _waitvsync:
-        ldx     VIA1::PRA       ; (TIMER is in RAM bank 0)
-        stz     VIA1::PRA
+        ldx     RAM_BANK        ; (TIMER is in RAM bank 0)
+        stz     RAM_BANK
         lda     TIMER + 2
 :       cmp     TIMER + 2
         beq     :-              ; Wait for next jiffy
-        stx     VIA1::PRA
+        stx     RAM_BANK
         rts