Difference between revisions of "6502 Emulator Example Code"
Chris Tyler (talk | contribs) |
Chris Tyler (talk | contribs) |
||
(23 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 | + | [[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.''' | ||
== Fill the Bitmapped Display == | == Fill the Bitmapped Display == | ||
Line 8: | 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 |
− | loop: sta ($10),y ; store colour | + | lda #$07 ; colour code to be used to fill the display |
− | iny ; increment index | + | |
− | bne loop ; branch until | + | 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 | + | inc $11 ; increment high byte of pointer |
− | |||
cpx $11 ; compare with max value | cpx $11 ; compare with max value | ||
bne loop ; continue if not done | bne loop ; continue if not done | ||
− | + | brk ; done - return to debugger | |
== Place a Message on the Character Display == | == Place a Message on the Character Display == | ||
− | define SCREEN $f000 | + | === Without using the ROM routines === |
− | ldy #$00 | + | |
+ | define SCREEN $f000 ; location of screen memory | ||
+ | |||
+ | 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 ; 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 | ||
+ | |||
+ | === 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 == | == Type on the Screen == | ||
Line 43: | Line 72: | ||
; let the user type on the first page of character screen | ; let the user type on the first page of character screen | ||
; has blinking cursor! | ; has blinking cursor! | ||
+ | ; does not use ROM routines | ||
; backspace works (non-destructive), arrows/ENTER don't | ; backspace works (non-destructive), arrows/ENTER don't | ||
Line 107: | 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 116: | Line 146: | ||
done: brk ; stop when finished | done: brk ; stop when finished | ||
− | data: | + | data: ; graphic to be displayed |
dcb 00,03,03,00 | dcb 00,03,03,00 | ||
dcb 07,00,00,07 | dcb 07,00,00,07 | ||
Line 124: | Line 154: | ||
== Etch-a-Sketch<sup>tm</sup> Style Drawing == | == Etch-a-Sketch<sup>tm</sup> 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 |
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.
Contents
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