James Cat's rough && ready blog

Moving multicoloured objects (electrem)

Posted in 6502 by zzjames on January 23, 2013

I got this code out of a advanced programming book for the electron:

advanced electron machine code techniques

for some reason it doesn’t work on the beebem, although I’m sure it should. for this reason I downloaded the electron emulator.

I have added a lot of comments to the code, some of the spacing of the comment bars looks odd, but when pasted into the electrem in mode 3 (80 column text mode)) it looks mostly ok.

The hairiest part is the .calcaddress subroutine, this is very specific to how the RAM addresses relate to the pixels on screen, from the .draw routine we call .calcaddress with the  x and y coordinate we want to know the screen address for and when the subroutine returns to .draw the memory address of that pixel is in the memory address loc, which is &75.

This just gives us a flavour of assembly language programming, e.g. how you must take care not to overwrite values in registers when calling subroutines (just assume all variables are global) – because some registers have to be used to perform some operations, sometimes you might have to ‘save’ the register contents into RAM before you call a subroutine and load them back when you return from a subroutine.

here’s the source code:

REM MOVING MULTICOLOURED OBJECTS
REM AN IMPROVED METHOD FOR MODE 2
REM USING 80 * 256 COORDINATES
GOTO 140

DEF FNdataTable(N)
FOR item=1 TO N
READ D$
D=EVAL(“&”+D$)
?P%=D:P%=P%+1
NEXT item
=PASS

OSWRCH=&FFEE:OSBYTE=&FFF4
REM – this is where shit lives:

thisSpriteX=&70
thisSpriteY=&71
width=&72
height=&73
wcount=&74
LOC=&75
STORE=&77
data=&79
Yreg=&7B
bitmap1=&7C
bitmap2=&7E
sprite1_X=&80:sprite1_Y=&81
sprite2_X=&82:sprite2_Y=&83
DIM START 1000

REM – start two pass compilation loop:

FOR PASS=0 TO 3 STEP 3
P%=START
RESTORE

