Sweet 16 (The 6502 Dream Machine) Ported to the VIC-20

Sweet 16 was created by Steve Wozniak to reduce code size and make it easier to handle 16-bit pointers and arithmetic for his Apple Integer BASIC. He wrote it around 1977 and referred to it in an article as The 6502 Dream Machine. I have ported this to the Commodore VIC-20 so that we can play with it on the Vic.

Outline of Sweet 16

Sweet 16 is described as a pseudo-machine interpreter, which is probably a better description than a virtual machine because it shares native memory for storage and is designed to switch back and forth between itself and native 6502 code. The pseudo-machine has sixteen 16-bit registers with five of them having a defined function.

  • R0  Accumulator
  • R12 Subroutine return stack pointer
  • R13 Comparison instruction results
  • R14 Status register
  • R15 Program counter

To execute Sweet 16 code you JSR to an address within it which will save the registers and status then execute the following bytes in memory as Sweet 16 code until it reaches the Sweet 16 RTN instruction which will restore the registers and status and continue executing the native 6502 that follows it.

The code is pretty compact and only takes around 300 bytes, it could have been made a little more compact and faster but it had to reside in ROM and therefore couldn't use self-modifying code.

Instruction Set

Register Operations Nonregister Operations
00RTNReturn to 6502 mode
1nSET RnConstant set 01BR eaBranch always
2nLD RnLoad 02BNC eaBranch if No Carry
3nST RnStore 03BC eaBranch if Carry
4nLD @RnLoad indirect 04BP eaBranch if Plus
5nST @RnStore indirect 05BM eaBranch if Minus
6nLDD @RnLoad double indirect 06BZ eaBranch if Zero
7nSTD @RnStore double indirect 07BNZ eaBranch if NonZero
8nPOP @RnPop indirect 08BM1 eaBranch if Minus 1
9nSTP @RnStore Pop indirect 09BNM1 eaBranch if Not Minus 1
AnADD RnAdd 0ABKBreak
BnSUB RnSubtract 0BRSReturn from Subroutine
CnPOPD @RnPop double indirect 0CBS eaBranch to Subroutine
DnCPR RnCompare 0DUnassigned
EnINR RnIncrement 0EUnassigned
FnDCR RnDecrement 0FUnassigned

There is an implicit Accumulator argument for most of the Register Operations and the Branch instructions all use relative addressing. The instruction set is well thought out with the ability to use 8-bit bytes or 16-bit words and helpfully instructions like the indirect instructions increment/decrement the register being used before/after use as appropriate. For a full description of the instructions take a look at the Byte Magazine Volume 02 Number 11 - November 1977 article.

Porting Sweet 16 to the Commodore VIC-20

The original Sweet 16 source code has been published a number of times including in Byte Magazine Volume 02 Number 11 - November 1977. In this article Steve Wozniak encourages users to modify Sweet 16 and even to port it to other processors, so hopefully he won't mind its being ported to the Vic. However, despite this and the fact that the code is widely available, it is still probably under copyright and therefore the port relies on patching the original source code rather than supplying a complete version.

I can't claim too much credit for porting it as beyond deciding on a suitable location for the registers in the zero page and aligning the code so that part of it fits into a single page, the majority of the work was converting the code to assemble using the XA assembler. Sweet16 needs 32 bytes in zero page for the registers, so I chose locations $2B-$4A. This will stop Basic programs from working, unless you save and restore those locations when needed, but does allow the Basic SYS command to still execute machine code.

I have uploaded the patch and test program to github: sweet16_vic20. Full instructions for patching, assembling and running the code are provided in the README.

Example Code

Below are a few examples to show what Sweet 16 looks like in use.

Memory Region Copy

Copying a string to a new location with Sweet 16.

DST         = $02BC                   ; Destination for memory copy
LEN         = $0005                   ; Length of memory to copy


copyHello   jsr  SW16                 ; Execute following Sweet 16 code
            .byt $11, <hello, >hello  ; SET  R1   Source Address
            .byt $12, <DST, >DST      ; SET  R2   Destination Address
            .byt $13, <LEN, >LEN      ; SET  R3   Length
            .byt $41                  ; LD   @R1
            .byt $52                  ; ST   @R2
            .byt $F3                  ; DCR  R3
            .byt $07, $FB             ; BNZ  -4
            .byt $00                  ; RTN
            rts

hello       .asc "HELLO"              ; String to copy

16-bit Multiplication

Using Sweet 16 to calculate 255*100.

X           = 255                     ; The values to multiply
Y           = 100

mulNums     jsr  SW16                 ; Execute following Sweet 16 code
            .byt $10 : .word 0000     ; SET  R0   sum
            .byt $11 : .word X        ; SET  R1   x
            .byt $12 : .word Y        ; SET  R2   y
            .byt $13 : .word result   ; SET  R3   result
            .byt $F2                  ; DCR  R2
            .byt $05, $03             ; BM 3
            .byt $A1                  ; ADD  R1
            .byt $01, $FA             ; BR   -5
            .byt $73                  ; STD  @R3
            .byt $00                  ; RTN
            rts

result      .word $0000               ; The result of the multiplication

Two's Complement

Getting the two's complement of a number by using Sweet 16 to load the value, then returning to 6502 code to call a routine to one's complement the value, then finally going back to Sweet 16 to add one to the value.

A           = $0010                   ; The value to two's complement

negate      jsr  SW16                 ; Execute following Sweet 16 code
            .byt $11 : .word A        ; SET  R1   a
            .byt $13 : .word result   ; SET  R3   result
            .byt $21                  ; LD   R1
            .byt $73                  ; STD  @R3
            .byt $00                  ; RTN
            jsr  notRes               ; One's complement RESULT
            jsr  SW16                 ; Continue executing Sweet 16 code
            .byt $C3                  ; POPD @R3
            .byt $E0                  ; INR  R0
            .byt $73                  ; STD  @R3
            .byt $00                  ; RTN


            ; One's complement RESULT
notRes      lda  result
            eor  #$FF
            sta  result
            lda  result+1
            eor  #$FF
            sta  result+1
            rts

result      .word $0000               ; The result of the operation

Video Demonstrating Sweet 16

You can see Sweet 16 running on the Vic in the following video:

Creative Commons License
Sweet 16 (The 6502 Dream Machine) Ported to the VIC-20 by Lawrence Woodman is licensed under a Creative Commons Attribution 4.0 International License.

Share This Post

Feedback/Discuss

Related Articles

Getting the Address of BASIC Variables on the VIC-20

Getting the address of a BASIC variable can be useful if you want to pass data to a machine code routine or want to access the bytes of a variable directly to improve speed and reduce garbage collectio...   Read More

Saving and Loading Memory on the VIC-20

Saving and loading memory is quite easy on the VIC-20 once you know how. However, it isn't obvious how to do this and therefore this article will present a few simple ways of doing it from BASIC and A...   Read More

Programming in Assembly with VICMON on the VIC-20

VICMON is a machine language monitor released by Commodore in 1982 and is great for programming the VIC-20. Its interactive nature means that it can often be quicker to develop via this rather than us...   Read More

Storing Machine Code in REM Statements on the VIC-20

BASIC programs often contain machine code routines but they take up quite a lot of space in BASIC. An interesting way to reduce the amount of space that they take is to store the machine code in REM s...   Read More

Code and Data in Display Memory on the VIC-20

The unexpanded Commodore VIC-20 only had 5K of RAM and therefore creative ways had to be found to maximize the available RAM. The display memory would use some of this memory and therefore one option ...   Read More