Understanding 6502 assembly on the Commodore 64 - (6) Our instructions to assembly

In chapter 3 we listed all of the instructions we had done with regard to memory modification to achieve or goal.  Today we will convert those instructions into assembly and then onward to machine code where the C64 can understand it and execute the tasks.










In order to accomplish this, we will have to introduce a couple of new things that our program will require.  I will spend extra time on those things not previously discussed.   Ive tried to keep the complexity to a minimum.  You will find with assembly that like anything else, the more you optimize something, the more difficult it is to understand.   The code to be demonstrated has been written for understandability and not performance.

Remember our list from page 3

HERE IS WHERE WE STARTED FOR SPRITE 0

1) MODIFY D015 :      SET TO 01

2) MODIFY D000:       SET TO AA
3) MODIFY D001:       SET TO 8F
4) MODIFY 07F8:        SET TO 0B
5) MODIFY D017:       SET TO 01
6) MODIFY D01D:      SET TO 01

7) HIT RETURN A BUNCH OF TIMES TO CLEAR THE SCREEN


8) STARTING AT 02C0 ADD THIS INTO MEMORY SEQUENTIALLY :


03 FF 00 07 FF 80 0F FF
80 1F 83 80 3E 00 80 7C
00 7F 78 00 7E F8 00 7C
F0 00 78 F0 00 70 F0 00
00 F0 00 70 F0 00 78 F8
00 7C 78 00 7E 7C 00 7F
3E 00 80 1F 83 80 0F FF
80 07 FF 80 03 FF 00 00

9) HIT RETURN A BUNCH OF TIMES TO CLEAR THE SCREEN

HERE WE HAVE A LOGO IN THE MIDDLE OF THE SCREEN

10) MODIFY D000:       SET TO FF
11) MODIFY D001:       SET TO 32
12) MODIFY 0D17:       SET TO 00
13) MODIFY 0D1D:      SET TO 00

HERE WANTED TO MOVE TO LOGO FURTHER TO THE RIGHT 


14) MODIFY D010:       SET TO 01

15) MODIFY D000:       SET TO 3B

HERE WANTED TO MAKE THE LOGO RED


14) MODIFY D027:       SET TO F2


Lets get started!!!!!!


From our memory map we read


$C000-$CFFF
4K Free RAM

Locations 49152 to 53247 ($C000 to $CFFF) are free RAM.  Since this
area is not contiguous with the BASIC program text RAM area, it is not
available for BASIC program or variable storage (it is not counted in
the FRE(0) total).

In other words, lots of free space to store an assembly program.  We want to tell the assembler that the program which we are writing should begin at $C000.   We do it with this instruction

; OUR STARTING ADDRESS USING SYS 49152
*=$C000

As we read through the memory map of the C64 we saw that a lot of these areas have names associated with them.  It is easier to remember a name or label than it is to remember $D015, for instance.

In order to keep everyone on the same page, I've labeled everything according to our memory map guide.   Mind you they are not the most descriptive, but better than hex values.  You can name them whatever you want.

The semi colon, is a remark like and is ignored by the assembler.   Its good for adding notes


; Sprite Enable Register
SPENA = $D015

; Sprite Shape Data Pointers

SSDP0 = $07F8
SSDP1 = $07F9

; Sprite 0 Horizontal Position

SP0X = $D000

; Sprite 0 Vertical Position

SP0Y = $D001

; Sprite 1 Horizontal Position

SP1X = $D002

; Sprite 1 Vertical Position

SP1Y = $D003

; Most Significant Bits of Sprites 0-7 Horizontal Position

MSIGX = $D010

; Sprite Vertical Expansion Register

YXPAND = $D017

; Sprite Horizontal Expansion Register

XXPAND = $D01D

; Sprite 0 Color Register

SP0COL = $D027

; Sprite 1 Color Register

SP1COL = $D028

; Sprite Multicolor Registers

SPMC = $D01C

; Sprite 0 data start

SP0DATA = $02C0

; Character out

CHROUT = $FFD2


