FAST-40Copyright © 2025 8-Bit Guru
FAST-40 is a utility program for the Commodore VIC-20 which reconfigures the stock 22x23 text screen to display a denser 40x24 mode. It is written entirely in 6502 assembly language, ships as an 8K cartridge (and loadable program) and requires a 3K RAM expansion for runtime workspace plus at least an 8K RAM expansion for user programs.
No video hardware modification is required.
Earlier 40-column programs typically suffered from some combination of sluggish performance, visual glitching, or screen-editor functionality issues. FAST-40 was designed to render an artifact-free 40x24 text mode whilst faithfully reproducing standard screen-editor functionality, with performance intended to be comparable to (or better than) the native 22x23 display.
Raw text output performance averages at 49% faster per character than the vanilla hardware-assisted ROM routines, and spikes to higher rates under long-line workloads.
FAST-40 works equally well on real VIC-20 hardware or under emulation - it can be attached as an auto-start cartridge in VICE, LOADed as a program (when BLK5 is configured as RAM) or burned/flashed/uploaded into a suitable EPROM or 'soft' cartridge such as the Final Expansion 3.
Both PAL and NTSC video standards are supported.
The JiffyDOS v6.01 Kernal ROM is supported if detected.
NOTE: FAST-40 expects to run on a real or emulated VIC-20 with an NMOS 6502 and makes use of several undocumented opcodes. It will not operate correctly on later 6502 variants (e.g. the CMOS 65C02) which disable or repurpose these opcodes.
The FAST-40 project is hosted on GitHub.
Creation of modified or derivative works using, in whole or in part, any sourcecode, assets, or binary artifact originating from this project is subject to the following:
-
Free for non-commercial use (you must clearly include a credit link to this project within your project).
-
Commercial use is expressly forbidden except by explicit consent from the copyright holder.
If you're familar with VICE and just want to dive straight in...
-
clone the repository, which includes an artifacts folder containing:
- FAST-40 built as an autostart cartridge (fast40.bin)
- FAST-40 built as a LOADable program (fast40.prg)
- a disk image (fast40.d64) containing the program build, a simple performance-comparison program written in BASIC, and a copy of the BASIC adventure game CITADEL adjusted for a 40-column display.
-
invoke xvic with xvic.exe -memory all -cartA fast40.bin
This will start the emulator with the FAST-40 cartridge installed and 24K for BASIC to play with.
-
Editor
My personal choice is Visual Studio Code, but any editor you're comfortable with will suffice. I also use a 3rd-party VSCode extension called Kick Assembler 8-Bit Retro Studio 0.23.3 which provides a bunch of useful functionality including syntax highlighting and automated invocation of KickAssembler and VICE without needing to switch out to a command prompt. -
Assembler
The sourcecode syntax targets KickAssembler 5.25. No other build tool is required.
Note that KickAssembler is written in Java and requires a Java runtime to operate. My preference is AdoptJDK. -
Emulator
The code builds a binary cartridge image which can be used with xvic, the VIC-20 emulator shipped with VICE.
To generate the autostart cartridge ROM artifact (fast40.bin):
java -jar [Your_KickAssembler_Path]\KickAss.jar main.asm -o fast40.bin -binfile
To generate the LOADable program artifact (fast40.prg):
java -jar [Your_KickAssembler_Path]\KickAss.jar main.asm -o fast40.prg
To start xvic with the cartridge ROM from the commandline:
[Your_VICE_Path]\bin\xvic.exe -memory all -cartA fast40.bin
To use the LOADable program within xvic, enable all RAM blocks, attach the fast40.d64 disk image, and type:
LOAD"FAST40",8,1
SYS64802
Consult the VICE documentation for full details regarding commandline options associated with attachment and autostarting of disk images and programs.
FAST-40 supports all VIC-20 character glyphs and control characters, including those for cursor positioning, colour selection, reverse-mode, etc. The VIC-20 keyboard does not emit visible characters for the SHIFT/C= key combination (which performs the toggle between upper-case and lower-case character sets) but these non-printing characters do exist and are supported.
FAST-40 character output performance is universally better than the stock VIC-20 - it generates characters in 40x24 mode an avergae of 49% faster than the native 22x23 mode.
The stock VIC-20 applies the SHIFT/C= characterset switch to the whole screen, meaning it is not possible to display glyphs from both upper-case and lower-case charactersets at the same time. FAST-40 does not have this limitation - characters from both sets can be displayed simultaneously.
FAST-40 adds an optional 'write-protect' mechanism which will prevent overwriting of a BASIC program if SHIFT/RUNSTOP is accidentally triggered; in tape-based systems the user has ample time to cancel the action before any new program is found and loaded, but disk-based systems are likely to action the LOAD much more quickly.
It is possible to write directly to the text screen without going through the CHAROUT vector (i.e. PRINT) in the style of the conventional memory-mapped screen. However, since FAST-40 uses a dynamically-updated lookup table to determine which line of the text buffer corresponds to each physical screen line, the text matrix is simply referenced by X/Y coordinates starting at 0,0 (top-left).
The format of the SYS command to 'POKE' to the character matrix is:
SYS 41006,COLUMN,ROW,CHARACTER,COLOUR
To set the first (top-left) character to the 'A' character in black:
SYS 41006,0,0,1,0
To set the last (bottom-right) character to the 'Z' character in red:
SYS 41006,39,23,26,2
Since the 40-column screen is mapped over a 160x192 bitmap, FAST-40 allows pixel plotting to that bitmap alongside the core text-presentation functionality.
The format of the SYS command to 'PLOT' to the hi-res bitmap is:
SYS 41003,COLUMN,ROW,COLOUR
To set the first (top-left) pixel to a black dot:
SYS 41003,0,0,0
To set the last (bottom-right) pixel to a red dot:
SYS 41003,159,191,2
To clear a pixel without changing the colour of the surrounding pixels:
SYS 41003,159,191,255
On a stock VIC-20 the SHIFT/RUNSTOP key combination causes the commands LOAD and RUN to be injected into the keyboard buffer to initiate an automatic start of the next program found on tape. Modern users prefer to use disk (or pseudo-disk devices such as SD cards) for storage instead of tape, and will often make use of the JiffyDOS Kernal ROM which disables tape operations in order to provide extended disk functionality.
FAST-40 detects the presence of JiffyDOS and alters the SHIFT/RUNSTOP commands to favour disk users as follows:
- If JiffyDOS is not present, the sequence
LOAD"$",8is executed to read the directory of the disk - If JiffyDOS is present (featuring the preferred
@$command to view the directory) the sequenceLOAD"*",8is executed to load the first program on the disk
A write-protect function is available which checks BASIC memory and triggers a ?LOAD ERROR if a program is already present. This check is disabled by default to preserve stock functionality and prevent interference with chain-loading of multi-part programs. When enabled, an explicit LOAD or NEW must be executed to overide the check.
To enable or disable the write-protect check, issue this command either directly or in your programs:
SYS 41000,X [ X=non-zero to enable, X=zero or omitted to disable]
FAST-40 makes changes to numerous memory areas, VIC registers, and system vectors in order to configure and manage the 40x24 display mode.
Memory areas:
$0003-$0004 Used if BRK debugging is enabled at build time
$00D9-$00F1 Working storage (Zero Page)
$0B92-$0FFF Text buffers (3K expansion RAM area)
$1000-$1FFF Hi-res screen matrix (4K onboard RAM area)
$9400-$95FF Lo-res colour matrix
VIC registers:
$9000 Screen x-position
$9001 Screen y-position
$9002 Screen memory address and columns
$9003 Screen rows and character height
$9005 Screen memory address and character generator address
System vectors:
$028F/$0290 SHIFT/CTRL/C= key decode
$0308/$0309 BASIC decode
$0314/$0315 IRQ interrupt
$0316/$0317 BRK interrupt
$0324/$0325 Character input
$0326/$0327 Character output
These vectors may be modified by other programs wishing to provide additional functionality alongside FAST-40. Such programs should preserve the vector chain by first capturing the target address of whichever vector(s) they need before replacing them with their own, and finalise their processing by passing control to those captured addresses.
The VIC-20 has no memory protection hardware and therefore FAST-40 cannot 'lock' the various memory areas, vectors, and VIC registers it uses. The following cautions apply for other programs wishing to operate in the 40x24 mode:
-
Programs should not read/write video or colour memory directly, but instead use the PRINT statement (in BASIC) or call the CHROUT vector at $FFD2 (in machine-code). Both are designed to route their output through the character input/output vectors which point to the custom display logic within FAST-40, and thereby allow it to manage screen output.
-
Common programming techniques such as switching character-case by altering the value at address 36869 ($9005), adjusting cursor blink phase, frequency, or position by altering the relevant zero-page values at $CC/$CD/$CF/$D3/$D6, or otherwise directly interacting with screen editor functionality via zero-page or other addresses is discouraged. Such interactions are unlikely to yield the expected result and will probably disrupt FAST-40 operation.
-
Limitations in the VIC design mean there is no way to preserve the usual 1:1 relationship between individual text-mode characters and their respective colour attributes when in 40x24 mode. All text colours are supported but they operate on 2x2 blocks of characters; in other words, the colour resolution is half that of the text resolution and colour layout should therefore be planned accordingly to avoid attribute clash.
-
FAST-40 needs just over 1K of the 3K expansion RAM area in BLK0, and reserves addresses $0B92-$0FFF for various text buffers. Consequently 1938 bytes from $0400-$0B91 is available for user programms, though this area is not directly available to BASIC.
In the event that a program inadvertantly 'breaks' FAST-40 by overwriting something it depends upon to generate the 40x24 mode, recovery can be achieved in the following ways:
-
Writes to the text buffer, display bitmap, colour memory, and screen-editor management areas will be repaired whenever the screen is cleared with SHIFT/CLRHOME or PRINT CHR$(147).
-
Writes to the VIC registers, system vectors, and/or most other runtime memory structures can almost always be repaired via a RUNSTOP/RESTORE 'soft' reset.
-
Any catastrophic breakage that exceeds the capacity of FAST-40 to repair itself will require a system reset to resolve. This can be achieved by power-cycling the machine, or hitting a hardware reset button if available.
These two VIC-20 afficionados at Denial - tokra and mathom - actively participated in the beta-test phase. Their time and effort spent testing, sending bug reports, and assisting with crash diagnosis is greatly appreciated.
- Initial testing release.
- Fixed a bug where entering long BASIC lines would sometimes lose the character in column 40, causing syntax errors (reported by tokra@denial)
- Fixed a bug where data fed to the INPUT command included the prompt in the returned value and therefore broke it (reported by mathom@denial)
- Fixed a bug where inserting a character into a long line would sometimes erroneously insert a blank line after it
- Fixed a bug where doing a character insert in column 40 erroneously placed the inserted space character into column 39
- Fixed a bug in the screen-scrolling logic where it forgot that the text buffer layout is not linear
- Fixed a bug where RUNSTOP/RESTORE didn't reset the default text colour and character-case
- Added a BRK handler to display CPU registers (to help debug a JiffyDOS showstopper crash reported by mathom@denial)
- Added an alternate build option to do LOAD"$",8 / LIST on SHIFT/RUNSTOP
- Tweaked the PAL/NTSC startup test to save the result and thereby avoid repeated re-tests on RUNSTOP/RESTORE
- Tweaked the cursor blink phase timings to help cursor visibility during rapid/repeated movement (reported by mathom@denial)
- Fixed a bug introduced in Beta 2 which corrupted the Stack and broke the INS/DEL routines (reported by tokra@denial)
- Fixed a bug where deleting a character from column 1 replaced the character in column 39 on the previous line instead of column 40
- Fixed a bug where deleting a character from column 1 of an unlinked line produced an unwanted side-effect on the previous line
- Fixed a bug where the screen-scroll CTRL-delay code intermittently failed to execute properly (reported by tokra@denial)
- Fixed a bug where the startup RAM detection wasn't triggering a clean system reset if BLK1 is empty
- Fixed the JiffyDOS showstopper crash (JiffyDOS rearranges some code in the SHIFT/CTRL/C= ROM keypress logic)
- Added the JiffyDOS banner to the startup message (if JiffyDOS is detected)
- Fixed a bug where line continuation markers were not correctly reset after a screen-scroll event
- Fixed a bug in the SHIFT/C= keypress handler to prevent keybounce
- Tweaked SHIFT/RUNSTOP keypress behaviour to better suit JiffyDOS users
- Tweaked startup colours back to stock blue-on-white for NTSC visual clarity (prompted by gunner@denial)
- Restructured memory usage so FAST-40 only needs 3K in BLK0 and leaves all 8K blocks free for BASIC
- Refactored bitmap rendering path logic (FAST-40 now draws 40x24 mode faster than the stock ROM draws 22x23)
- Refactored logic in INS/DEL keypress, bitmap line-refresh, and logical line extension routines
- Removed case-switch bitmap refresh which caused a race condition crash (reported by boray@denial)
- Added \artifacts folder to the repository, containing
- fast40.bin - pre-built cartridge version
- fast40.prg - pre-built LOADable version (prompted by boray@denial)
- fast40.d64 - disk image containing fast40.prg plus a simple performance-comparison program written in BASIC and a copy of the BASIC adventure game CITADEL adjusted for a 40-column display
- Fixed a bug where the BRK handler wasn't being set properly (reported by mike@denial)
- Refactored the startup logic so the RUNSTOP/RESTORE handler can do better breakage recovery
- Add a SHIFT-key modifier to the scroll CTRL-delay logic to toggle a scroll-lock until released
- Added a write-protect check so SHIFT/RUNSTOP actions trigger ?LOAD ERROR if there is a BASIC program in memory
- Fixed a bug where SHIFT/C= sometimes forgot to undraw the cursor
- Fixed a bug where SHIFT/C= generated a visible character in quote-mode
- Fixed a bug where SHIFT/RUNSTOP injected a rogue character when JiffyDOS is present
- Flipped the SHIFT/RUNSTOP write-protect check to DISABLED by default
- Refactored the bitmap address lookup tables to reduce their ROM footprint by 80%
- Refactored the glyph rendering pipeline to increase average throughput by 5-10%
- Refactored the control-code dispatch logic and tables to improve throughput by 10%
- Removed the RESET command which slowed BASIC execution excessively
- Removed the self-modifying glyph merge routine (now exists as unrolled ROM logic)
- Added hi-res pixel 'PLOT'
- Added character matrix 'POKE'
- Added a fast multi-parameter SYS interface for the new BASIC-accessible features:
- SYS 41000 Write-protect enable/disable
- SYS 41003 Plot/unplot hi-res screen pixel
- SYS 41006 Direct-to-screen character write
8-Bit Guru (also: Eight-Bit Guru, 8BitGuru, 8BG) is the nom de guerre of Mark Johnson. I'm a professional coder from the UK who has been telling computers what to do since 1981. My day job is all about C# and Azure, whilst my hobby projects mostly involve writing 6502 assembly language for the VIC-20 (my first computer, back in '81).