Difference between revisions of "6502 Emulator Example Code"

From CDOT Wiki
Jump to: navigation, search
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:6502]][[Category:Assembly Language]][[Category:SPO600]]This is a collection of simple examples of [[6502]] 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 [http://6502.cdot.systems emulator].
+
[[Category:6502]][[Category:Assembly Language]][[Category:SPO600]]This is a collection of simple examples of [[6502]] [[assembly language|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 [http://6502.cdot.systems 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 [https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html|GNU General Public License] as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.'''
 
'''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 [https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html|GNU General Public License] as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.'''
Line 10: Line 10:
 
       sta $11
 
       sta $11
 
        
 
        
       ldx #$06    ; max value for $11
+
       ldx #$06    ; max value for $11, the high byte of the pointer
 
        
 
        
       ldy #$00    ; index
+
       ldy #$00    ; index - this value is added to the pointer
 
   
 
   
       lda #$07    ; colour code
+
       lda #$07    ; colour code to be used to fill the display
 
   
 
   
  loop: sta ($10),y  ; store colour
+
  loop: sta ($10),y  ; store colour to the value of the pointer + Y
       iny          ; increment index
+
       iny          ; increment index - prepare to fill next pixel
       bne loop    ; branch until page done
+
       bne loop    ; branch until page done - stops when Y==0
 
        
 
        
 
       inc $11      ; increment high byte of pointer
 
       inc $11      ; increment high byte of pointer
      lda $11      ; load page number as colour
 
 
       cpx $11      ; compare with max value
 
       cpx $11      ; compare with max value
 
       bne loop    ; continue if not done  
 
       bne loop    ; continue if not done  
Line 31: Line 30:
 
=== Without using the ROM routines ===
 
=== Without using the ROM routines ===
  
   define SCREEN $f000
+
   define SCREEN $f000     ; location of screen memory
             ldy #$00
+
 +
             ldy #$00     ; index value (character we're currently processing)
 
    
 
    
   char:    lda text,y
+
   char:    lda text,y   ; get a character from address (text + Y)
             beq done
+
             beq done      ; if the character is NULL, branch to done
             sta SCREEN,y
+
             sta SCREEN,y ; store character at (SCREEN + Y)
             iny
+
             iny           ; increment Y (go to next character)
             bne char
+
             bne char     ; repeat loop
 
    
 
    
   done:    brk
+
   done:    brk           ; when we're done, break (stop the program)
 
    
 
    
   text:
+
   text:                   ; this is the text message
 
   dcb "6","5","0","2",32,"w","a","s",32,"h","e","r","e",".",00
 
   dcb "6","5","0","2",32,"w","a","s",32,"h","e","r","e",".",00
  
Line 54: Line 54:
 
  define PLOT $fff0 ; get/set cursor coordinates
 
  define PLOT $fff0 ; get/set cursor coordinates
 
   
 
   
           jsr SCINIT
+
           jsr SCINIT ; initialize and clear the screen
 
           ldy #$00
 
           ldy #$00
 
   
 
   
 
  char:    lda text,y
 
  char:    lda text,y
 
           beq done
 
           beq done
           jsr CHROUT
+
           jsr CHROUT ; put the character in A on to the screen
 
           iny
 
           iny
 
           bne char
 
           bne char
Line 137: Line 137:
 
   adc #$20 ; add 32 to drop one row
 
   adc #$20 ; add 32 to drop one row
 
   sta $10
 
   sta $10
   lda $11 ; carry to high byte if needed
+
   lda $11         ; carry to high byte if needed
 
   adc #$00
 
   adc #$00
 
   sta $11
 
   sta $11
Line 154: Line 154:
 
== Etch-a-Sketch<sup>tm</sup> Style Drawing ==
 
== Etch-a-Sketch<sup>tm</sup> Style Drawing ==
  
  ; zero-page variable locations
+
; zero-page variable locations
  define ROW $20 ; current row
+
define ROW $20 ; current row
  define COL $21 ; current column
+
define COL $21 ; current column
  define POINTER $10 ; ptr: start of row
+
define POINTER $10 ; ptr: start of row
  define POINTER_H $11
+
define POINTER_H $11
 
+
  ; constants
+
; constants
  define DOT $01 ; dot colour
+
define DOT $01 ; dot colour
  define CURSOR $04 ; black colour
+
define CURSOR $04 ; black colour
 
+
 
+
  ldy #$00 ; put help text on screen
+
ldy #$00 ; put help text on screen
  print: lda help,y
+
print: lda help,y
  beq setup
+
beq setup
  sta $f000,y
+
sta $f000,y
  iny
+
iny
  bne print
+
bne print
 
+
  setup: lda #$0f ; set initial ROW,COL
+
setup: lda #$0f ; set initial ROW,COL
  sta ROW
+
sta ROW
  sta COL
+
sta COL
 
+
  draw: lda ROW ; ensure ROW is in range 0:31
+
draw: lda ROW ; ensure ROW is in range 0:31
  and #$1f
+
and #$1f
  sta ROW
+
sta ROW
 
+
  lda COL ; ensure COL is in range 0:31
+
lda COL ; ensure COL is in range 0:31
  and #$1f
+
and #$1f
  sta COL
+
sta COL
 
+
  ldy ROW ; load POINTER with start-of-row
+
ldy ROW ; load POINTER with start-of-row
  lda table_low,y
+
lda table_low,y
  sta POINTER
+
sta POINTER
  lda table_high,y
+
lda table_high,y
  sta POINTER_H
+
sta POINTER_H
 
+
  ldy COL ; store CURSOR at POINTER plus COL
+
ldy COL ; store CURSOR at POINTER plus COL
  lda #CURSOR
+
lda #CURSOR
  sta (POINTER),y
+
sta (POINTER),y
 
+
  getkey: lda $ff ; get a keystroke
+
getkey: lda $ff ; get a keystroke
 
+
beq getkey
  ldx #$00 ; clear out the key buffer
+
  stx $ff
+
ldx #$00 ; clear out the key buffer
 
+
stx $ff
  cmp #$43 ; handle C or c
+
  beq clear
+
cmp #$43 ; handle C or c
  cmp #$63
+
beq clear
  beq clear
+
cmp #$63
 
+
beq clear
  cmp #$80 ; if not a cursor key, ignore
+
  bmi getkey
+
cmp #$80 ; if not a cursor key, ignore
  cmp #$84
+
bmi getkey
  bpl getkey
+
cmp #$84
 
+
bpl getkey
  pha ; save A
+
 
+
pha ; save A
  lda #DOT ; set current position to DOT
+
  sta (POINTER),y
+
lda #DOT ; set current position to DOT
 
+
sta (POINTER),y
  pla ; restore A
+
 
+
pla ; restore A
  cmp #$80 ; check key == up
+
  bne check1
+
cmp #$80 ; check key == up
 
+
bne check1
  dec ROW ; ... if yes, decrement ROW
+
  jmp done
+
dec ROW ; ... if yes, decrement ROW
 
+
jmp done
  check1: cmp #$81 ; check key == right
+
  bne check2
+
check1: cmp #$81 ; check key == right
 
+
bne check2
  inc COL ; ... if yes, increment COL
+
  jmp done
+
inc COL ; ... if yes, increment COL
 
+
jmp done
  check2: cmp #$82 ; check if key == down
+
  bne check3
+
check2: cmp #$82 ; check if key == down
 
+
bne check3
  inc ROW ; ... if yes, increment ROW
+
  jmp done
+
inc ROW ; ... if yes, increment ROW
 
+
jmp done
  check3: cmp #$83 ; check if key == left
+
  bne done
+
check3: cmp #$83 ; check if key == left
 
+
bne done
  dec COL ; ... if yes, decrement COL
+
  clc
+
dec COL ; ... if yes, decrement COL
  bcc done
+
clc
 
+
bcc done
  clear: lda table_low ; clear the screen
+
  sta POINTER
+
clear: lda table_low ; clear the screen
  lda table_high
+
sta POINTER
  sta POINTER_H
+
lda table_high
 
+
sta POINTER_H
  ldy #$00
+
  tya
+
ldy #$00
 
+
tya
  c_loop: sta (POINTER),y
+
  iny
+
c_loop: sta (POINTER),y
  bne c_loop
+
iny
 
+
bne c_loop
  inc POINTER_H
+
  ldx POINTER_H
+
inc POINTER_H
  cpx #$06
+
ldx POINTER_H
  bne c_loop
+
cpx #$06
 
+
bne c_loop
  done: clc ; repeat
+
  bcc draw
+
done: clc ; repeat
 
+
bcc draw
 
+
  ; these two tables contain the high and low bytes
+
  ; of the addresses of the start of each row
+
; 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
+
table_high:
  dcb $03,$03,$03,$03,$03,$03,$03,$03
+
dcb $02,$02,$02,$02,$02,$02,$02,$02
  dcb $04,$04,$04,$04,$04,$04,$04,$04
+
dcb $03,$03,$03,$03,$03,$03,$03,$03
  dcb $05,$05,$05,$05,$05,$05,$05,$05,
+
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
+
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
  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 on character screen
+
 
+
; help message for the character screen
  help:
+
  dcb "A","r","r","o","w",32,"k","e","y","s"
+
help:
  dcb 32,"d","r","a","w",32,"/",32,"'","C","'"
+
dcb "A","r","r","o","w",32,"k","e","y","s"
  dcb 32,"k","e","y",32,"c","l","e","a","r","s"
+
dcb 32,"d","r","a","w",32,"/",32,"'","C","'"
  dcb 00
+
dcb 32,"k","e","y",32,"c","l","e","a","r","s"
 +
dcb 00
  
 
== Additional Examples ==
 
== 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
 
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

Latest revision as of 15:13, 13 September 2022

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