CHROUT is a new one,  This is a built in kernel function that outputs a character to screen, who's hex value is stored in the Accumulator.  This has a lot more overhead than merely setting a character to screen in memory, but includes such features as moving to the next line and scrolling up all the text when you reach the bottom.   This is a common tool used on the C64 so you might as well get an intro.


I like to make a label called START or INIT, thats just my thing.    To start off I want to clear the screen, in the same way you would type CLS in basic. we had this as instruction 7 on our previous list. Since we are not interfacing within the screen producing the sprite, we need only to clear the screen once.

7) HIT RETURN A BUNCH OF TIMES TO CLEAR THE SCREEN

I just added it to the top

; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)
START:
lda #$93
jsr CHROUT

On the C64 value 147 (hex 93) will clear the screen. LoaDing it into [A] and Jumping to SubRoutine CHROUT will clear the screen.  When CHROUT finishes, the program will continue just after the jsr CHROUT line.

From our list.........  I took out lines 5 and 6 and 12 and 13 since we doubled the size and then later undoubled it for demonstration purposes only

1) MODIFY D015 :      SET TO 01
2) MODIFY D000:       SET TO AA
3) MODIFY D001:       SET TO 8F
4) MODIFY 07F8:        SET TO 0B

Here it is in assembly

lda #$01
sta SPENA

lda #$AA

sta SP0X

lda #$8F

sta SP0Y

lda #$0B

sta SSDP0

So far we've done things step by step.  In our list we come to the point where we have to hand jam all of our bytes into memory area $02C0 to build out sprite

8) STARTING AT 02C0 ADD THIS INTO MEMORY SEQUENTIALLY :

03 FF 00 07 FF 80 0F FF
80 1F 83 80 3E 00 80 7C
00 7F 78 00 7E F8 00 7C
F0 00 78 F0 00 70 F0 00
00 F0 00 70 F0 00 78 F8
00 7C 78 00 7E 7C 00 7F
3E 00 80 1F 83 80 0F FF
80 07 FF 80 03 FF 00 00

If we were to follow our list to the letter of the law, I guess I could do something like this

!!!!!! Very bad example warning !!!!!!

lda #$03
sta $02C0
lda #$FF
sta $02C1
lda #00
sta $02C2

etc. etc. etc. etc. for 64 bytes.......

!!!!!! END OF BAD EXAMPLE !!!!!!

Something like this would make a person worthy of being flogged publicly in front of all computer programmers, and the 6502 gods would never smile upon you.

Its time to learn a simple buy highly necessary loop to copy data into memory.  Before we make the loop lets get that data (all 64 bytes) stored at the end of the program and assign a label to it. We leave this at the bottom of our program.  it will be stored with our program into memory directly after our RTS which ends the program.  It will literally be right after RTS our last instruction, which is shown in memory as 60

                                         hex from our program ## means anything
in memory we would see ## ## ## ## ## ## 60 03 FF 00 07 FF 80 and so on
our program never runs an instruction call 03 because 60 already ended the program, this is just data after the end.


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 

Good, so now we have all of this sprite data directly at the end of the program but we want to move each byte into the correct memory location starting at $02C0

;;;;;;;;;;;;;;;;;;;; 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

SP0INIT:

ldx #$00
jsr SPR0LOADLOOP
jsr MOVEANDCOLOR
rts


SP0INIT: is a label I made It is not jumped to, its just the next line after sta SSDP0.

At this point I want to make sure the X register is equal to 0 before I jump into the loop SPR0LOADLOOP.   This loop is heavily reliant on the value in X.  It is the same as in basic

LET X=0

With X being zero I jump into my SPR0LOADLOOP subroutine the RTS here is technically not necessary but good practice.



SPR0LOADLOOP:

lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts

This is the loop in all its glory, lets read it in english, remember X is zero from before. The first data value is 0 the second is 1 the third is 2 etc...

1. load A with our first (0) value from SPRITE0DATA which is $03
2. store value in A to SPODATA address with an offset of X (zero) or $02C0
3. Add 1 to X    (aka X=X+1)      "X is now equal to 1"
4. Compare the value of X to 64 (hex $40)
5. if it is not equal start the loop over at SPR0LOADLOOP

