Skip to main content

6502 Emulator Example Code

This is a collection of simple examples of 6502 assembly language code which will run in the 6502 Emulator. To use this code, copy and paste one of these programs into the text box of the emulator.

This code is Copyright ©2020-2022 Seneca College of Applied Arts and Technology. Each of these programs is free software; you can redistribute them and/or modify them under the terms of the General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

Fill the Bitmapped Display

      lda #$00     ; set pointer at $10 to $0200
sta $10
lda #$02
sta $11

ldx #$06 ; max value for $11, the high byte of the pointer

ldy #$00 ; index - this value is added to the pointer

lda #$07 ; colour code to be used to fill the display

loop: sta ($10),y ; store colour to the value of the pointer + Y
iny ; increment index - prepare to fill next pixel
bne loop ; branch until page done - stops when Y==0

inc $11 ; increment high byte of pointer
cpx $11 ; compare with max value
bne loop ; continue if not done

brk ; done - return to debugger

Place a Message on the Character Display

Without using the ROM routines

 define SCREEN $f000     ; location of screen memory

ldy #$00 ; index value (character we're currently processing)

char: lda text,y ; get a character from address (text + Y)
beq done ; if the character is NULL, branch to done
sta SCREEN,y ; store character at (SCREEN + Y)
iny ; increment Y (go to next character)
bne char ; repeat loop

done: brk ; when we're done, break (stop the program)

text: ; this is the text message
dcb "6","5","0","2",32,"w","a","s",32,"h","e","r","e",".",00

Using the ROM routines

; ROM routines
define SCINIT $ff81 ; initialize/clear screen
define CHRIN $ffcf ; input character from keyboard
define CHROUT $ffd2 ; output character to screen
define SCREEN $ffed ; get screen size
define PLOT $fff0 ; get/set cursor coordinates

jsr SCINIT ; initialize and clear the screen
ldy #$00

char: lda text,y
beq done
jsr CHROUT ; put the character in A on to the screen
iny
bne char

done: brk

text:
dcb "6","5","0","2",32,"w","a","s",32,"h","e","r","e",".",00

Type on the Screen

; let the user type on the first page of character screen
; has blinking cursor!
; does not use ROM routines
; backspace works (non-destructive), arrows/ENTER don't

next: ldx #$00
idle: inx
cpx #$10
bne check
lda $f000,y
eor #$80
sta $f000,y

check: lda $ff
beq idle

ldx #$00
stx $ff

cmp #$08 ; bs
bne print

lda $f000,y
and #$7f
sta $f000,y

dey
jmp next

print: sta $f000,y
iny
jmp next

Place a Graphic on the Screen

 define WIDTH   4 ; width of graphic
define HEIGHT 4 ; height of graphic


lda #$25 ; create a pointer at $10
sta $10 ; which points to where
lda #$02 ; the graphic should be drawn
sta $11

lda #$00 ; number of rows we've drawn
sta $12 ; is stored in $12

ldx #$00 ; index for data
ldy #$00 ; index for screen column

draw: lda data,x
sta ($10),y
inx
iny
cpy #WIDTH
bne draw

inc $12 ; increment row counter

lda #HEIGHT ; are we done yet?
cmp $12
beq done ; ...exit if we are

lda $10 ; load pointer
clc
adc #$20 ; add 32 to drop one row
sta $10
lda $11 ; carry to high byte if needed
adc #$00
sta $11

ldy #$00
beq draw

done: brk ; stop when finished

data: ; graphic to be displayed
dcb 00,03,03,00
dcb 07,00,00,07
dcb 07,00,00,07
dcb 00,03,03,00

Etch-a-Sketchtm Style Drawing

; zero-page variable locations
define ROW $20 ; current row
define COL $21 ; current column
define POINTER $10 ; ptr: start of row
define POINTER_H $11

; constants
define DOT $01 ; dot colour
define CURSOR $04 ; black colour


ldy #$00 ; put help text on screen
print: lda help,y
beq setup
sta $f000,y
iny
bne print

setup: lda #$0f ; set initial ROW,COL
sta ROW
sta COL

draw: lda ROW ; ensure ROW is in range 0:31
and #$1f
sta ROW

lda COL ; ensure COL is in range 0:31
and #$1f
sta COL

ldy ROW ; load POINTER with start-of-row
lda table_low,y
sta POINTER
lda table_high,y
sta POINTER_H

ldy COL ; store CURSOR at POINTER plus COL
lda #CURSOR
sta (POINTER),y

getkey: lda $ff ; get a keystroke
beq getkey

ldx #$00 ; clear out the key buffer
stx $ff

cmp #$43 ; handle C or c
beq clear
cmp #$63
beq clear

cmp #$80 ; if not a cursor key, ignore
bmi getkey
cmp #$84
bpl getkey

pha ; save A

lda #DOT ; set current position to DOT
sta (POINTER),y

pla ; restore A

cmp #$80 ; check key == up
bne check1

dec ROW ; ... if yes, decrement ROW
jmp done

check1: cmp #$81 ; check key == right
bne check2

inc COL ; ... if yes, increment COL
jmp done

check2: cmp #$82 ; check if key == down
bne check3

inc ROW ; ... if yes, increment ROW
jmp done

check3: cmp #$83 ; check if key == left
bne done

dec COL ; ... if yes, decrement COL
clc
bcc done

clear: lda table_low ; clear the screen
sta POINTER
lda table_high
sta POINTER_H

ldy #$00
tya

c_loop: sta (POINTER),y
iny
bne c_loop

inc POINTER_H
ldx POINTER_H
cpx #$06
bne c_loop

done: clc ; repeat
bcc draw


; these two tables contain the high and low bytes
; of the addresses of the start of each row

table_high:
dcb $02,$02,$02,$02,$02,$02,$02,$02
dcb $03,$03,$03,$03,$03,$03,$03,$03
dcb $04,$04,$04,$04,$04,$04,$04,$04
dcb $05,$05,$05,$05,$05,$05,$05,$05,

table_low:
dcb $00,$20,$40,$60,$80,$a0,$c0,$e0
dcb $00,$20,$40,$60,$80,$a0,$c0,$e0
dcb $00,$20,$40,$60,$80,$a0,$c0,$e0
dcb $00,$20,$40,$60,$80,$a0,$c0,$e0

; help message for the character screen

help:
dcb "A","r","r","o","w",32,"k","e","y","s"
dcb 32,"d","r","a","w",32,"/",32,"'","C","'"
dcb 32,"k","e","y",32,"c","l","e","a","r","s"
dcb 00

Additional Examples

Additional examples, as well as the source code for the emulator's ROM routines, are in a repository at https://github.com/ctyler/6502js-code