[OPT PASS

\ set up mode 2
LDA #&16
JSR OSWRCH
LDA #2
JSR OSWRCH

\ pointers to bitmap data – addresses are 16 bit so need 2 locations

LDA #(loadbitmap1 MOD 256) \ bitmap 1 low byte
STA bitmap1
LDA #(loadbitmap1 DIV 256) \ bitmap 1 high byte
STA bitmap1+1

LDA #(loadbitmap2 MOD 256) \ bitmap 2 low byte
STA bitmap2
LDA #(loadbitmap2 DIV 256) \ bitmap 2 high byte
STA bitmap2+1

\ set up initial coordinates
LDA #0
STA sprite1_X \ 1 is 0,0
STA sprite1_Y

LDA #34
STA sprite2_X \ 2 is 34,200
LDA #200
STA sprite2_Y

\ ——————————————————————– \

.LOOP \ game loop
INC sprite1_X \ sprite movements
INC sprite1_Y \ sprite movements
DEC sprite2_Y \ sprite movements

JSR SCREEN \ this subsroutine call is in the loop

LDA sprite2_Y \ test for exit conditions
CMP #0 \ is 2 off the screen yet?
BNE LOOP \ no
BEQ START \ yes

\ ——————————————————————– \

\ ————————————————–\
\ screen subroutine loads bitmapN \
\ pointer into $data and spriteN_X & \
\ spriteN_Y into X and Y regs \
\ ————————————————– \

.SCREEN \ store pointer to bitmap 1 in $data
LDA bitmap1
STA data
LDA bitmap1+1
STA data+1

LDA #&13 \ *FX 13 hardware lock on screen refresh
JSR OSBYTE \ call this now as everything is safely stored out of registers

LDX sprite1_X \ store x and y coords in x and y registers
LDY sprite1_Y

JSR draw \ call draw subroutine

LDA bitmap2 \ store pointer to bitmap 2 in $data
STA data
LDA bitmap2+1
STA data+1

LDX sprite2_X \ store x and y coords in x and y registers
LDY sprite2_Y

\ call draw subroutine
JSR draw
RTS

\ ——————————————————————– \

\ ——————————————————-\
\ draw subroutine writes to screen \
\ ram from top-left which uses calcaddress\
\ to get the memory location of the top-left \
\ ———————————————————— \

.draw
STX thisSpriteX \store current x,y
STY thisSpriteY \ these are used by calcaddress

LDY #0 \ initialise Y to zero for loop with Y

LDA (data),Y
STA height \ first data item is height
INY
LDA (data),Y \ look at next data item
STA width \ second data item is width

LDX #2 \ we’re on the second data item, store this fact in x….

.newrow
LDA #0
STA Yreg \ zero out Yregistration
LDA width \ load width
STA wcount \ put width into wcount

JSR CALCADDRESS \ calculate screen addresses from coordinates

.newcolumn
TXA \transfer x to the accumulator
TAY \ transfer the accumulator to Y (y = x)
\ (so first time) we pick up the loop from the 2 we stashed in x
LDA(data),Y \ start loading the bitmap into accumulator

LDY Yreg \ use y register as start off y offset
STA (LOC),Y \ write pixel value of bitmap starting at loc indirect index mode is 16bit so uses LOC and LOC+1

TYA \ add 8 to pixel value by transferring to accumulator
ADC #8 \ adding 8
STA Yreg \ transferring back to yreg location

INX \ increase count in x register
DEC wcount \ decrease width count
BNE newcolumn \ if wcount is not zero then loop

INC thisSpriteY \ thisSpriteY used in calcaddress subroutine
DEC height
BNE newrow
RTS

\ ——————————————————————– \
.CALCADDRESS

\ zero out some stuff
LDA #0
STA STORE+1 \ store only used in this subroutine
STA LOC \ loc and loc+1 used to return the screen address

\\ do X coordinate

LDA thisSpriteX \ load the current value in thisSpriteX
ASL A \ we need to multiple x by 8 so we shift left 3 times
ASL A \ we assume all values of x < 127 so we only need to
ROL STORE+1 \ start pickin up carry flag after 2nd shift
ASL A
ROL STORE+1 \ again pick up any carry
STA STORE \ put result in store (so store + 1 is msb)

\\ do Y coordinate

LDA thisSpriteY \ load the current thisSpriteY
AND #&F8 \ same as 8*(y div 8) looses 3 least sig bits
LSR A \ two right shifts gives the same high byte as
LSR A \ six left shifts on a 2 byte number
STA LOC+1 \ store the 64*(y div 8) in loc high byte
\ we don’t need to store a low byte because we know the last 3 bits were zero from the AND #&F8

LSR A \ double right shift gives us 64(8*(y div 8)) / 4 = 16(8*(y div 8))
LSR A
ROR LOC \ pick up the carry in loc’s low byte

\\ add them together
ADC LOC+1 \ add back the previously stored 64*(y div 8) gives 80*(y div 8)

TAY \ stash in Y register

\\ do the final y mod 8 to get the number of pixels down into the block
LDA thisSpriteY
AND #7

\\ add thec components together

ADC LOC \ add to LOCs low byte (as y mod 8 will only be a single byte)
ADC STORE \ add store low btye (8x value)
STA LOC \ store this subtotal in LOC
TYA \ get back the 80*(y div 8) result
ADC STORE+1 \ add the store high byte
ADC #&30 \ add on the &3000
STA LOC+1 \ store in loc high byte
RTS

\ ————-load bitmap data into sprite 1 & 2 ————— \
.loadbitmap1
OPT FNdataTable(86)
.loadbitmap2
OPT FNdataTable(62)
RTS

] : REM back to basic

REM \ —————————————————————– \

NEXT PASS
CALL START

REM \ —————————————————————– \

REM THIS IS THE bitmap1 DATA
DATA E,6
DATA 0,0,0,0,0,0
DATA 0,0,0,0,0,0
DATA 0,0,4F,8F,0,0
DATA 0,0,1,2,0,0
DATA 0,0,1,2,0,0
DATA 0,0,3,3,0,0
DATA 0,1,3,3,2,0
DATA 0,3,9,6,3,0
DATA 0,3,3,3,3,0
DATA 0,3,3,3,3,0
DATA 0,3,3,3,3,0
DATA 0,0,2,1,0,0
DATA 0,0,0,0,0,0
DATA 0,0,0,0,0,0

REM THIS IS THE bitmap2 DATA
DATA A,6
DATA 0,0,0,0,0,0
DATA 0,0,0,0,0,0
DATA 0,0,1,2,0,0
DATA 0,0,3,3,0,0
DATA 0,1,3,3,2,0
DATA 0,3,9,6,3,0
DATA 0,3,3,3,3,0
DATA 0,0,2,1,0,0
DATA 0,0,0,0,0,0
DATA 0,0,0,0,0,0

I guess without going into detail if you don’t know much about the acorn assembler and mos  some of that is going to be a big mystery, but more on that later.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: