By now you've realized this series is not a quick and dirty instruction for cutting and pasting code allowing for instant gratification for displaying cool demos and raster effects on your screen. There are a great many pages which demonstrate this. This is about 6502 assembly, and the computers memory mapped archetecture.
Ive been doing my best to avoid NMI and IRQ. So far so good. I believe a quasi demonstration of an interrupt can be done without writing one.
In order to do this however, our sprite will need a friend. I thought now would be a good time to build some bridges so our new sprite (SPRITE1) is an Apple, or my poor rendition of an apple.
Adding the second sprite is self explanatory, but we will need some code to move our C64 logo about the screen. Please note that I have moved the SPRITE0 data to a new location with a vector of
$80 and SPRITE1 to $81. This would in fact allow my sprite loading loop to load both sprites into contiguous memory locations, but I keep it seperate for ease of following code. In the future we will load Sprite data all at once, but not now
Ive cleaned up the code a bit too so its easier to follow along........ Here it is
; Jordans Super duper commodore logo maker, mover and shaker
; 64TASS assembler style code for 6502
; Jordan Rubin 2014 http://technocoma.blogspot.com
; start program type SYS 49152
*=$C000
;;;;;;WORDS ARE EASIER TO REMEMBER THAN ADDRESSES, LETS ASSIGN NAMES TO OUR ADRESSES
SPENA = $D015 ; Sprite Enable Register
SSDP0 = $07F8 ; Sprite Shape Data Pointers
SSDP1 = $07F9
SP0X = $D000 ; Sprite 0 Horizontal Position
SP0Y = $D001 ; Sprite 0 Vertical Position
SP1X = $D002 ; Sprite 1 Horizontal Position
SP1Y = $D003 ; Sprite 1 Vertical Position
MSIGX = $D010 ; Most Significant Bits of Sprites 0-7 Horizontal Position
YXPAND = $D017 ; Sprite Vertical Expansion Register
XXPAND = $D01D ; Sprite Horizontal Expansion Register
SP0COL = $D027 ; Sprite 0 Color Register
SP1COL = $D028 ; Sprite 1 Color Register
SPMC = $D01C ; Sprite Multicolor Registers
SP0DATA = $2000 ; Sprite 0 and 1 data start
SP1DATA = $2040
CHROUT = $FFD2 ; Character out
SCNKEY = $FF9F ; Scan keyboard for keypress
GETIN = $FFE4 ; Get Input
START:
lda #$93
jsr CHROUT ; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)
lda #% 00000011
sta SPENA ; Activate SPRITE 0,1
lda #$90
sta SP0X ; Set X coordinate for SPRITE0
lda #$B1
sta SP1X ; Set X coordinate for SPRITE1
lda #$8F
sta SP0Y ; Set Y coordinate for SPRITE0
lda #$8F
sta SP1Y ; Set Y coordinate for SPRITE1
lda #$80
sta SSDP0 ; Set the location to find SPRITE0 Data
lda #$81
sta SSDP1 ; Set the location to find SPRITE0 Data
SP0INIT:
ldx #$00 ; SET X=0
jsr SPR0LOADLOOP ; Load SPRITE0 into memory
jsr SPR1LOADLOOP ; Load SPRITE1 into memory
jmp SCANKBD ; Scan Keyboard for a keypress
rts
;;;;;;;;;;;;;;;;;;;; This is a very quick and easy loader to move the sprite data
;;;;;;;;;;;;;;;;;;;; Into memory area SP0DATA, reading each byte and incrementing
;;;;;;;;;;;;;;;;;;;; the address until weve reached all 64 bytes, hex $40
SPR0LOADLOOP:
lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts
SPR1LOADLOOP:
lda SPRITE1DATA,x
sta SP1DATA,x
inx
cpx #$40
bne SPR1LOADLOOP
rts
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
jmp SCANKBD
;;;;;;;;;;;;;;; Incriment color value on keystroke C
COLORCHANGE:
ldy SP0COL
iny
sty SP0COL
jmp SCANKBD
;;;;;;;;;;;;;;; Cause program to end on keystroke E
END:
ldy #% 00000000
sty SPENA
rts
; DUMP OUT SPRITE DATA INTO OUR AREA SP0DATA and SP1DATA
SPRITE0DATA:
.byte $03, $FF, $00, $07, $FF, $80, $0F, $FF, $80, $1F, $83, $80, $3E, $00, $80
.byte $7C, $00, $7F, $78, $00, $7E, $F8, $00, $7C, $F0, $00, $78, $F0, $00, $70
.byte $F0, $00, $00, $F0, $00, $70, $F0, $00, $78, $F8, $00, $7C, $78, $00, $7E
.byte $7C, $00, $7F, $3E, $00, $80, $1F, $83, $80, $0F, $FF, $80, $07, $FF, $80
.byte $03, $FF, $00, $00
SPRITE1DATA:
.byte $02, $02, $00, $00, $88, $00, $00, $AA, $00, $0A, $AA, $80, $0A, $AA, $A0
.byte $2A, $AA, $A0, $2A, $AA, $A8, $2A, $AA, $A8, $2A, $AA, $A0, $2A, $AA, $80
.byte $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $A0, $2A, $AA, $A8
.byte $2A, $AA, $A8, $0A, $AA, $A0, $0A, $AA, $A0, $02, $AA, $A0, $00, $AA, $80
.byte $00, $A2, $00, $82
This is what we have now........ Stop laughing at my Applesprite!!!!!!
We are going to need 4 new keyboard functions to move our commodore logo, the apple will remain stationary, we also want something to happen when a collision is detected, maybe the apple turns green when they collide
So I created some new code in test to add functionality
UP is I, DOWN is K, LEFT is J, and RIGHT is L
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jmp SCANKBD
Now I need to create the corresponding labels and functions for UP DOWN LEFT RIGHT
UP:
ldy SP0Y
dey
sty SP0Y
jmp SCANKBD
DOWN:
ldy SP0Y
iny
sty SP0Y
jmp SCANKBD
LEFT:
ldy SP0X
dey
sty SP0X
jmp SCANKBD
RIGHT:
ldy SP0X
iny
sty SP0X
jmp SCANKBD
Too easy! we already know and have used SP0X and SP0Y in our program before, now its just a matter if incrementing and decrementing. Note that for ease of code, I have nothing that checks to see if the sprite is at the end of the screen or if its too far right to move any further past FF and will loop back to 00.
What we need now, is with each keystroke and movement, some way to test if there is a collision with sprite 1, and if so, what to do?
Well, we always come back to SCANKBD so why not a Jump to SubRoutine there to check for a collision and handle it appropriately
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
jsr COLLISION
This would be a bad idea. Why would we check for a collision over and over whilst waiting in our scan keyboard loop, why not check for a collision after a keypress, since the status isn't going to change until after the sprite is moved.
Lets put it here at the bottom to TEST just before we go back to scanning the keyboard
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jsr COLLISION PUT IT HERE
jmp SCANKBD
Lets now take a moment and look at our trusty memory map, looks like well need to assign $D01E the name of SPSPCL up top in our program
SPSPCL = $D01E ; Sprite collision register
Its a good thing we learned how to express a value as binary, we will be using it here, with 2 sprites this will be simple. If there is no sprite collision the value of D01E will be 00000000, if sprite0 collides with sprite 1, bits 0 and 1 will be high. so the value of D01E will be 00000011 as shown
COLLISION:
ldy SPSPCL
cpy #% 00000011 ; Did Sprite0 and Sprite1 collide?
beq APPLEGREEN ; if YES goto APPLEGREEN function
rts
APPLEGREEN:
lda #$F5
sta SP1COL ; turn apple color green
rts
Here it is in action!!!!
Lets look at the final program, our controls are
E - END
C - Color cycle the C64 logo
I - UP
K - DOWN
J - LEFT
L - RIGHT
; Jordans Super duper commodore logo maker, mover and shaker
; 64TASS assembler style code for 6502
; Jordan Rubin 2014 http://technocoma.blogspot.com
; start program type SYS 49152
*=$C000
;;;;;;WORDS ARE EASIER TO REMEMBER THAN ADDRESSES, LETS ASSIGN NAMES TO OUR ADRESSES
SPENA = $D015 ; Sprite Enable Register
SSDP0 = $07F8 ; Sprite Shape Data Pointers
SSDP1 = $07F9
SP0X = $D000 ; Sprite 0 Horizontal Position
SP0Y = $D001 ; Sprite 0 Vertical Position
SP1X = $D002 ; Sprite 1 Horizontal Position
SP1Y = $D003 ; Sprite 1 Vertical Position
MSIGX = $D010 ; Most Significant Bits of Sprites 0-7 Horizontal Position
YXPAND = $D017 ; Sprite Vertical Expansion Register
XXPAND = $D01D ; Sprite Horizontal Expansion Register
SP0COL = $D027 ; Sprite 0 Color Register
SP1COL = $D028 ; Sprite 1 Color Register
SPMC = $D01C ; Sprite Multicolor Registers
SP0DATA = $2000 ; Sprite 0 and 1 data start
SP1DATA = $2040
SPSPCL = $D01E ; Sprite collosion register
CHROUT = $FFD2 ; Character out
SCNKEY = $FF9F ; Scan keyboard for keypress
GETIN = $FFE4 ; Get Input
START:
lda #$93
jsr CHROUT ; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)
lda #% 00000011
sta SPENA ; Activate SPRITE 0,1
lda #$90
sta SP0X ; Set X coordinate for SPRITE0
lda #$B1
sta SP1X ; Set X coordinate for SPRITE1
lda #$8F
sta SP0Y ; Set Y coordinate for SPRITE0
lda #$8F
sta SP1Y ; Set Y coordinate for SPRITE1
lda #$80
sta SSDP0 ; Set the location to find SPRITE0 Data
lda #$81
sta SSDP1 ; Set the location to find SPRITE0 Data
SP0INIT:
ldx #$00 ; SET X=0
jsr SPR0LOADLOOP ; Load SPRITE0 into memory
jsr SPR1LOADLOOP ; Load SPRITE1 into memory
jmp SCANKBD ; Scan Keyboard for a keypress
rts
;;;;;;;;;;;;;;;;;;;; This is a very quick and easy loader to move the sprite data
;;;;;;;;;;;;;;;;;;;; Into memory area SP0DATA, reading each byte and incrementing
;;;;;;;;;;;;;;;;;;;; the address until weve reached all 64 bytes, hex $40
SPR0LOADLOOP:
lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts
SPR1LOADLOOP:
lda SPRITE1DATA,x
sta SP1DATA,x
inx
cpx #$40
bne SPR1LOADLOOP
rts
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jsr COLLISION
jmp SCANKBD
UP:
ldy SP0Y
dey
sty SP0Y
jmp SCANKBD
DOWN:
ldy SP0Y
iny
sty SP0Y
jmp SCANKBD
LEFT:
ldy SP0X
dey
sty SP0X
jmp SCANKBD
RIGHT:
ldy SP0X
iny
sty SP0X
jmp SCANKBD
COLLISION:
ldy SPSPCL
cpy #% 00000011 ; Did Sprite0 and Sprite1 collide?
beq APPLEGREEN ; if YES goto APPLEGREEN function
rts
APPLEGREEN:
lda #$F5
sta SP1COL ; turn apple color green
rts
;;;;;;;;;;;;;;; Incriment color value on keystroke C
COLORCHANGE:
ldy SP0COL
iny
sty SP0COL
jmp SCANKBD
;;;;;;;;;;;;;;; Cause program to end on keystroke E
END:
ldy #% 00000000
sty SPENA
rts
; DUMP OUT SPRITE DATA INTO OUR AREA SP0DATA and SP1DATA
SPRITE0DATA:
.byte $03, $FF, $00, $07, $FF, $80, $0F, $FF, $80, $1F, $83, $80, $3E, $00, $80
.byte $7C, $00, $7F, $78, $00, $7E, $F8, $00, $7C, $F0, $00, $78, $F0, $00, $70
.byte $F0, $00, $00, $F0, $00, $70, $F0, $00, $78, $F8, $00, $7C, $78, $00, $7E
.byte $7C, $00, $7F, $3E, $00, $80, $1F, $83, $80, $0F, $FF, $80, $07, $FF, $80
.byte $03, $FF, $00, $00
SPRITE1DATA:
.byte $02, $02, $00, $00, $88, $00, $00, $AA, $00, $0A, $AA, $80, $0A, $AA, $A0
.byte $2A, $AA, $A0, $2A, $AA, $A8, $2A, $AA, $A8, $2A, $AA, $A0, $2A, $AA, $80
.byte $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $A0, $2A, $AA, $A8
.byte $2A, $AA, $A8, $0A, $AA, $A0, $0A, $AA, $A0, $02, $AA, $A0, $00, $AA, $80
.byte $00, $A2, $00, $82
NEXT----->
Understanding 6502 assembly on the Commodore 64 - (12) Recap and Beginning Registers
Table of contents
Ive been doing my best to avoid NMI and IRQ. So far so good. I believe a quasi demonstration of an interrupt can be done without writing one.
In order to do this however, our sprite will need a friend. I thought now would be a good time to build some bridges so our new sprite (SPRITE1) is an Apple, or my poor rendition of an apple.
Adding the second sprite is self explanatory, but we will need some code to move our C64 logo about the screen. Please note that I have moved the SPRITE0 data to a new location with a vector of
$80 and SPRITE1 to $81. This would in fact allow my sprite loading loop to load both sprites into contiguous memory locations, but I keep it seperate for ease of following code. In the future we will load Sprite data all at once, but not now
Ive cleaned up the code a bit too so its easier to follow along........ Here it is
; Jordans Super duper commodore logo maker, mover and shaker
; 64TASS assembler style code for 6502
; Jordan Rubin 2014 http://technocoma.blogspot.com
; start program type SYS 49152
*=$C000
;;;;;;WORDS ARE EASIER TO REMEMBER THAN ADDRESSES, LETS ASSIGN NAMES TO OUR ADRESSES
SPENA = $D015 ; Sprite Enable Register
SSDP0 = $07F8 ; Sprite Shape Data Pointers
SSDP1 = $07F9
SP0X = $D000 ; Sprite 0 Horizontal Position
SP0Y = $D001 ; Sprite 0 Vertical Position
SP1X = $D002 ; Sprite 1 Horizontal Position
SP1Y = $D003 ; Sprite 1 Vertical Position
MSIGX = $D010 ; Most Significant Bits of Sprites 0-7 Horizontal Position
YXPAND = $D017 ; Sprite Vertical Expansion Register
XXPAND = $D01D ; Sprite Horizontal Expansion Register
SP0COL = $D027 ; Sprite 0 Color Register
SP1COL = $D028 ; Sprite 1 Color Register
SPMC = $D01C ; Sprite Multicolor Registers
SP0DATA = $2000 ; Sprite 0 and 1 data start
SP1DATA = $2040
CHROUT = $FFD2 ; Character out
SCNKEY = $FF9F ; Scan keyboard for keypress
GETIN = $FFE4 ; Get Input
START:
lda #$93
jsr CHROUT ; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)
lda #% 00000011
sta SPENA ; Activate SPRITE 0,1
lda #$90
sta SP0X ; Set X coordinate for SPRITE0
lda #$B1
sta SP1X ; Set X coordinate for SPRITE1
lda #$8F
sta SP0Y ; Set Y coordinate for SPRITE0
lda #$8F
sta SP1Y ; Set Y coordinate for SPRITE1
lda #$80
sta SSDP0 ; Set the location to find SPRITE0 Data
lda #$81
sta SSDP1 ; Set the location to find SPRITE0 Data
SP0INIT:
ldx #$00 ; SET X=0
jsr SPR0LOADLOOP ; Load SPRITE0 into memory
jsr SPR1LOADLOOP ; Load SPRITE1 into memory
jmp SCANKBD ; Scan Keyboard for a keypress
rts
;;;;;;;;;;;;;;;;;;;; This is a very quick and easy loader to move the sprite data
;;;;;;;;;;;;;;;;;;;; Into memory area SP0DATA, reading each byte and incrementing
;;;;;;;;;;;;;;;;;;;; the address until weve reached all 64 bytes, hex $40
SPR0LOADLOOP:
lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts
SPR1LOADLOOP:
lda SPRITE1DATA,x
sta SP1DATA,x
inx
cpx #$40
bne SPR1LOADLOOP
rts
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
jmp SCANKBD
;;;;;;;;;;;;;;; Incriment color value on keystroke C
COLORCHANGE:
ldy SP0COL
iny
sty SP0COL
jmp SCANKBD
;;;;;;;;;;;;;;; Cause program to end on keystroke E
END:
ldy #% 00000000
sty SPENA
rts
; DUMP OUT SPRITE DATA INTO OUR AREA SP0DATA and SP1DATA
SPRITE0DATA:
.byte $03, $FF, $00, $07, $FF, $80, $0F, $FF, $80, $1F, $83, $80, $3E, $00, $80
.byte $7C, $00, $7F, $78, $00, $7E, $F8, $00, $7C, $F0, $00, $78, $F0, $00, $70
.byte $F0, $00, $00, $F0, $00, $70, $F0, $00, $78, $F8, $00, $7C, $78, $00, $7E
.byte $7C, $00, $7F, $3E, $00, $80, $1F, $83, $80, $0F, $FF, $80, $07, $FF, $80
.byte $03, $FF, $00, $00
SPRITE1DATA:
.byte $02, $02, $00, $00, $88, $00, $00, $AA, $00, $0A, $AA, $80, $0A, $AA, $A0
.byte $2A, $AA, $A0, $2A, $AA, $A8, $2A, $AA, $A8, $2A, $AA, $A0, $2A, $AA, $80
.byte $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $A0, $2A, $AA, $A8
.byte $2A, $AA, $A8, $0A, $AA, $A0, $0A, $AA, $A0, $02, $AA, $A0, $00, $AA, $80
.byte $00, $A2, $00, $82
This is what we have now........ Stop laughing at my Applesprite!!!!!!
We are going to need 4 new keyboard functions to move our commodore logo, the apple will remain stationary, we also want something to happen when a collision is detected, maybe the apple turns green when they collide
So I created some new code in test to add functionality
UP is I, DOWN is K, LEFT is J, and RIGHT is L
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jmp SCANKBD
Now I need to create the corresponding labels and functions for UP DOWN LEFT RIGHT
UP:
ldy SP0Y
dey
sty SP0Y
jmp SCANKBD
DOWN:
ldy SP0Y
iny
sty SP0Y
jmp SCANKBD
LEFT:
ldy SP0X
dey
sty SP0X
jmp SCANKBD
RIGHT:
ldy SP0X
iny
sty SP0X
jmp SCANKBD
What we need now, is with each keystroke and movement, some way to test if there is a collision with sprite 1, and if so, what to do?
Well, we always come back to SCANKBD so why not a Jump to SubRoutine there to check for a collision and handle it appropriately
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
jsr COLLISION
This would be a bad idea. Why would we check for a collision over and over whilst waiting in our scan keyboard loop, why not check for a collision after a keypress, since the status isn't going to change until after the sprite is moved.
Lets put it here at the bottom to TEST just before we go back to scanning the keyboard
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jsr COLLISION PUT IT HERE
jmp SCANKBD
Lets now take a moment and look at our trusty memory map, looks like well need to assign $D01E the name of SPSPCL up top in our program
SPSPCL = $D01E ; Sprite collision register
53278 $D01E SPSPCL
Sprite to Sprite Collision Register
Bit 0: Did Sprite 0 collide with another sprite? (1=yes)
Bit 1: Did Sprite 1 collide with another sprite? (1=yes)
Bit 2: Did Sprite 2 collide with another sprite? (1=yes)
Bit 3: Did Sprite 3 collide with another sprite? (1=yes)
Bit 4: Did Sprite 4 collide with another sprite? (1=yes)
Bit 5: Did Sprite 5 collide with another sprite? (1=yes)
Bit 6: Did Sprite 6 collide with another sprite? (1=yes)
Bit 7: Did Sprite 7 collide with another sprite? (1=yes)
COLLISION:
ldy SPSPCL
cpy #% 00000011 ; Did Sprite0 and Sprite1 collide?
beq APPLEGREEN ; if YES goto APPLEGREEN function
rts
APPLEGREEN:
lda #$F5
sta SP1COL ; turn apple color green
rts
Here it is in action!!!!
Lets look at the final program, our controls are
E - END
C - Color cycle the C64 logo
I - UP
K - DOWN
J - LEFT
L - RIGHT
; Jordans Super duper commodore logo maker, mover and shaker
; 64TASS assembler style code for 6502
; Jordan Rubin 2014 http://technocoma.blogspot.com
; start program type SYS 49152
*=$C000
;;;;;;WORDS ARE EASIER TO REMEMBER THAN ADDRESSES, LETS ASSIGN NAMES TO OUR ADRESSES
SPENA = $D015 ; Sprite Enable Register
SSDP0 = $07F8 ; Sprite Shape Data Pointers
SSDP1 = $07F9
SP0X = $D000 ; Sprite 0 Horizontal Position
SP0Y = $D001 ; Sprite 0 Vertical Position
SP1X = $D002 ; Sprite 1 Horizontal Position
SP1Y = $D003 ; Sprite 1 Vertical Position
MSIGX = $D010 ; Most Significant Bits of Sprites 0-7 Horizontal Position
YXPAND = $D017 ; Sprite Vertical Expansion Register
XXPAND = $D01D ; Sprite Horizontal Expansion Register
SP0COL = $D027 ; Sprite 0 Color Register
SP1COL = $D028 ; Sprite 1 Color Register
SPMC = $D01C ; Sprite Multicolor Registers
SP0DATA = $2000 ; Sprite 0 and 1 data start
SP1DATA = $2040
SPSPCL = $D01E ; Sprite collosion register
CHROUT = $FFD2 ; Character out
SCNKEY = $FF9F ; Scan keyboard for keypress
GETIN = $FFE4 ; Get Input
START:
lda #$93
jsr CHROUT ; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)
lda #% 00000011
sta SPENA ; Activate SPRITE 0,1
lda #$90
sta SP0X ; Set X coordinate for SPRITE0
lda #$B1
sta SP1X ; Set X coordinate for SPRITE1
lda #$8F
sta SP0Y ; Set Y coordinate for SPRITE0
lda #$8F
sta SP1Y ; Set Y coordinate for SPRITE1
lda #$80
sta SSDP0 ; Set the location to find SPRITE0 Data
lda #$81
sta SSDP1 ; Set the location to find SPRITE0 Data
SP0INIT:
ldx #$00 ; SET X=0
jsr SPR0LOADLOOP ; Load SPRITE0 into memory
jsr SPR1LOADLOOP ; Load SPRITE1 into memory
jmp SCANKBD ; Scan Keyboard for a keypress
rts
;;;;;;;;;;;;;;;;;;;; This is a very quick and easy loader to move the sprite data
;;;;;;;;;;;;;;;;;;;; Into memory area SP0DATA, reading each byte and incrementing
;;;;;;;;;;;;;;;;;;;; the address until weve reached all 64 bytes, hex $40
SPR0LOADLOOP:
lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts
SPR1LOADLOOP:
lda SPRITE1DATA,x
sta SP1DATA,x
inx
cpx #$40
bne SPR1LOADLOOP
rts
;;;;;;;;;;;;;;;; Our scan keyboard function, if a key is pressed, it will appear
;;;;;;;;;;;;;;;; In the accumulator, hex value
SCANKBD:
jsr SCNKEY
jsr GETIN
;;;;;;;;;;;;;;; Check which key was pressed and JMP to its routine
TEST:
cmp #67
beq COLORCHANGE
cmp #69
beq END
cmp #73
beq UP
cmp #75
beq DOWN
cmp #74
beq LEFT
cmp #76
beq RIGHT
jsr COLLISION
jmp SCANKBD
UP:
ldy SP0Y
dey
sty SP0Y
jmp SCANKBD
DOWN:
ldy SP0Y
iny
sty SP0Y
jmp SCANKBD
LEFT:
ldy SP0X
dey
sty SP0X
jmp SCANKBD
RIGHT:
ldy SP0X
iny
sty SP0X
jmp SCANKBD
COLLISION:
ldy SPSPCL
cpy #% 00000011 ; Did Sprite0 and Sprite1 collide?
beq APPLEGREEN ; if YES goto APPLEGREEN function
rts
APPLEGREEN:
lda #$F5
sta SP1COL ; turn apple color green
rts
;;;;;;;;;;;;;;; Incriment color value on keystroke C
COLORCHANGE:
ldy SP0COL
iny
sty SP0COL
jmp SCANKBD
;;;;;;;;;;;;;;; Cause program to end on keystroke E
END:
ldy #% 00000000
sty SPENA
rts
; DUMP OUT SPRITE DATA INTO OUR AREA SP0DATA and SP1DATA
SPRITE0DATA:
.byte $03, $FF, $00, $07, $FF, $80, $0F, $FF, $80, $1F, $83, $80, $3E, $00, $80
.byte $7C, $00, $7F, $78, $00, $7E, $F8, $00, $7C, $F0, $00, $78, $F0, $00, $70
.byte $F0, $00, $00, $F0, $00, $70, $F0, $00, $78, $F8, $00, $7C, $78, $00, $7E
.byte $7C, $00, $7F, $3E, $00, $80, $1F, $83, $80, $0F, $FF, $80, $07, $FF, $80
.byte $03, $FF, $00, $00
SPRITE1DATA:
.byte $02, $02, $00, $00, $88, $00, $00, $AA, $00, $0A, $AA, $80, $0A, $AA, $A0
.byte $2A, $AA, $A0, $2A, $AA, $A8, $2A, $AA, $A8, $2A, $AA, $A0, $2A, $AA, $80
.byte $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $80, $2A, $AA, $A0, $2A, $AA, $A8
.byte $2A, $AA, $A8, $0A, $AA, $A0, $0A, $AA, $A0, $02, $AA, $A0, $00, $AA, $80
.byte $00, $A2, $00, $82
NEXT----->
Understanding 6502 assembly on the Commodore 64 - (12) Recap and Beginning Registers
Table of contents
Very nice tutorial! I'm really enjoying it so far.
ReplyDeleteOne note: In SP0INIT, you should add another ldx #$00 after returning from SPR0LOADLOOP. Right now, X is already $40 when entering SPR1LOADLOOP, so it has to run the loop 256 times so that X wraps back around to 0, then it can finally start copying our sprite data. This also has the side effect of obliterating whatever was in $2080-20bf. An even better solution, since labels are free, would be to include the *critical* "initialize X to 0" instruction *inside* the subroutine, and have an additional label for the loop.
Example:
SPR0LOAD:
ldx #$00
SPR0LOADLOOP:
lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts
Looking forward to continuing the tutorial!