1. load A with our first (1) value from SPRITE0DATA which is $FF
2. store value in A to SPODATA address with an offset of X (1) or $02C1
3. Add 1 to X    (aka X=X+1)     "X is now equal to 2"
4. Compare the value of X to 64 (hex $40)
5. if it is not equal start the loop over at SPR0LOADLOOP

Once X equals 40, the program hits the RTS and returns under from where SPR0LOADLOOP was called. This takes it back under the jsr from SPOINIT, which is the next instruction jsr MOVEANDCOLOR.


10) MODIFY D000:       SET TO FF
11) MODIFY D001:       SET TO 32
12) MODIFY 0D17:       SET TO 00
13) MODIFY 0D1D:      SET TO 00

HERE WANTED TO MOVE TO LOGO FURTHER TO THE RIGHT 


14) MODIFY D010:       SET TO 01

15) MODIFY D000:       SET TO 3B

HERE WANTED TO MAKE THE LOGO RED


14) MODIFY D027:       SET TO F2


We already found a solution for the FF limitation, moving the logo to the right , so lets just implement it by making $D010 set to 01 and D000 set to $3B from the start. Then we will make the logo red


MOVEANDCOLOR:
; This adds 255 to the value of SPOX
lda #$01
sta MSIGX
; X coordinate SPRITE 0
lda #$3B
sta SP0X
; Y coordinate SPRITE 0
lda #$32
sta SP0Y
; Set the sprite color to RED
lda #$F2
sta SP0COL
rts

The end rts will take us back to the line just under jar MOVEANDCOLOR. this executes the last RTS which ends the program.


Heres a listing of the whole program in order, with much less commentary. You can however, paste this directly into Relaunch64 and hit the run button


; Jordans Super Duper Commodore Logo Maker

; 64TASS assembler style code for 6502
; Jordan Rubin 2014 http://technocoma.blogspot.com
;
;Creates a commodore logo SPRITE , moves it to the to right and makes it red 
;
;
; start program type SYS 49152
*=$C000

;;;;;;WORDS ARE EASIER TO REMEMBER THAN ADDRESSES, LETS ASSIGN NAMES TO OUR ADRESSES


; Sprite Enable Register

SPENA = $D015

; Sprite Shape Data Pointers

SSDP0 = $07F8
SSDP1 = $07F9

; Sprite 0 Horizontal Position

SP0X = $D000

; Sprite 0 Vertical Position

SP0Y = $D001

; Sprite 1 Horizontal Position

SP1X = $D002

; Sprite 1 Vertical Position

SP1Y = $D003

; Most Significant Bits of Sprites 0-7 Horizontal Position

MSIGX = $D010

; Sprite Vertical Expansion Register

YXPAND = $D017

; Sprite Horizontal Expansion Register

XXPAND = $D01D

; Sprite 0 Color Register

SP0COL = $D027

; Sprite 1 Color Register

SP1COL = $D028

; Sprite Multicolor Registers

SPMC = $D01C

; Sprite 0 data start

SP0DATA = $02C0

; Character out

CHROUT = $FFD2


;;;;;;;;;;;;; Load 147, hex $93 into A reg and JSR to CHROUT (Clears the screen)

START:
lda #$93
jsr CHROUT

;;;;;;;;;;;;; Put values into memory locations like we did by hand

lda #$01
sta SPENA

lda #$AA

sta SP0X

lda #$8F

sta SP0Y

lda #$0B

sta SSDP0

;;;;;;;;;;;;;;;;;;;; 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
SP0INIT:
ldx #$00
jsr SPR0LOADLOOP
jsr MOVEANDCOLOR
rts

SPR0LOADLOOP:

lda SPRITE0DATA,x
sta SP0DATA,x
inx
cpx #$40
bne SPR0LOADLOOP
rts

;;;;;;;;;;;;;;;;;;; Lets move it into position and color it red

MOVEANDCOLOR:
lda #$01
sta MSIGX

lda #$3B

sta SP0X

lda #$32

sta SP0Y

lda #$F2

sta SP0COL
rts

; Our sprite data for sprite 0

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        


NEXT----->Understanding 6502 assembly on the Commodore 64 - (7) The Assembler and Machine code Compiling


Table of contents




No comments:

Post a Comment