mirror of
https://github.com/jborza/emu6502.git
synced 2025-02-19 07:30:57 +00:00
test binaries for the graphic emulator
This commit is contained in:
parent
ea7c3bf731
commit
676c62c171
BIN
bins/00.bin
Normal file
BIN
bins/00.bin
Normal file
Binary file not shown.
8
bins/01.asm
Normal file
8
bins/01.asm
Normal file
@ -0,0 +1,8 @@
|
||||
LDY #$0F
|
||||
LDX #$00
|
||||
loop:
|
||||
TYA
|
||||
STA $0200,X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
BIN
bins/01.bin
Normal file
BIN
bins/01.bin
Normal file
Binary file not shown.
8
bins/01a.asm
Normal file
8
bins/01a.asm
Normal file
@ -0,0 +1,8 @@
|
||||
LDY #$0F
|
||||
LDX #$00
|
||||
loop:
|
||||
TYA
|
||||
STA $0200,X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
BIN
bins/01a.bin
Normal file
BIN
bins/01a.bin
Normal file
Binary file not shown.
8
bins/02.asm
Normal file
8
bins/02.asm
Normal file
@ -0,0 +1,8 @@
|
||||
LDY #$0F
|
||||
LDX #$00
|
||||
loop:
|
||||
TYA
|
||||
STA $0200,X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
BIN
bins/02.bin
Normal file
BIN
bins/02.bin
Normal file
Binary file not shown.
22
bins/03.asm
Normal file
22
bins/03.asm
Normal file
@ -0,0 +1,22 @@
|
||||
;number of loops to perform
|
||||
LDA #$10
|
||||
STA $A0
|
||||
|
||||
;number of bytes to color in a loop
|
||||
|
||||
outer:
|
||||
LDY #$0A
|
||||
;LDX #$00
|
||||
|
||||
loop:
|
||||
;LDA #$01
|
||||
STA $0200, X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
||||
|
||||
;outer loop handling
|
||||
DEC $A0
|
||||
LDA $A0
|
||||
BNE outer
|
||||
|
BIN
bins/03.bin
Normal file
BIN
bins/03.bin
Normal file
Binary file not shown.
22
bins/04.asm
Normal file
22
bins/04.asm
Normal file
@ -0,0 +1,22 @@
|
||||
;number of loops to perform
|
||||
LDA #$10
|
||||
STA $A0
|
||||
|
||||
|
||||
outer:
|
||||
;number of bytes to color in a loop
|
||||
LDY #$03
|
||||
;LDX #$00
|
||||
|
||||
loop:
|
||||
;LDA #$01
|
||||
STA $0200, X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
||||
|
||||
;outer loop handling
|
||||
DEC $A0
|
||||
LDA $A0
|
||||
BNE outer
|
||||
|
BIN
bins/04.bin
Normal file
BIN
bins/04.bin
Normal file
Binary file not shown.
17
bins/05.asm
Normal file
17
bins/05.asm
Normal file
@ -0,0 +1,17 @@
|
||||
; color loop with the stack
|
||||
LDX #$00
|
||||
LDY #$00
|
||||
firstloop:
|
||||
TXA
|
||||
STA $0200,Y
|
||||
PHA
|
||||
INX
|
||||
INY
|
||||
CPY #$10
|
||||
BNE firstloop ;loop until Y is $10
|
||||
secondloop:
|
||||
PLA
|
||||
STA $0200,Y
|
||||
INY
|
||||
CPY #$20 ;loop until Y is $20
|
||||
BNE secondloop
|
BIN
bins/05.bin
Normal file
BIN
bins/05.bin
Normal file
Binary file not shown.
32
bins/06.asm
Normal file
32
bins/06.asm
Normal file
@ -0,0 +1,32 @@
|
||||
start:
|
||||
;number of loops to perform
|
||||
LDA #$10
|
||||
STA $A0
|
||||
|
||||
|
||||
outer:
|
||||
;number of bytes to color in a loop
|
||||
LDY #$03
|
||||
;LDX #$00
|
||||
|
||||
loop:
|
||||
;LDA #$01
|
||||
STA $0200, X
|
||||
INX
|
||||
DEY
|
||||
BNE loop
|
||||
|
||||
;outer loop handling
|
||||
DEC $A0
|
||||
LDA $A0
|
||||
BNE outer
|
||||
|
||||
;overwrite the address for drawing and loop once again
|
||||
|
||||
LDA #$30
|
||||
ADC $0607 ;add 3*16 for the next color strip
|
||||
STA $0607
|
||||
LDA #$90
|
||||
CMP $0607
|
||||
;LDA $0607
|
||||
BNE start
|
1
bins/06.bin
Normal file
1
bins/06.bin
Normal file
@ -0,0 +1 @@
|
||||
©… <03>Υθ<>ΠωΖ ¥ Πρ©0m<06>©<>ΝΠή
|
19
bins/07.asm
Normal file
19
bins/07.asm
Normal file
@ -0,0 +1,19 @@
|
||||
LDX #$00
|
||||
LDY #$00
|
||||
firstloop:
|
||||
TXA
|
||||
STA $0200,Y
|
||||
PHA
|
||||
INX
|
||||
INY
|
||||
STA $0200,Y
|
||||
INY
|
||||
PHA
|
||||
CPY #$20
|
||||
BNE firstloop ;loop until Y is $10
|
||||
secondloop:
|
||||
PLA
|
||||
STA $0200,Y
|
||||
INY
|
||||
CPY #$40 ;loop until Y is $20
|
||||
BNE secondloop
|
BIN
bins/07.bin
Normal file
BIN
bins/07.bin
Normal file
Binary file not shown.
24
bins/easy6502_notes.txt
Normal file
24
bins/easy6502_notes.txt
Normal file
@ -0,0 +1,24 @@
|
||||
Notes:
|
||||
|
||||
Memory location $fe contains a new random byte on every instruction.
|
||||
Memory location $ff contains the ascii code of the last key pressed.
|
||||
|
||||
Memory locations $200 to $5ff map to the screen pixels. Different values will
|
||||
draw different colour pixels. The colours are:
|
||||
|
||||
$0: Black
|
||||
$1: White
|
||||
$2: Red
|
||||
$3: Cyan
|
||||
$4: Purple
|
||||
$5: Green
|
||||
$6: Blue
|
||||
$7: Yellow
|
||||
$8: Orange
|
||||
$9: Brown
|
||||
$a: Light red
|
||||
$b: Dark grey
|
||||
$c: Grey
|
||||
$d: Light green
|
||||
$e: Light blue
|
||||
$f: Light grey
|
22
bins/hex2bin.py
Normal file
22
bins/hex2bin.py
Normal file
@ -0,0 +1,22 @@
|
||||
import sys
|
||||
|
||||
output_name = sys.argv[1]
|
||||
print(output_name)
|
||||
|
||||
f = open(output_name, 'wb')
|
||||
|
||||
def as_byte(value):
|
||||
return bytes([value])
|
||||
|
||||
def process_line(line):
|
||||
hexes = line[5:].strip()
|
||||
hex_values = [int(hex,16) for hex in hexes.split(' ')]
|
||||
for hex_value in hex_values:
|
||||
print(as_byte(hex_value))
|
||||
f.write(as_byte(hex_value))
|
||||
#print(chr(hex_value), end = '')
|
||||
|
||||
for line in sys.stdin:
|
||||
process_line(line)
|
||||
|
||||
f.close()
|
274
bins/snake.asm
Normal file
274
bins/snake.asm
Normal file
@ -0,0 +1,274 @@
|
||||
; ___ _ __ ___ __ ___
|
||||
; / __|_ _ __ _| |_____ / /| __|/ \_ )
|
||||
; \__ \ ' \/ _` | / / -_) _ \__ \ () / /
|
||||
; |___/_||_\__,_|_\_\___\___/___/\__/___|
|
||||
|
||||
; Change direction: W A S D
|
||||
|
||||
define appleL $00 ; screen location of apple, low byte
|
||||
define appleH $01 ; screen location of apple, high byte
|
||||
define snakeHeadL $10 ; screen location of snake head, low byte
|
||||
define snakeHeadH $11 ; screen location of snake head, high byte
|
||||
define snakeBodyStart $12 ; start of snake body byte pairs
|
||||
define snakeDirection $02 ; direction (possible values are below)
|
||||
define snakeLength $03 ; snake length, in bytes
|
||||
|
||||
; Directions (each using a separate bit)
|
||||
define movingUp 1
|
||||
define movingRight 2
|
||||
define movingDown 4
|
||||
define movingLeft 8
|
||||
|
||||
; ASCII values of keys controlling the snake
|
||||
define ASCII_w $77
|
||||
define ASCII_a $61
|
||||
define ASCII_s $73
|
||||
define ASCII_d $64
|
||||
|
||||
; System variables
|
||||
define sysRandom $fe
|
||||
define sysLastKey $ff
|
||||
|
||||
|
||||
jsr init
|
||||
jsr loop
|
||||
|
||||
init:
|
||||
jsr initSnake
|
||||
jsr generateApplePosition
|
||||
rts
|
||||
|
||||
|
||||
initSnake:
|
||||
lda #movingRight ;start direction
|
||||
sta snakeDirection
|
||||
|
||||
lda #4 ;start length (2 segments)
|
||||
sta snakeLength
|
||||
|
||||
lda #$11
|
||||
sta snakeHeadL
|
||||
|
||||
lda #$10
|
||||
sta snakeBodyStart
|
||||
|
||||
lda #$0f
|
||||
sta $14 ; body segment 1
|
||||
|
||||
lda #$04
|
||||
sta snakeHeadH
|
||||
sta $13 ; body segment 1
|
||||
sta $15 ; body segment 2
|
||||
rts
|
||||
|
||||
|
||||
generateApplePosition:
|
||||
;load a new random byte into $00
|
||||
lda sysRandom
|
||||
sta appleL
|
||||
|
||||
;load a new random number from 2 to 5 into $01
|
||||
lda sysRandom
|
||||
and #$03 ;mask out lowest 2 bits
|
||||
clc
|
||||
adc #2
|
||||
sta appleH
|
||||
|
||||
rts
|
||||
|
||||
|
||||
loop:
|
||||
jsr readKeys
|
||||
jsr checkCollision
|
||||
jsr updateSnake
|
||||
jsr drawApple
|
||||
jsr drawSnake
|
||||
jsr spinWheels
|
||||
jmp loop
|
||||
|
||||
|
||||
readKeys:
|
||||
lda sysLastKey
|
||||
cmp #ASCII_w
|
||||
beq upKey
|
||||
cmp #ASCII_d
|
||||
beq rightKey
|
||||
cmp #ASCII_s
|
||||
beq downKey
|
||||
cmp #ASCII_a
|
||||
beq leftKey
|
||||
rts
|
||||
upKey:
|
||||
lda #movingDown
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingUp
|
||||
sta snakeDirection
|
||||
rts
|
||||
rightKey:
|
||||
lda #movingLeft
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingRight
|
||||
sta snakeDirection
|
||||
rts
|
||||
downKey:
|
||||
lda #movingUp
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingDown
|
||||
sta snakeDirection
|
||||
rts
|
||||
leftKey:
|
||||
lda #movingRight
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingLeft
|
||||
sta snakeDirection
|
||||
rts
|
||||
illegalMove:
|
||||
rts
|
||||
|
||||
|
||||
checkCollision:
|
||||
jsr checkAppleCollision
|
||||
jsr checkSnakeCollision
|
||||
rts
|
||||
|
||||
|
||||
checkAppleCollision:
|
||||
lda appleL
|
||||
cmp snakeHeadL
|
||||
bne doneCheckingAppleCollision
|
||||
lda appleH
|
||||
cmp snakeHeadH
|
||||
bne doneCheckingAppleCollision
|
||||
|
||||
;eat apple
|
||||
inc snakeLength
|
||||
inc snakeLength ;increase length
|
||||
jsr generateApplePosition
|
||||
doneCheckingAppleCollision:
|
||||
rts
|
||||
|
||||
|
||||
checkSnakeCollision:
|
||||
ldx #2 ;start with second segment
|
||||
snakeCollisionLoop:
|
||||
lda snakeHeadL,x
|
||||
cmp snakeHeadL
|
||||
bne continueCollisionLoop
|
||||
|
||||
maybeCollided:
|
||||
lda snakeHeadH,x
|
||||
cmp snakeHeadH
|
||||
beq didCollide
|
||||
|
||||
continueCollisionLoop:
|
||||
inx
|
||||
inx
|
||||
cpx snakeLength ;got to last section with no collision
|
||||
beq didntCollide
|
||||
jmp snakeCollisionLoop
|
||||
|
||||
didCollide:
|
||||
jmp gameOver
|
||||
didntCollide:
|
||||
rts
|
||||
|
||||
|
||||
updateSnake:
|
||||
ldx snakeLength
|
||||
dex
|
||||
txa
|
||||
updateloop:
|
||||
lda snakeHeadL,x
|
||||
sta snakeBodyStart,x
|
||||
dex
|
||||
bpl updateloop
|
||||
|
||||
lda snakeDirection
|
||||
lsr
|
||||
bcs up
|
||||
lsr
|
||||
bcs right
|
||||
lsr
|
||||
bcs down
|
||||
lsr
|
||||
bcs left
|
||||
up:
|
||||
lda snakeHeadL
|
||||
sec
|
||||
sbc #$20
|
||||
sta snakeHeadL
|
||||
bcc upup
|
||||
rts
|
||||
upup:
|
||||
dec snakeHeadH
|
||||
lda #$1
|
||||
cmp snakeHeadH
|
||||
beq collision
|
||||
rts
|
||||
right:
|
||||
inc snakeHeadL
|
||||
lda #$1f
|
||||
bit snakeHeadL
|
||||
beq collision
|
||||
rts
|
||||
down:
|
||||
lda snakeHeadL
|
||||
clc
|
||||
adc #$20
|
||||
sta snakeHeadL
|
||||
bcs downdown
|
||||
rts
|
||||
downdown:
|
||||
inc snakeHeadH
|
||||
lda #$6
|
||||
cmp snakeHeadH
|
||||
beq collision
|
||||
rts
|
||||
left:
|
||||
dec snakeHeadL
|
||||
lda snakeHeadL
|
||||
and #$1f
|
||||
cmp #$1f
|
||||
beq collision
|
||||
rts
|
||||
collision:
|
||||
jmp gameOver
|
||||
|
||||
|
||||
drawApple:
|
||||
ldy #0
|
||||
lda sysRandom
|
||||
sta (appleL),y
|
||||
rts
|
||||
|
||||
|
||||
drawSnake:
|
||||
ldx snakeLength
|
||||
lda #0
|
||||
sta (snakeHeadL,x) ; erase end of tail
|
||||
|
||||
ldx #0
|
||||
lda #1
|
||||
sta (snakeHeadL,x) ; paint head
|
||||
rts
|
||||
|
||||
|
||||
spinWheels:
|
||||
ldx #0
|
||||
spinloop:
|
||||
nop
|
||||
nop
|
||||
dex
|
||||
bne spinloop
|
||||
rts
|
||||
|
||||
|
||||
gameOver:
|
BIN
bins/snake.bin
Normal file
BIN
bins/snake.bin
Normal file
Binary file not shown.
452
bins/snake6502.asm
Normal file
452
bins/snake6502.asm
Normal file
@ -0,0 +1,452 @@
|
||||
; ___ _ __ ___ __ ___
|
||||
; / __|_ _ __ _| |_____ / /| __|/ \_ )
|
||||
; \__ \ ' \/ _` | / / -_) _ \__ \ () / /
|
||||
; |___/_||_\__,_|_\_\___\___/___/\__/___|
|
||||
|
||||
; An annotated version of the snake example from Nick Morgan's 6502 assembly tutorial
|
||||
; on http://skilldrick.github.io/easy6502/ that I created as an exercise for myself
|
||||
; to learn a little bit about assembly. I **think** I understood everything, but I may
|
||||
; also be completely wrong :-)
|
||||
|
||||
; Change direction with keys: W A S D
|
||||
|
||||
; $00-01 => screen location of apple, stored as two bytes, where the first
|
||||
; byte is the least significant.
|
||||
; $10-11 => screen location of snake head stored as two bytes
|
||||
; $12-?? => snake body (in byte pairs)
|
||||
; $02 => direction ; 1 => up (bin 0001)
|
||||
; 2 => right (bin 0010)
|
||||
; 4 => down (bin 0100)
|
||||
; 8 => left (bin 1000)
|
||||
; $03 => snake length, in number of bytes, not segments
|
||||
|
||||
|
||||
;The screens is divided in 8 strips of 8x32 "pixels". Each strip
|
||||
;is stored in a page, having their own most significant byte. Each
|
||||
;page has 256 bytes, starting at $00 and ending at $ff.
|
||||
|
||||
; ------------------------------------------------------------
|
||||
;1 | $0200 - $02ff |
|
||||
;2 | |
|
||||
;3 | |
|
||||
;4 | |
|
||||
;5 | |
|
||||
;6 | |
|
||||
;7 | |
|
||||
;8 | |
|
||||
; ------------------------------------------------------------
|
||||
;9 | $03 - $03ff |
|
||||
;10 | |
|
||||
;11 | |
|
||||
;12 | |
|
||||
;13 | |
|
||||
;14 | |
|
||||
;15 | |
|
||||
;16 | |
|
||||
; ------------------------------------------------------------
|
||||
;17 | $04 - $03ff |
|
||||
;18 | |
|
||||
;19 | |
|
||||
;20 | |
|
||||
;21 | |
|
||||
;22 | |
|
||||
;23 | |
|
||||
;24 | |
|
||||
; ------------------------------------------------------------
|
||||
;25 | $05 - $03ff |
|
||||
;26 | |
|
||||
;27 | |
|
||||
;28 | |
|
||||
;29 | |
|
||||
;30 | |
|
||||
;31 | |
|
||||
;32 | |
|
||||
; ------------------------------------------------------------
|
||||
|
||||
jsr init ;jump to subroutine init
|
||||
jsr loop ;jump to subroutine loop
|
||||
|
||||
init:
|
||||
jsr initSnake ;jump to subroutine initSnake
|
||||
jsr generateApplePosition ;jump to subroutine generateApplePosition
|
||||
rts ;return
|
||||
|
||||
|
||||
initSnake:
|
||||
;start the snake in a horizontal position in the middle of the game field
|
||||
;having a total length of one head and 4 bytes for the segments, meaning a
|
||||
;total length of 3: the head and two segments.
|
||||
;The head is looking right, and the snaking moving to the right.
|
||||
|
||||
;initial snake direction (2 => right)
|
||||
lda #2 ;start direction, put the dec number 2 in register A
|
||||
sta $02 ;store value of register A at address $02
|
||||
|
||||
;initial snake length of 4
|
||||
lda #4 ;start length, put the dec number 4 (the snake is 4 bytes long)
|
||||
;in register A
|
||||
sta $03 ;store value of register A at address $03
|
||||
|
||||
;Initial snake head's location's least significant byte to determine
|
||||
;where in a 8x32 strip the head will start. hex $11 is just right
|
||||
;of the center of the first row of a strip
|
||||
lda #$11 ;put the hex number $11 (dec 17) in register A
|
||||
sta $10 ;store value of register A at address hex 10
|
||||
|
||||
;Initial snake body, two least significant bytes set to hex $10
|
||||
;and hex $0f, one and two places left of the head respectively
|
||||
lda #$10 ;put the hex number $10 (dec 16) in register A
|
||||
sta $12 ;store value of register A at address hex $12
|
||||
lda #$0f ;put the hex number $0f (dec 15) in register A
|
||||
sta $14 ;store value of register A at address hex $14
|
||||
|
||||
;the most significant bytes of the head and body of the snake
|
||||
;are all set to hex $04, which is the third 8x32 strip.
|
||||
lda #$04 ;put the hex number $04 in register A
|
||||
sta $11 ;store value of register A at address hex 11
|
||||
sta $13 ;store value of register A at address hex 13
|
||||
sta $15 ;store value of register A at address hex 15
|
||||
rts ;return
|
||||
|
||||
|
||||
generateApplePosition:
|
||||
;Th least significant byte of the apple position will determine where
|
||||
;in a 8x32 strip the apple is placed. This number can be any one byte value because
|
||||
;the size of one 8x32 strip fits exactly in one out of 256 bytes
|
||||
lda $fe ;load a random number between 0 and 255 from address $fe into register A
|
||||
sta $00 ;store value of register A at address hex 00
|
||||
|
||||
;load a new random number from 2 to 5 into $01 for the most significant byte of
|
||||
;the apple position. This will determine in which 8x32 strip the apple is placed
|
||||
lda $fe ;load a random number from address $fe into register A
|
||||
|
||||
;AND: logical AND with accumulator. Apply logical AND with hex $03 to value in
|
||||
;register A. Hex 03 is binary 00000011, so only the two least significant bits
|
||||
;are kept, resulting in a value between 0 (bin 00000000) and 3 (bin 00000011).
|
||||
;Add 2 to the result, giving a random value between 2 and 5
|
||||
and #$03 ;mask out lowest 2 bits
|
||||
clc ;clear carry flag
|
||||
adc #2 ;add to register A, using carry bit for overflow.
|
||||
sta $01 ;store value of y coordinate from register A into address $01
|
||||
|
||||
rts ;return
|
||||
|
||||
|
||||
loop:
|
||||
;the main game loop
|
||||
jsr readKeys ;jump to subroutine readKeys
|
||||
jsr checkCollision ;jump to subroutine checkCollision
|
||||
jsr updateSnake ;jump to subroutine updateSnake
|
||||
jsr drawApple ;jump to subroutine drawApple
|
||||
jsr drawSnake ;jump to subroutine drawSnake
|
||||
jsr spinWheels ;jump to subroutine spinWheels
|
||||
jmp loop ;jump to loop (this is what makes it loop)
|
||||
|
||||
|
||||
readKeys:
|
||||
;for getting keypresses, the last address ($ff) in the zero page contains
|
||||
;the hex code of the last pressed key
|
||||
|
||||
lda $ff ;load the value of the latest keypress from address $ff into register A
|
||||
cmp #$77 ;compare value in register A to hex $77 (W)
|
||||
beq upKey ;Branch On Equal, to upKey
|
||||
cmp #$64 ;compare value in register A to hex $64 (D)
|
||||
beq rightKey ;Branch On Equal, to rightKey
|
||||
cmp #$73 ;compare value in register A to hex $73 (S)
|
||||
beq downKey ;Branch On Equal, to downKey
|
||||
cmp #$61 ;compare value in register A to hex $61 (A)
|
||||
beq leftKey ;Branch On Equal, to leftKey
|
||||
rts ;return
|
||||
|
||||
upKey:
|
||||
lda #4 ;load value 4 into register A, correspoding to the value for DOWN
|
||||
bit $02 ;AND with value at address $02 (the current direction),
|
||||
;setting the zero flag if the result of ANDing the two values
|
||||
;is 0. So comparing to 4 (bin 0100) only sets zero flag if
|
||||
;current direction is 4 (DOWN). So for an illegal move (current
|
||||
;direction is DOWN), the result of an AND would be a non zero value
|
||||
;so the zero flag would not be set. For a legal move the bit in the
|
||||
;new direction should not be the same as the one set for DOWN,
|
||||
;so the zero flag needs to be set
|
||||
bne illegalMove ;Branch If Not Equal: meaning the zero flag is not set.
|
||||
|
||||
lda #1 ;Ending up here means the move is legal, load the value 1 (UP) into
|
||||
;register A
|
||||
sta $02 ;Store the value of A (the new direction) into register A
|
||||
rts ;return
|
||||
|
||||
rightKey:
|
||||
lda #8 ;load value 8 into register A, corresponding to the value for LEFT
|
||||
bit $02 ;AND with current direction at address $02 and check if result
|
||||
;is zero
|
||||
bne illegalMove ;Branch If Not Equal: meaning the zero flag is not set.
|
||||
|
||||
lda #2 ;Ending up here means the move is legal, load the value 2 (RIGHT) into
|
||||
;register A
|
||||
sta $02 ;Store the value of A (the new direction) into register A
|
||||
rts ;return
|
||||
|
||||
downKey:
|
||||
lda #1 ;load value 1 into register A, correspoding to the value for UP
|
||||
bit $02 ;AND with current direction at address $02 and check if result
|
||||
;is zero
|
||||
bne illegalMove ;Branch If Not Equal: meaning the zero flag is not set.
|
||||
|
||||
lda #4 ;Ending up here means the move is legal, load the value 4 (DOWN) into
|
||||
;register A
|
||||
sta $02 ;Store the value of A (the new direction) into register A
|
||||
rts ;return
|
||||
|
||||
leftKey:
|
||||
lda #2 ;load value 1 into register A, correspoding to the value for RIGHT
|
||||
bit $02 ;AND with current direction at address $02 and check if result
|
||||
;is zero
|
||||
bne illegalMove ;Branch If Not Equal: meaning the zero flag is not set.
|
||||
|
||||
lda #8 ;Ending up here means the move is legal, load the value 8 (LEFT) into
|
||||
;register A
|
||||
sta $02 ;Store the value of A (the new direction) into register A
|
||||
rts ;return
|
||||
|
||||
illegalMove:
|
||||
;for an illegal move, just return, so the keypress is ignored
|
||||
rts ;return
|
||||
|
||||
|
||||
checkCollision:
|
||||
jsr checkAppleCollision ;jump to subroutine checkAppleCollision
|
||||
jsr checkSnakeCollision ;jump to subroutine checkSnakeCollision
|
||||
rts ;return
|
||||
|
||||
|
||||
checkAppleCollision:
|
||||
;check if the snake collided with the apple by comparing the least significant
|
||||
;and most significant byte of the position of the snake's head and the apple.
|
||||
lda $00 ;load value at address $00 (the least significant
|
||||
;byte of the apple's position) into register A
|
||||
cmp $10 ;compare to the value stored at address $10
|
||||
;(the least significant byte of the position of the snake's head)
|
||||
bne doneCheckingAppleCollision ;if different, branch to doneCheckingAppleCollision
|
||||
lda $01 ;load value of address $01 (the most significant byte
|
||||
;of the apple's position) into register A
|
||||
cmp $11 ;compare the value stored at address $11 (the most
|
||||
;significant byte of the position of the snake's head)
|
||||
bne doneCheckingAppleCollision ;if different, branch to doneCheckingAppleCollision
|
||||
|
||||
;Ending up here means the coordinates of the snake head are equal to that of
|
||||
;the apple: eat apple
|
||||
inc $03 ;increment the value held in memory $03 (snake length)
|
||||
inc $03 ;twice because we're adding two bytes for one segment
|
||||
|
||||
;create a new apple
|
||||
jsr generateApplePosition ;jump to subroutine generateApplePosition
|
||||
|
||||
doneCheckingAppleCollision:
|
||||
;the snake head was not on the apple. Don't do anything with the apple
|
||||
rts ;return
|
||||
|
||||
|
||||
checkSnakeCollision:
|
||||
ldx #2 ;Load the value 2 into the X register, so we start with the first segment
|
||||
|
||||
snakeCollisionLoop:
|
||||
lda $10,x ;load the value stored at address $10 (the least significant byte of
|
||||
;the location of the snake's head) plus the value of the x register
|
||||
;(2 in the first iteration) to get the least significant byte of the
|
||||
;position of the next snake segment
|
||||
cmp $10 ;compare to the value at address $10 (the least significant
|
||||
;byte of the position of the snake's head
|
||||
bne continueCollisionLoop ;if not equals, we haven't found a collision yet,
|
||||
;branch to continueCollisionLoop to continue the loop
|
||||
|
||||
maybeCollided:
|
||||
;ending up here means we found a segment of the snake's body that
|
||||
;has a least significant byte that's equal to that of the snake's head.
|
||||
lda $11,x ;load the value stored at address $11 (most significant byte of
|
||||
;the location of the snake's head) plus the value of the x register
|
||||
;(2 in the first iteration) to get the most significant byte
|
||||
;of the position of the next snake segment
|
||||
cmp $11 ;compare to the value at address $11 (the most significant
|
||||
;byte of the position of the snake head)
|
||||
beq didCollide ;both position bytes of the compared segment of the snake body
|
||||
;are equal to those of the head, so we have a collision of the
|
||||
;snake's head with its own body.
|
||||
|
||||
continueCollisionLoop:
|
||||
;increment the value in the x register twice because we use two bytes to store
|
||||
;the coordinates for snake head and body segments
|
||||
inx ;increment the value of the x register
|
||||
inx ;increment the value of the x register
|
||||
cpx $03 ;compare the value in the x register to the value stored at
|
||||
;address $03 (snake length).
|
||||
beq didntCollide ;if equals, we got to last section with no collision: branch
|
||||
;to didntCollide
|
||||
|
||||
;ending up here means we haven't checked all snake body segments yet
|
||||
jmp snakeCollisionLoop;jump to snakeCollisionLoop to continue the loop
|
||||
|
||||
didCollide:
|
||||
;there was a collision
|
||||
jmp gameOver ;jump to gameOver
|
||||
|
||||
didntCollide:
|
||||
;there was no collision, continue the game
|
||||
rts ;return
|
||||
|
||||
|
||||
updateSnake:
|
||||
;collision checks have been done, update the snake. Load the length of the snake
|
||||
;minus one into the A register
|
||||
ldx $03 ;load the value stored at address $03 (snake length) into register X
|
||||
dex ;decrement the value in the X register
|
||||
txa ;transfer the value stored in the X register into the A register. WHY?
|
||||
|
||||
updateloop:
|
||||
|
||||
;Example: the length of the snake is 4 bytes (two segments). In the lines above
|
||||
;the X register has been set to 3. The snake coordinates are now stored as follows:
|
||||
;$10,$11 : the snake head
|
||||
;$12,$13,$14,$15: the snake body segments (two bytes for each of the 2 segments)
|
||||
;
|
||||
;The loop shifts all coordinates of the snake two places further in memory,
|
||||
;calculating the offset of the origin from $10 and place it in memory offset to
|
||||
;$12, effectively shifting each of the snake's segments one place further:
|
||||
;
|
||||
;from: x===
|
||||
;to: ===
|
||||
lda $10,x ;load the value stored at address $10 + x into register A
|
||||
sta $12,x ;store the value of register A into address $12
|
||||
;plus the value of register X
|
||||
dex ;decrement X, and set negative flag if value becomes negative
|
||||
bpl updateloop ;branch to updateLoop if positive (negative flag not set)
|
||||
|
||||
;now determine where to move the head, based on the direction of the snake
|
||||
;lsr: Logical Shift Right. Shift all bits in register A one bit to the right
|
||||
;the bit that "falls off" is stored in the carry flag
|
||||
lda $02 ;load the value from address $02 (direction) into register A
|
||||
lsr ;shift to right
|
||||
bcs up ;if a 1 "fell off", we started with bin 0001, so the snakes needs to go up
|
||||
lsr ;shift to right
|
||||
bcs right ;if a 1 "fell off", we started with bin 0010, so the snakes needs to go right
|
||||
lsr ;shift to right
|
||||
bcs down ;if a 1 "fell off", we started with bin 0100, so the snakes needs to go down
|
||||
lsr ;shift to right
|
||||
bcs left ;if a 1 "fell off", we started with bin 1000, so the snakes needs to go left
|
||||
up:
|
||||
lda $10 ;put value stored at address $10 (the least significant byte, meaning the
|
||||
;position in a 8x32 strip) in register A
|
||||
sec ;set carry flag
|
||||
sbc #$20 ;Subtract with Carry: subtract hex $20 (dec 32) together with the NOT of the
|
||||
;carry bit from value in register A. If overflow occurs the carry bit is clear.
|
||||
;This moves the snake up one row in its strip and checks for overflow
|
||||
sta $10 ;store value of register A at address $10 (the least significant byte
|
||||
;of the head's position)
|
||||
bcc upup ;If the carry flag is clear, we had an overflow because of the subtraction,
|
||||
;so we need to move to the strip above the current one
|
||||
rts ;return
|
||||
upup:
|
||||
;An overflow occurred when subtracting 20 from the least significant byte
|
||||
dec $11 ;decrement the most significant byte of the snake's head's position to
|
||||
;move the snake's head to the next up 8x32 strip
|
||||
lda #$1 ;load hex value $1 (dec 1) into register A
|
||||
cmp $11 ;compare the value at address $11 (snake head's most significant
|
||||
;byte, determining which strip it's in). If it's 1, we're one strip too
|
||||
;(the first one has a most significant byte of $02), which means the snake
|
||||
;hit the top of the screen
|
||||
|
||||
beq collision ;branch if equal to collision
|
||||
rts ;return
|
||||
right:
|
||||
inc $10 ;increment the value at address $10 (snake head's least
|
||||
;significant byte, determining where in the 8x32 strip the head is
|
||||
;located) to move the head to the right
|
||||
lda #$1f ;load value hex $1f (dec 31) into register A
|
||||
bit $10 ;the value stored at address $10 (the snake head coordinate) is ANDed
|
||||
;with hex $1f (bin 11111), meaning all multiples of hex $20 (dec 32)
|
||||
;will be zero (because they all end with bit patterns ending in 5 zeros)
|
||||
;if it's zero, it means we hit the right of the screen
|
||||
beq collision ;branch to collision if zero flag is set
|
||||
rts ;return
|
||||
down:
|
||||
lda $10 ;put value from address $10 (the least significant byte, meaning the
|
||||
;position in a 8x32 strip) in register A
|
||||
clc ;clear carry flag
|
||||
adc #$20 ;add hex $20 (dec 32) to the value in register A and set the carry flag
|
||||
;if overflow occurs
|
||||
sta $10 ;store the result at address $10
|
||||
bcs downdown ;if the carry flag is set, an overflow occurred when adding hex $20 to the
|
||||
;least significant byte of the location of the snake's head, so we need to move
|
||||
;the next 8x3 strip
|
||||
rts ;return
|
||||
downdown:
|
||||
inc $11 ;increment the value in location hex $11, holding the most significatnt byte
|
||||
;of the location of the snake's head.
|
||||
lda #$6 ;load the value hex $6 into the A register
|
||||
cmp $11 ;if the most significant byte of the head's location is equals to 6, we're
|
||||
;one strip to far down (the last one was hex $05)
|
||||
beq collision ;if equals to 6, the snake collided with the bottom of the screen
|
||||
rts ;return
|
||||
|
||||
left:
|
||||
;A collision with the left side of the screen happens if the head wraps around to
|
||||
;the previous row, on the right most side of the screen, where, because the screen
|
||||
;is 32 wide, the right most positions always have a least significant byte that ends
|
||||
;in 11111 in binary form (hex $1f). ANDing with hex $1f in this column will always
|
||||
;return hex $1f, so comparing the result of the AND with hex $1f will determine if
|
||||
;the snake collided with the left side of the screen.
|
||||
|
||||
dec $10 ;subtract one from the value held in memory position $10 (least significant
|
||||
;byte of the snake head position) to make it move left.
|
||||
lda $10 ;load value held in memory position $10 (least significant byte of the
|
||||
;snake head position) into register A
|
||||
and #$1f ;AND the value hex $1f (bin 11111) with the value in register A
|
||||
cmp #$1f ;compare the ANDed value above with bin 11111.
|
||||
beq collision ;branch to collision if equals
|
||||
rts ;return
|
||||
collision:
|
||||
jmp gameOver ;jump to gameOver
|
||||
|
||||
|
||||
drawApple:
|
||||
ldy #0 ;load the value 0 into the Y register
|
||||
lda $fe ;load the value stored at address $fe (the random number generator)
|
||||
;into register A
|
||||
sta ($00),y ;dereference to the address stored at address $00 and $01
|
||||
;(the address of the apple on the screen) and set the value to
|
||||
;the value of register A and add the value of Y (0) to it. This results
|
||||
;in the apple getting a random color
|
||||
rts ;return
|
||||
|
||||
|
||||
drawSnake:
|
||||
ldx #0 ;set the value of the X register to 0
|
||||
lda #1 ;set the value of the A register to 1
|
||||
sta ($10,x) ;dereference to the memory address that's stored at address
|
||||
;$10 (the two bytes for the location of the head of the snake) and
|
||||
;set its value to the one stored in register A
|
||||
ldx $03 ;set the value of the x register to the value stored in memory at
|
||||
;location $03 (the length of the snake)
|
||||
lda #0 ;set the value of the a register to 0
|
||||
sta ($10,x) ;dereference to the memory address that's stored at address
|
||||
;$10, add the length of the snake to it, and store the value of
|
||||
;register A (0) in the resulting address. This draws a black pixel on the
|
||||
;tail. Because the snake is moving, the head "draws" on the screen in
|
||||
;white as it moves, and the tail works as an eraser, erasing the white trail
|
||||
;using black pixels
|
||||
rts ;return
|
||||
|
||||
|
||||
spinWheels:
|
||||
;slow the game down by wasting cycles
|
||||
ldx #0 ;load zero in the X register
|
||||
spinloop:
|
||||
nop ;no operation, just skip a cycle
|
||||
nop ;no operation, just skip a cycle
|
||||
dex ;subtract one from the value stored in register x
|
||||
bne spinloop ;if the zero flag is clear, loop. The first dex above wrapped the
|
||||
;value of x to hex $ff, so the next zero value is 255 (hex $ff)
|
||||
;loops later.
|
||||
rts ;return
|
||||
|
||||
|
||||
gameOver: ;game over is literally the end of the program
|
274
bins/snake_fast.asm
Normal file
274
bins/snake_fast.asm
Normal file
@ -0,0 +1,274 @@
|
||||
; ___ _ __ ___ __ ___
|
||||
; / __|_ _ __ _| |_____ / /| __|/ \_ )
|
||||
; \__ \ ' \/ _` | / / -_) _ \__ \ () / /
|
||||
; |___/_||_\__,_|_\_\___\___/___/\__/___|
|
||||
|
||||
; Change direction: W A S D
|
||||
|
||||
define appleL $00 ; screen location of apple, low byte
|
||||
define appleH $01 ; screen location of apple, high byte
|
||||
define snakeHeadL $10 ; screen location of snake head, low byte
|
||||
define snakeHeadH $11 ; screen location of snake head, high byte
|
||||
define snakeBodyStart $12 ; start of snake body byte pairs
|
||||
define snakeDirection $02 ; direction (possible values are below)
|
||||
define snakeLength $03 ; snake length, in bytes
|
||||
|
||||
; Directions (each using a separate bit)
|
||||
define movingUp 1
|
||||
define movingRight 2
|
||||
define movingDown 4
|
||||
define movingLeft 8
|
||||
|
||||
; ASCII values of keys controlling the snake
|
||||
define ASCII_w $57
|
||||
define ASCII_a $41
|
||||
define ASCII_s $53
|
||||
define ASCII_d $44
|
||||
|
||||
; System variables
|
||||
define sysRandom $fe
|
||||
define sysLastKey $ff
|
||||
|
||||
|
||||
jsr init
|
||||
jsr loop
|
||||
|
||||
init:
|
||||
jsr initSnake
|
||||
jsr generateApplePosition
|
||||
rts
|
||||
|
||||
|
||||
initSnake:
|
||||
lda #movingRight ;start direction
|
||||
sta snakeDirection
|
||||
|
||||
lda #4 ;start length (2 segments)
|
||||
sta snakeLength
|
||||
|
||||
lda #$11
|
||||
sta snakeHeadL
|
||||
|
||||
lda #$10
|
||||
sta snakeBodyStart
|
||||
|
||||
lda #$0f
|
||||
sta $14 ; body segment 1
|
||||
|
||||
lda #$04
|
||||
sta snakeHeadH
|
||||
sta $13 ; body segment 1
|
||||
sta $15 ; body segment 2
|
||||
rts
|
||||
|
||||
|
||||
generateApplePosition:
|
||||
;load a new random byte into $00
|
||||
lda sysRandom
|
||||
sta appleL
|
||||
|
||||
;load a new random number from 2 to 5 into $01
|
||||
lda sysRandom
|
||||
and #$03 ;mask out lowest 2 bits
|
||||
clc
|
||||
adc #2
|
||||
sta appleH
|
||||
|
||||
rts
|
||||
|
||||
|
||||
loop:
|
||||
jsr readKeys
|
||||
jsr checkCollision
|
||||
jsr updateSnake
|
||||
jsr drawApple
|
||||
jsr drawSnake
|
||||
jsr spinWheels
|
||||
jmp loop
|
||||
|
||||
|
||||
readKeys:
|
||||
lda sysLastKey
|
||||
cmp #ASCII_w
|
||||
beq upKey
|
||||
cmp #ASCII_d
|
||||
beq rightKey
|
||||
cmp #ASCII_s
|
||||
beq downKey
|
||||
cmp #ASCII_a
|
||||
beq leftKey
|
||||
rts
|
||||
upKey:
|
||||
lda #movingDown
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingUp
|
||||
sta snakeDirection
|
||||
rts
|
||||
rightKey:
|
||||
lda #movingLeft
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingRight
|
||||
sta snakeDirection
|
||||
rts
|
||||
downKey:
|
||||
lda #movingUp
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingDown
|
||||
sta snakeDirection
|
||||
rts
|
||||
leftKey:
|
||||
lda #movingRight
|
||||
bit snakeDirection
|
||||
bne illegalMove
|
||||
|
||||
lda #movingLeft
|
||||
sta snakeDirection
|
||||
rts
|
||||
illegalMove:
|
||||
rts
|
||||
|
||||
|
||||
checkCollision:
|
||||
jsr checkAppleCollision
|
||||
jsr checkSnakeCollision
|
||||
rts
|
||||
|
||||
|
||||
checkAppleCollision:
|
||||
lda appleL
|
||||
cmp snakeHeadL
|
||||
bne doneCheckingAppleCollision
|
||||
lda appleH
|
||||
cmp snakeHeadH
|
||||
bne doneCheckingAppleCollision
|
||||
|
||||
;eat apple
|
||||
inc snakeLength
|
||||
inc snakeLength ;increase length
|
||||
jsr generateApplePosition
|
||||
doneCheckingAppleCollision:
|
||||
rts
|
||||
|
||||
|
||||
checkSnakeCollision:
|
||||
ldx #2 ;start with second segment
|
||||
snakeCollisionLoop:
|
||||
lda snakeHeadL,x
|
||||
cmp snakeHeadL
|
||||
bne continueCollisionLoop
|
||||
|
||||
maybeCollided:
|
||||
lda snakeHeadH,x
|
||||
cmp snakeHeadH
|
||||
beq didCollide
|
||||
|
||||
continueCollisionLoop:
|
||||
inx
|
||||
inx
|
||||
cpx snakeLength ;got to last section with no collision
|
||||
beq didntCollide
|
||||
jmp snakeCollisionLoop
|
||||
|
||||
didCollide:
|
||||
jmp gameOver
|
||||
didntCollide:
|
||||
rts
|
||||
|
||||
|
||||
updateSnake:
|
||||
ldx snakeLength
|
||||
dex
|
||||
txa
|
||||
updateloop:
|
||||
lda snakeHeadL,x
|
||||
sta snakeBodyStart,x
|
||||
dex
|
||||
bpl updateloop
|
||||
|
||||
lda snakeDirection
|
||||
lsr
|
||||
bcs up
|
||||
lsr
|
||||
bcs right
|
||||
lsr
|
||||
bcs down
|
||||
lsr
|
||||
bcs left
|
||||
up:
|
||||
lda snakeHeadL
|
||||
sec
|
||||
sbc #$20
|
||||
sta snakeHeadL
|
||||
bcc upup
|
||||
rts
|
||||
upup:
|
||||
dec snakeHeadH
|
||||
lda #$1
|
||||
cmp snakeHeadH
|
||||
beq collision
|
||||
rts
|
||||
right:
|
||||
inc snakeHeadL
|
||||
lda #$1f
|
||||
bit snakeHeadL
|
||||
beq collision
|
||||
rts
|
||||
down:
|
||||
lda snakeHeadL
|
||||
clc
|
||||
adc #$20
|
||||
sta snakeHeadL
|
||||
bcs downdown
|
||||
rts
|
||||
downdown:
|
||||
inc snakeHeadH
|
||||
lda #$6
|
||||
cmp snakeHeadH
|
||||
beq collision
|
||||
rts
|
||||
left:
|
||||
dec snakeHeadL
|
||||
lda snakeHeadL
|
||||
and #$1f
|
||||
cmp #$1f
|
||||
beq collision
|
||||
rts
|
||||
collision:
|
||||
jmp gameOver
|
||||
|
||||
|
||||
drawApple:
|
||||
ldy #0
|
||||
lda sysRandom
|
||||
sta (appleL),y
|
||||
rts
|
||||
|
||||
|
||||
drawSnake:
|
||||
ldx snakeLength
|
||||
lda #0
|
||||
sta (snakeHeadL,x) ; erase end of tail
|
||||
|
||||
ldx #0
|
||||
lda #1
|
||||
sta (snakeHeadL,x) ; paint head
|
||||
rts
|
||||
|
||||
|
||||
spinWheels:
|
||||
ldx #1
|
||||
spinloop:
|
||||
nop
|
||||
nop
|
||||
dex
|
||||
bne spinloop
|
||||
rts
|
||||
|
||||
|
||||
gameOver:
|
BIN
bins/snake_fast.bin
Normal file
BIN
bins/snake_fast.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user