Compare commits

...

17 Commits

Author SHA1 Message Date
6054d97cf6 binaries for version v1.2 2021-11-08 22:21:25 +01:00
9c902abb59 intro/demo: show PETSCII brand name + forbid intro skip 2021-11-08 19:38:41 +01:00
a8319e9fb7 refactoring: macro for memset, memcpy, mov_word_mem 2021-11-07 22:52:31 +01:00
6e0d335b83 polishing 2021-11-07 21:09:27 +01:00
157c8598e6 doc: custom semi-graphic chars 2021-11-07 20:58:02 +01:00
db8707bebf refactoring: reorganize syntax sugar for segments handling 2021-11-07 20:37:44 +01:00
f67017c9a6 makefile: remove unused variable 2021-11-07 20:37:44 +01:00
85ac2cf971 refactoring: wip: move code segments 2021-11-07 20:37:44 +01:00
51477cff9d some code documentation + memset macro 2021-11-07 20:37:34 +01:00
b19754f3d5 "snake" movement is more fluid
but not perfect, yet
2021-06-01 21:53:34 +02:00
61515025a5 stable bounce 2021-04-15 14:33:29 +02:00
d13e88b0fd moustache notation 2021-04-14 11:24:36 +02:00
493d69f669 magic moustaches fixed 2021-04-14 09:50:46 +02:00
a41ae70993 proper intro 2021-04-14 00:30:42 +02:00
05ed319d93 new demo/intro draft 2021-04-13 23:19:47 +02:00
2c4130899c updated memory map with new sid 2021-04-12 23:31:21 +02:00
c8199e7144 updated sid tune
new sid tune is bigger than 4k, so charset had to be moved
now (part of) first half of the charset actually is used by the sid
and ignored by the VIC; chars had to be redefined
2021-04-12 23:28:34 +02:00
29 changed files with 1780 additions and 2443 deletions

View File

@ -1,14 +1,14 @@
.POSIX: .POSIX:
ASM=$(wildcard src/*.asm) ASM=$(wildcard src/*.asm)
RES=res.bin/amour.sid res.bin/levels.bin res.bin/unlzg.bin RES=res.bin/amour2.sid res.bin/levels.bin res.bin/unlzg.bin
.PHONY: debug env clean all .PHONY: debug env clean all
all: bin/snake6502.bin bin/snake6502.d64 all: bin/snake6502.bin bin/snake6502.d64
bin/snake6502.bin: bin/snake.pack.lz bin/snake6502.bin: bin/snake.pack.lz
dasm src/cart.asm -Isrc/ -DVERBOSE=$(VERBOSE) -f3 -sbuild/cart.symbols.txt -obin/snake6502.bin dasm src/cart.asm -Isrc/ -f3 -T1 -sbuild/cart.symbols.txt -obin/snake6502.bin
bin/snake6502.d64: bin/loader.prg bin/snake6502.d64: bin/loader.prg
c1541 -format "snake6502,01" d64 bin/snake6502.d64 c1541 -format "snake6502,01" d64 bin/snake6502.d64
@ -16,13 +16,13 @@ bin/snake6502.d64: bin/loader.prg
c1541 -attach bin/snake6502.d64 -write bin/snake.pack.lz.prg packlz c1541 -attach bin/snake6502.d64 -write bin/snake.pack.lz.prg packlz
bin/loader.prg: bin/snake.pack.lz.prg bin/loader.prg: bin/snake.pack.lz.prg
dasm src/loader.asm -Isrc/ -DVERBOSE=$(VERBOSE) -f1 -sbuild/loader.sybols.txt -obin/loader.prg dasm src/loader.asm -Isrc/ -f1 -sbuild/loader.sybols.txt -obin/loader.prg
bin/snake.prg: bin/snake.pack bin/snake.prg: bin/snake.pack
dasm src/prg.asm -Isrc/ -DVERBOSE=$(VERBOSE) -f1 -sbuild/prg.symbols.txt -obin/snake.prg dasm src/prg.asm -Isrc/ -f1 -T1 -sbuild/prg.symbols.txt -obin/snake.prg
bin/snake.pack: env $(ASM) $(RES) bin/explodefont bin/snake.pack: env $(ASM) $(RES) bin/explodefont
dasm src/main.asm -Isrc/ -DSYSTEM=64 -DDEBUG=$(DEBUG) -DVERBOSE=$(VERBOSE) -DCARTRIDGE=$(CARTRIDGE) -f3 -sbuild/pack.symbols.txt -obin/snake.pack dasm src/main.asm -Isrc/ -DSYSTEM=64 -DDEBUG=$(DEBUG) -f3 -T1 -sbuild/pack.symbols.txt -obin/snake.pack
bin/snake.pack.lz: bin/snake.pack liblzg/src/tools/lzg bin/snake.pack.lz: bin/snake.pack liblzg/src/tools/lzg
liblzg/src/tools/lzg bin/snake.pack > bin/snake.pack.lz liblzg/src/tools/lzg bin/snake.pack > bin/snake.pack.lz
@ -43,8 +43,8 @@ env:
bin/explodefont: util/explodefont.cpp bin/explodefont: util/explodefont.cpp
g++ -o bin/explodefont util/explodefont.cpp g++ -o bin/explodefont util/explodefont.cpp
res.bin/amour.sid: res.bin/amour2.sid:
cp res.org/amour.sid res.bin/amour.sid cp res.org/amour2.sid res.bin/amour2.sid
res.bin/levels.bin: bin/level res.org/levels.txt res.bin/levels.bin: bin/level res.org/levels.txt
bin/level < res.org/levels.txt > res.bin/levels.bin bin/level < res.org/levels.txt > res.bin/levels.bin

View File

@ -1,5 +1,6 @@
# snake6502 # snake6502
![Intro screenshot](scrot/intro.png)
![Gameplay screenshot](scrot/gameplay.png) ![Gameplay screenshot](scrot/gameplay.png)
*snake6502* is a snake-like game clone for Commodore home computers, written for fun because «I always wanted to code something for a computer of my retrocomputers collection actually, this is the main reason I collect them: to write programs». *snake6502* is a snake-like game clone for Commodore home computers, written for fun because «I always wanted to code something for a computer of my retrocomputers collection actually, this is the main reason I collect them: to write programs».
@ -26,8 +27,6 @@ You can also define the following environment variables:
```$ DEBUG=1 make``` build with debugging artifacts ```$ DEBUG=1 make``` build with debugging artifacts
```$ VERBOSE=1 make``` output useful info during compilation
## Tape ## Tape
Copy ```loader.prg``` and ```packlz``` from disk to tape. Copy ```loader.prg``` and ```packlz``` from disk to tape.
On a physical machine, you can use [disk2tape](https://git.giomba.it/giomba/cbmutil). On a physical machine, you can use [disk2tape](https://git.giomba.it/giomba/cbmutil).
@ -47,30 +46,55 @@ Address | PRG | Description
```$0000 - $0001``` | no | hardware ```$0000 - $0001``` | no | hardware
```$0002 - $00FF``` | no | zero page pointers ```$0002 - $00FF``` | no | zero page pointers
```$0100 - $01FF``` | no | stack page ```$0100 - $01FF``` | no | stack page
```$0200 - $07FF``` | no | *free ram* ```$0200 - $03FF``` | no | operating system variables
```$1000 - $1FFF``` | yes | SID tune ```$0400 - $07FF``` | no | video memory
```$2000 - $27FF``` | yes | custom char ```$1000 - $1FFF``` | yes | SID tune, may overlap charset
```$2000 - $23FF``` | yes | custom char, unused, allow SID overlap
```$2400 - $27FF``` | yes | custom char (actual 0x80+)
```$2800 - $xxxx``` | yes | Program segment (only needed part used) ```$2800 - $xxxx``` | yes | Program segment (only needed part used)
```$xxxx - $CCFF``` | no | *free ram* ```$xxxx - $CCFF``` | no | *free ram*
```$CD00 - $CDFF``` | no | data segment (not-initialized vars) ```$CD00 - $CFFF``` | no | data segment (not-initialized vars)
```$CE00 - $CEFF``` | no | list X
```$CF00 - $CFFF``` | no | list Y
```$D000 - $DFFF``` | no | I/O ```$D000 - $DFFF``` | no | I/O
```$E000 - $FFFF``` | no | Kernal ```$E000 - $FFFF``` | no | Kernal
### Compression ### Compression
```snake.pack``` is compressed into ```snake.pack.lz``` using [liblzg](https://github.com/mbitsnbites/liblzg), to save space in order to fit the game in a *PROM. ```snake.pack``` is compressed into ```snake.pack.lz``` using [liblzg](https://github.com/mbitsnbites/liblzg), to save space, mainly in order to fit the game in a *PROM.
Decompression occurs with one of the following loaders.
### Decompression ### Loader
#### Cartridge
```cart.asm``` is located at ```$8000``` (standard org address for C64 cartridges), and contains the decompression routine and the ```snake.pack.lz```. It decompresses ```snake.pack.lz``` back to ```$1000```, and jumps to its entry point at ```$2800```. ```cart.asm``` is located at ```$8000``` (standard org address for C64 cartridges), and contains the decompression routine and the ```snake.pack.lz```. It decompresses ```snake.pack.lz``` back to ```$1000```, and jumps to its entry point at ```$2800```.
#### Disk
```loader.asm``` loads at ```$801```, like any other BASIC automatic runner, and contains the decompression routine.
```snake.pack.lz``` is loaded at ```$8000``` from disk drive, then decompressed back to ```$1000```, and finally the loader jumps to the program entry point at ```$2800```.
### Miscellanea ### Miscellanea
#### Custom charset #### Custom charset
Index | Description Index | Description
----------------|------------- ----------------|-------------
```$00 - $1F``` | A-Z (space first) ```$00 - $7F``` | unused (space for SID)
```$20 - $3F``` | A-Z, reversed (space first) ```$80 - $9F``` | A-Z (space first)
```$40 - $4F``` | hex digits ```$A0 - $BF``` | A-Z, reversed (space first)
```$50 - $5F``` | hex digits, reversed ```$C0 - $CF``` | hex digits
```$60 - ``` | game tiles ```$D0 - $DF``` | hex digits, reversed
```$E0 - $EF``` | game tiles
```$F0 - $FF``` | semigraphic tiles
##### Semigrahic Tiles
Char | Output
----------|--------
```$F0``` | ```◜```
```$F1``` | ```◝```
```$F2``` | ```◟```
```$F3``` | ```◞```
```$F4``` | ```-```
```$F5``` | ```|```
```$F6``` | ```◢```
```$F7``` | ```◣```
```$F8``` | ```◥```
```$F9``` | ```◤```
```$FA``` | ```┴```
```$FB``` | ```┬```
```$FC``` | ```┤```
```$FD``` | ```├```

BIN
dist/snake6502.bin vendored

Binary file not shown.

BIN
dist/snake6502.d64 vendored

Binary file not shown.

Binary file not shown.

BIN
res.org/amour2.sid Normal file

Binary file not shown.

BIN
scrot/intro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,12 +1,13 @@
processor 6502 processor 6502
; SEGMENTS
SEG.U zeropageSegment SEG.U zeropageSegment
org $02 org $02
INCLUDE "zeropage.asm" SEG loaderSegment
SEG cartridgeSegment
org $8000 org $8000
; LOADER
SEG loaderSegment
cartridge SUBROUTINE cartridge SUBROUTINE
WORD .coldstart WORD .coldstart
WORD .warmstart WORD .warmstart
@ -47,12 +48,9 @@ cartridge SUBROUTINE
; decompression util ; decompression util
INCLUDE "lzgmini.asm" INCLUDE "lzgmini.asm"
#if VERBOSE = 1
ECHO "8k CARTRIDGE SIZE:",(. - $8000),"=",[(. - $8000)d] ECHO "8k CARTRIDGE SIZE:",(. - $8000),"=",[(. - $8000)d]
ECHO "SPACE LEFT:",($9fff - .),"=",[($9fff - .)d] ECHO "SPACE LEFT:",($9fff - .),"=",[($9fff - .)d]
#endif
; force filler for the *PROM ; force filler for the *PROM
. = $9fff . = $9fff
BYTE #$ff BYTE #$ff

View File

@ -1,9 +1,4 @@
#if VERBOSE = 1 SEG.U dataSegment
LASTINIT SET .
#endif
; Data section - Not initialized variables ($CD00 - $CDFF)
; ----------------------------------------------------------------------
; Number of interrupt ; Number of interrupt
; Used as counter to be decremented to do some things less frequently ; Used as counter to be decremented to do some things less frequently
irqn: irqn:
@ -54,6 +49,22 @@ delayStatus:
score: score:
WORD WORD
#if VERBOSE = 1 ; vertical scroll intro
ECHO "data.asm @ ",LASTINIT,"len:",(. - LASTINIT) introYscroll:
#endif BYTE
; interrupt raster line to draw moustache
moustacheLine:
BYTE
; horizontal intro scroll
XScrollOffset:
BYTE
XScrollDirection:
BYTE
XCharOffset:
BYTE
; Lists for snake head and tail
listX DS 256
listY DS 256

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
statusPlay: ; do Game statusPlay: ; do Game
; Check counter ; Check counter
ldx irqn ldx irqn
@ -335,9 +332,4 @@ checkEndWallHit:
sta (tileMem),y sta (tileMem),y
skipPauseTests: skipPauseTests:
rts rts
#if VERBOSE = 1
ECHO "game.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,7 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
; Game is over ; Game is over
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
gameover: gameover:
@ -24,7 +21,3 @@ gameover:
lda #ST_DELAY lda #ST_DELAY
sta status sta status
rts rts
#if VERBOSE = 1
ECHO "gameover.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,7 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
; Initialized variables ; Initialized variables
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
@ -25,11 +22,20 @@ delay:
; Status of the game (costants pre-processor defined, sort of enum) ; Status of the game (costants pre-processor defined, sort of enum)
ST_INTRO0 = 0 ST_INTRO0 = 0
ST_INTRO1 = 1 ST_INTRO1 = 1
ST_LEVEL_TITLE = 2 ST_INTRO2 = 2
ST_LEVEL_LOAD = 3 ST_INTRO3 = 3
ST_PLAY = 4 ST_INTRO4 = 4
ST_DELAY = 5 ST_INTRO5 = 5
ST_END = 6 ST_INTRO6 = 6
ST_INTRO7 = 7
ST_INTRO8 = 8
ST_MENURESET = 64
ST_MENU = 65
ST_LEVEL_TITLE = 128
ST_LEVEL_LOAD = 129
ST_PLAY = 130
ST_DELAY = 131
ST_END = 132
ST_PAUSE = 255 ST_PAUSE = 255
; Screen features ; Screen features
@ -38,10 +44,10 @@ SCREEN_H = 24
; Tiles ; Tiles
; ----- ; -----
EMPTY_TILE = $60 EMPTY_TILE = $e0
SNAKE_TILE = $61 SNAKE_TILE = $e1
FOOD_TILE = $62 FOOD_TILE = $e2
WALL_TILE = $63 WALL_TILE = $e3
; Tiles colors ; Tiles colors
; Note: these colors will be picked by the level select routine ; Note: these colors will be picked by the level select routine
@ -62,16 +68,6 @@ WALL_COLOR:
gameoverString: gameoverString:
BYTE "GAME IS OVER" BYTE "GAME IS OVER"
BYTE #0 BYTE #0
intro0string:
#if SYSTEM = 64
BYTE " SNAKE BY GIOMBA "
#else
BYTE " SNAKE16 BY GIOMBA "
#endif
BYTE #0
intro1string:
BYTE " PRESS SPACE TO PLAY "
BYTE #0
intro2string: intro2string:
BYTE "RETROFFICINA.GLGPROGRAMS.IT" BYTE "RETROFFICINA.GLGPROGRAMS.IT"
BYTE #0 BYTE #0
@ -79,26 +75,38 @@ intro3string:
#if DEBUG = 1 #if DEBUG = 1
BYTE "DBG RELS" BYTE "DBG RELS"
#else #else
BYTE "(C) 2018" BYTE "2017 (C) 2021"
#endif #endif
BYTE #0 BYTE #0
levelIntroString: levelIntroString:
BYTE "NEXT LEVEL" BYTE "NEXT LEVEL"
BYTE #0 BYTE #0
colorshade: ; a gradient of dark-bright-dark (40 columns)
HEX 0b 0b 0b 0b 0b 0c 0c 0c 0c 0c 05 05 05 0d 0d 0d 0d 07 07 07 07 07 07 0d 0d 0d 0d 05 05 05 0c 0c 0c 0c 0c 0b 0b 0b 0b 0b
scoreString: scoreString:
BYTE "SCORE PART" BYTE "SCORE PART"
BYTE #0 BYTE #0
noMoreLevelsString: noMoreLevelsString:
BYTE "NO MORE LEVELS" BYTE "NO MORE LEVELS"
BYTE #0 BYTE #0
introStringA1:
BYTE "RETROFFICINA"
BYTE #$0
introStringA2:
BYTE "AND"
BYTE #$0
introStringA3:
BYTE "GIOMBA"
BYTE #$0
introStringA4:
BYTE "PRESENT"
BYTE #$0
introStringA5:
BYTE "A COMMODORE 64"
BYTE #$0
introStringA6:
BYTE "VIDEOGAME"
BYTE #$0
; Levels ; Levels
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
levelsList: levelsList:
INCBIN "../res.bin/levels.bin" INCBIN "../res.bin/levels.bin"
#if VERBOSE = 1
ECHO "initdata.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,86 +1,656 @@
#if VERBOSE = 1 SEG zeropageSegment
LASTINIT SET . introDestPtr WORD
#endif
; Currently statusIntro0 is the same as statusIntro1 SEG programSegment
; statusIntro1 has just been reserved for future use introreset SUBROUTINE
statusIntro0: jsr multicolorOff
statusIntro1:
; Decrement interrupt divider for the intro
ldx introCounter
dex
stx introCounter
cpx #0
beq status1do ; if divider is 0, then do status1do ...
rts ; ... else just do nothing and return
status1do:
; Reset introCounter
ldx #5
stx introCounter
; I want to print strings at different columns to make them jsr clearScreen
; bounce across the screen, so take last introX and add introXinc,
; then print string at that point. If introX is too far right, then
; set introXinc as #$ff (equals -1) so next time introX will be
; decremented by 1. And then, if introX is too far left, then
; set introXinc as #$01 so next time will be moved to right again.
lda introX
clc
adc introXinc ; this is #$01 or #$0ff, so actually it is +1 or -1
sta introX
cmp #19 ; am I too far right?
beq status1setSX ; if yes, set SX (left)
cmp #0 ; am I too far left?
beq status1setDX ; if yes, set DX (right)
jmp status1okset ; else do nothing (aka, next time re-use current
; increment value)
status1setDX:
lda #$01 ; set introXinc as +1
sta introXinc
jmp status1okset
status1setSX:
lda #$ff ; set introXinc as -1
sta introXinc
jmp status1okset
status1okset: ; Set screen colors
; Print "SNAKE BY GIOMBA" (see above for pointer details) lda #0
lda #<intro0string sta $d020 ; overscan
sta srcStringPointer sta $d021 ; center
lda #>intro0string
sta srcStringPointer + 1
; $0428 is 2nd line (previously filled with color shades by reset routine)
lda #$28
clc
adc introX ; just add X, to make it look like it has moved
sta dstScreenPointer
lda #$04
sta dstScreenPointer + 1
jsr printString
; Print "PRESS SPACE TO PLAY" lda #14
lda #<intro1string sta introYscroll
sta srcStringPointer
lda #>intro1string ; for "GLGPROGRAMS" at the beginning
sta srcStringPointer + 1 ldx #$78
; $0478 is 4th line (previously filled with color shades by reset routine) stx introDestPtr
; add #19, then sub introX will make it move to other way of 2nd line ldy #$04
lda #$78 sty introDestPtr + 1
clc
adc #19 ; add #19 ; GLGPROGRAMS color
sec ldy #$00
sbc introX ; sub introX lda #$02
sta dstScreenPointer .colorLoop:
lda #$04 sta $d800,y
sta dstScreenPointer + 1 sta $d900,y
jsr printString sta $da00,y
sta $db00,y
dey
bne .colorLoop
; first raster interrupt line, for moustaches
lda #68+18
sta moustacheLine
; Some considerations on speed:
; yes, maybe I should have put the string chars once in screen text memory
; and then move it left and right. Should re-think about this.
; For now, just return.
rts rts
#if VERBOSE = 1 statusIntro0 SUBROUTINE
ECHO "intro1.asm @ ",LASTINIT,"len:",(. - LASTINIT) ; arrives raster interrupt, move moustache one line below
#endif inc moustacheLine
lda $d011 ; load current vertical offset from VIC-II
and #$07
cmp #$07
beq .nextline ; if 7, then it is next text line
inc $d011 ; else setup moustache interrupt to trigger next raster line...
jsr setupMoustacheInterrupt
rts ; ...and return: my job here is done
.nextline:
lda $d011 ; reset raster offset to 0...
and #$f8
sta $d011
MOV_WORD_MEM dstPointer, introDestPtr
MEMSET "D", #$80, #40
clc ; ... move introDestPtr to next text line ...
lda introDestPtr
adc #40
sta introDestPtr
lda introDestPtr + 1
adc #0
sta introDestPtr + 1
MOV_WORD_MEM dstPointer, introDestPtr
MEMCPY "D", #GLGProgramsText, #200 ; ... and copy "GLG Programs" text to next text line
dec introYscroll ; remember that we are one line below
beq .next ; if we reached the end of the vertical scroll, advance status
jsr setupMoustacheInterrupt ; else just continue with the moustache
rts
.next:
lda #ST_INTRO1
sta status
rts
setupMoustacheInterrupt SUBROUTINE
; Store in $314 address of our custom interrupt handler
ldx #<.moustacheInterruptH
ldy #>.moustacheInterruptH
stx $314
sty $315
; Set raster beam to trigger interrupt at row
lda moustacheLine
sta $d012
rts
.moustacheInterruptH:
; "higher" moustache interrupt (on the right of the screen)
; +36
dec $d019 ; +42, EOI
lda #$02 ; +44, color
sta $d020 ; +48, color
nop ; +50, timing
nop ; +52, timing
nop ; +54, timing
bit $02 ; +57, timing
lda #$00 ; +59, color
sta $d020 ; +63, color
; second line, +0
inc $0800 ; + 6, timing
inc $0800 ; +12, timing
inc $0800 ; +18, timing
inc $0800 ; +24, timing
inc $0800 ; +30, timing
inc $0800 ; +36, timing
inc $0800 ; +42, timing
lda #$02 ; +44, color
sta $d020 ; +48, color
inc $0800 ; +54, timing
bit $02 ; +57, timing
lda #$00 ; +59, color
sta $d020 ; +63, color
; set raster beam low
ldx #<.moustacheInterruptL
ldy #>.moustacheInterruptL
stx $314
sty $315
clc
lda moustacheLine
adc #23 ; "lower" moustache is 23 raster lines below higher one
sta $d012
jmp $ea31
.moustacheInterruptL:
; "lower" moustache interrupt (on the left of the screen)
; +36
dec $d019 ; +42, EOI
inc $0800 ; +48, timing
inc $0800 ; +54, timing
lda #$02 ; +56, color
bit $0800 ; +60, timing
bit $02 ; +63, timing
; newline
sta $d020 ; + 4, color
lda #$00 ; + 6, timing
inc $0800 ; +12, timing
inc $0800 ; +18, timing
nop ; +20, timing
sta $d020 ; +24, color
lda #$02 ; +26, color
bit $0800 ; +30, timing
inc $0800 ; +36, timing
inc $0800 ; +42, timing
inc $0800 ; +48, timing
inc $0800 ; +54, timing
inc $0800 ; +60, timing
bit $02 ; +63, timing
; newline
sta $d020 ; + 4, color
lda #$00 ; + 6, color
inc $0800 ; +12, timing
inc $0800 ; +18, timing
sta $d020 ; +22, color
ldx #<irq ; restore main raster interrupt handler
ldy #>irq
stx $314
sty $315
lda #$00
sta $d012
jmp $ea31
GLGProgramsText: ; fancy PETSCII-looking brand name
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$f0,#$f4,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f1,#$80,#$80,#$80,#$f0,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$f5,#$f5,#$80,#$f5,#$80,#$f5,#$80,#$fd,#$f4,#$f3,#$f0,#$f0,#$f1,#$f0,#$f1,#$f0,#$f0,#$fc,#$f0,#$fb,#$f1,#$f2,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f2,#$f4,#$fc,#$f2,#$f4,#$f2,#$f4,#$fc,#$80,#$f5,#$80,#$80,#$f5,#$f2,#$f3,#$f2,#$fc,#$f5,#$f2,#$f3,#$f5,#$f5,#$f5,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$fa,#$f4,#$f4,#$f4,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
statusIntro1 SUBROUTINE
; continue moving moustaches down, up to 4 raster lines (middle of text)
lda $d011
and #$07
cmp #$04
beq .next ; if interrupt is in the middle, don't move it anymore, and...
inc $d011
inc moustacheLine
jsr setupMoustacheInterrupt
rts
.next:
jsr setupMoustacheInterrupt ; ... always remember to display moustache, anyhow ...
lda counter ; wait for song synchronization up to interrupt $0080
cmp #$80
bne .end
lda counter + 1
cmp #$00
bne .end
ldy #$0
lda #$07
.colorLoop:
sta $d940,y
iny
cpy #200
bne .colorLoop
lda #ST_INTRO2
sta status
.end:
rts
statusIntro2 SUBROUTINE
jsr setupMoustacheInterrupt
; "RETROFFICINA"
lda #<introStringA1
sta srcStringPointer
lda #>introStringA1
sta srcStringPointer + 1
lda #$48
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$01
bne .end
lda #ST_INTRO3
sta status
.end:
rts
statusIntro3 SUBROUTINE
jsr setupMoustacheInterrupt
; "AND"
lda #<introStringA2
sta srcStringPointer
lda #>introStringA2
sta srcStringPointer + 1
lda #$a5
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$86
bne .end
lda counter + 1
cmp #$01
bne .end
lda #ST_INTRO4
sta status
.end:
rts
statusIntro4 SUBROUTINE
jsr setupMoustacheInterrupt
; "GIOMBA"
lda #<introStringA3
sta srcStringPointer
lda #>introStringA3
sta srcStringPointer + 1
lda #$f9
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$02
bne .end
MEMSET #$540, #$80, #200
lda #ST_INTRO5
sta status
.end:
rts
statusIntro5 SUBROUTINE
jsr setupMoustacheInterrupt
; "PRESENT"
lda #<introStringA4
sta srcStringPointer
lda #>introStringA4
sta srcStringPointer + 1
lda #$50
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$80
bne .end
lda counter + 1
cmp #$02
bne .end
lda #ST_INTRO6
sta status
.end:
rts
statusIntro6 SUBROUTINE
jsr setupMoustacheInterrupt
; "A COMMODORE 64"
lda #<introStringA5
sta srcStringPointer
lda #>introStringA5
sta srcStringPointer + 1
lda #$9d
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$03
bne .end
lda #ST_INTRO7
sta status
.end:
rts
statusIntro7 SUBROUTINE
jsr setupMoustacheInterrupt
; "VIDEOGAME"
lda #<introStringA6
sta srcStringPointer
lda #>introStringA6
sta srcStringPointer + 1
lda #$ef
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$80
bne .end
lda counter + 1
cmp #$03
bne .end
lda #ST_INTRO8
sta status
.end:
rts
statusIntro8 SUBROUTINE
jsr setupMoustacheInterrupt
; blank wait
lda counter
cmp #$16
bne .end
lda counter + 1
cmp #$04
bne .end
lda #ST_MENURESET
sta status
.end:
rts
statusMenuReset SUBROUTINE
lda #$05
ldy #$0
.lastlineColorLoop:
sta $db98,y
iny
cpy #80
bne .lastlineColorLoop
; Print Game Title: big "SNAKE"
MEMSET #$d800, #$02, #280 ; color
MEMCPY #$400, #SnakeText, #280 ; text
; Print PETSCII GLG Programs
MEMSET #($6a8 + $d800 - $400), #$02, #200 ; color
MEMCPY #$6a8, #GLGProgramsText, #200 ; text
; Print website
lda #<intro2string ; lsb of string address
sta srcStringPointer ; put into lsb of source pointer
lda #>intro2string ; do the same for msb of string address
sta srcStringPointer + 1 ; put into msb of source pointer
lda #$9e ; this is lsb of address of 23th line
sta dstScreenPointer ; put into lsb of dest pointer
lda #$07 ; do the same for msb of adress of 20th line
sta dstScreenPointer + 1 ; put into msb of dest pointer
jsr printString ; print
; Print Copyright
lda #<intro3string ; the assembly is the same as above,
sta srcStringPointer ; just change string to be printed
lda #>intro3string ; and line (24th line)
sta srcStringPointer + 1
lda #$ce
sta dstScreenPointer
lda #$07
sta dstScreenPointer + 1
jsr printString
; boat-shaped horizontal line (rounded edges toward the top)
; this overwrites the "present" word from the intro
lda #$f2 ; 3rd quadrant
sta $540
lda #$f3 ; 4th quadrant
sta $567
lda #$07 ; color for edges
sta $540+$d800-$400
sta $567+$d800-$400
ldy #$1
.boatLineLoop:
lda #$f4 ; horizontal line
sta $540,y
lda #$07
sta $540+$d800-$400,y
iny
cpy #39
bne .boatLineLoop
lda #$05
sta XCharOffset
jsr setupMoustacheInterrupt ; never forget the magic moustaches
lda #ST_MENU
sta status
rts
SnakeText:
HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f7 80 80 f6 80 f6 a0 a0 f7 80 f7 80 80 80 f6 a0 a0 f9 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 f7 80 a0 80 a0 80 80 a0 80 a0 f6 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 a0 f7 a0 80 a0 80 80 a0 80 a0 a0 f9 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 f8 a0 a0 f7 80 a0 f8 a0 a0 80 a0 a0 a0 a0 80 a0 f9 80 80 a0 a0 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 f8 a0 80 a0 80 80 a0 80 a0 f7 80 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 80 a0 80 a0 80 80 a0 80 a0 a0 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f8 80 80 f8 80 f9 80 80 f8 80 a0 f8 f9 80 f8 a0 a0 f7 80 80 80 80 80 80 80 80 80
;ParabolicSpaceChars:
; HEX 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
;ParabolicSpaceScroll:
; HEX 00 01 01 01 01 01 01 01 02 02 02 03 03 04 04 05 06 06 07 00 00 01 02 03 04 05 06 07 00 01 02 04 05 06 00 01 02 04 05 07 00 02 04 05 07 00 01 03 04 06 00 01 03 04 06 07 00 02 03 04 06 07 00 01 02 03 04 05 06 07 00 01 02 02 03 04 04 05 05 06 06 06 07 06 07 07 07 07 07 07 07
setupXScrollInterrupt SUBROUTINE
ldx #<XScrollInterruptH
ldy #>XScrollInterruptH
stx $314
sty $315
; Set raster beam to trigger interrupt at row
lda #42
sta $d012
rts
XScrollInterruptH SUBROUTINE
lda $d016
and #$f8
ora XScrollOffset
sta $d016
dec $d019
ldx #<XScrollInterruptL
ldy #>XScrollInterruptL
stx $314
sty $315
lda #110
sta $d012
jmp $ea31
XScrollInterruptL SUBROUTINE
lda $d016
and #$f8
sta $d016
dec $d019
ldx #<XScrollInterruptMoveAll
ldy #>XScrollInterruptMoveAll
stx $314
sty $315
lda #120
sta $d012
jmp $ea31
XScrollInterruptMoveAll SUBROUTINE
dec $d019 ; EOI
tsx
dex
lda XCharOffset
asl
asl
asl
sta $100,x
lda $d016
and #$07
ora $100,x
inx
txs
cmp #78
bcs .isEdge
cmp #3
bcc .isEdge
cmp #70
bcs .isMiddle
cmp #10
bcc .isMiddle
jmp .enter
.isMiddle:
lda counter
and #$01
beq .enter
jmp .next
.isEdge:
lda counter
and #$03
beq .enter ; ah, some good spaghetti code to accomodate for far branch
jmp .next ; bounce slower
.isCenter:
.enter:
lda XScrollDirection
and #$01
bne .goRight
.goLeft:
dec XScrollOffset
lda XScrollOffset
and #$07
cmp #$07
beq .continue1
jmp .next
.continue1:
lda #$07
sta XScrollOffset
.moveEverythingLeft:
dec XCharOffset
ldy #0
.loop1:
lda $401,y
sta $400,y
lda $429,y
sta $428,y
lda $451,y
sta $450,y
lda $479,y
sta $478,y
lda $4a1,y
sta $4a0,y
lda $4c9,y
sta $4c8,y
lda $4f1,y
sta $4f0,y
iny
cpy #38
bne .loop1
lda XCharOffset
cmp #0
bne .next
lda #$01
sta XScrollDirection
jmp .next
.goRight:
inc XScrollOffset
lda XScrollOffset
and #$07
cmp #$00
bne .next
lda #$00
sta XScrollOffset
.moveEverythingRight:
inc XCharOffset
ldy #38
.loop2:
lda $400,y
sta $401,y
lda $428,y
sta $429,y
lda $450,y
sta $451,y
lda $478,y
sta $479,y
lda $4a0,y
sta $4a1,y
lda $4c8,y
sta $4c9,y
lda $4f0,y
sta $4f1,y
dey
bne .loop2
lda XCharOffset
cmp #10
bne .next
lda #$00
sta XScrollOffset
lda #$00
sta XScrollDirection
.next:
jsr setupMoustacheInterrupt
jmp $ea31
statusMenu SUBROUTINE
jsr setupXScrollInterrupt
rts

View File

@ -1,53 +0,0 @@
#if VERBOSE = 1
LASTINIT SET .
#endif
; Intro reset
; ----------------------------------------------------------------------
introreset:
jsr multicolorOff
jsr clearScreen
; Copy shade colors from costant table to color RAM for 2nd and 4th line of text
ldx #39
introresetColorShade
lda colorshade,x
sta $d828,x ; 2nd line
sta $d878,x ; 4th line
dex
cpx #$ff
bne introresetColorShade
; Set screen colors
lda #0
sta $d020 ; overscan
sta $d021 ; center
; Print website
lda #<intro2string ; lsb of string address
sta srcStringPointer ; put into lsb of source pointer
lda #>intro2string ; do the same for msb of string address
sta srcStringPointer + 1 ; put into msb of source pointer
lda #$26 ; this is lsb of address of 20th line
sta dstScreenPointer ; put into lsb of dest pointer
lda #$07 ; do the same for msb of adress of 20th line
sta dstScreenPointer + 1 ; put into msb of dest pointer
jsr printString ; print
; Print Copyright
lda #<intro3string ; the assembly is the same as above,
sta srcStringPointer ; just change string to be printed
lda #>intro3string ; and line (21th line)
sta srcStringPointer + 1
lda #$58
sta dstScreenPointer
lda #$07
sta dstScreenPointer + 1
jsr printString
rts
#if VERBOSE = 1
ECHO "introreset.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,7 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
; Reset variables for a new level ; Reset variables for a new level
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
levelresetvar: levelresetvar:
@ -35,7 +32,3 @@ clearListLoop:
bne clearListLoop bne clearListLoop
rts rts
#if VERBOSE = 1
ECHO "levelreset.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,9 +1,14 @@
#if VERBOSE = 1 SEG zeropageSegment
LASTINIT SET . ; Pointer to video memory used in the level loading routine
#endif levelVideoPointer WORD
levelColorPointer WORD
; Pointer to level struct
levelPointer WORD
SEG programSegment
; load new level on the screen ; load new level on the screen
statusLevelTitle SUBROUTINE statusLevelTitle SUBROUTINE
jsr multicolorOff
jsr clearScreen jsr clearScreen
; Print "Next Level" ; Print "Next Level"
@ -57,10 +62,11 @@ statusLevelTitle SUBROUTINE
rts rts
statusLevelLoad SUBROUTINE statusLevelLoad SUBROUTINE
jsr multicolorOn
; Upper bar -- fill with spaces, color yellow ; Upper bar -- fill with spaces, color yellow
ldx #39 ldx #39
.loop: .loop:
lda #$0 lda #$80
sta $400,x sta $400,x
lda #7 lda #7
sta $d800,x sta $d800,x
@ -139,9 +145,9 @@ writeLevelElement:
lda levelT lda levelT
sta (levelVideoPointer),y sta (levelVideoPointer),y
; tiles colors can be found in an array ; tiles colors can be found in an array
; position in array = tile value - $60 ; position in array = tile value - $e0
sec sec
sbc #$60 sbc #$e0
tax tax
lda tilesColors,x lda tilesColors,x
sta (levelColorPointer),y sta (levelColorPointer),y
@ -165,7 +171,3 @@ writeLevelEnd:
lda #ST_PLAY lda #ST_PLAY
sta status sta status
rts rts
#if VERBOSE = 1
ECHO "levels.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,10 +1,9 @@
processor 6502 processor 6502
SEG.U SEG.U zeropageSegment
org $02 org $02
INCLUDE "zeropage.asm"
SEG autostart SEG loaderSegment
org $801 org $801
autostartRoutine SUBROUTINE autostartRoutine SUBROUTINE
; this is at $801 ; this is at $801
@ -50,11 +49,9 @@ autostartRoutine SUBROUTINE
; DATA ; DATA
; ------------------------------------- ; -------------------------------------
SEG loaderSegment
packFileName: packFileName:
BYTE "PACKLZ" BYTE "PACKLZ"
packFileNameEnd: packFileNameEnd:
#if VERBOSE = 1
ECHO "PRG SIZE:",(. - $801),"=",[(. - $801)d]
#endif

View File

@ -1,44 +1,48 @@
inflate SUBROUTINE SEG zeropageSegment
.inEnd EQU 2 srcPointer WORD
.offset EQU 4 dstPointer WORD
.length EQU 6 inEnd WORD
.symbol EQU 25 offset WORD
.marker1 EQU 30 length BYTE
.marker2 EQU 31 symbol BYTE
.marker3 EQU 32 marker1 BYTE
.marker4 EQU 33 marker2 BYTE
.copy EQU 34 marker3 BYTE
marker4 BYTE
copy WORD
SEG loaderSegment
inflate SUBROUTINE
clc clc
ldy #10 ldy #10
lda (srcPointer),y lda (srcPointer),y
adc srcPointer adc srcPointer
sta .inEnd sta inEnd
dey dey
lda (srcPointer),y lda (srcPointer),y
adc srcPointer + 1 adc srcPointer + 1
sta .inEnd + 1 sta inEnd + 1
clc clc
lda .inEnd lda inEnd
adc #16 adc #16
sta .inEnd sta inEnd
lda .inEnd + 1 lda inEnd + 1
adc #0 adc #0
sta .inEnd + 1 sta inEnd + 1
; Get the marker symbols ; Get the marker symbols
ldy #16 ldy #16
lda (srcPointer),y lda (srcPointer),y
sta .marker1 sta marker1
iny iny
lda (srcPointer),y lda (srcPointer),y
sta .marker2 sta marker2
iny iny
lda (srcPointer),y lda (srcPointer),y
sta .marker3 sta marker3
iny iny
lda (srcPointer),y lda (srcPointer),y
sta .marker4 sta marker4
; Skip header + marker symbols (16 + 4 bytes) ; Skip header + marker symbols (16 + 4 bytes)
clc clc
@ -53,30 +57,30 @@ inflate SUBROUTINE
ldy #0 ; Make sure that Y is zero ldy #0 ; Make sure that Y is zero
.mainloop: .mainloop:
lda srcPointer ; done? lda srcPointer ; done?
cmp .inEnd cmp inEnd
bne .notdone bne .notdone
lda srcPointer + 1 lda srcPointer + 1
cmp .inEnd + 1 cmp inEnd + 1
bne .notdone bne .notdone
rts rts
.notdone: .notdone:
lda (srcPointer),y ; A = symbol lda (srcPointer),y ; A = symbol
sta .symbol sta symbol
sta $d020 sta $d020
inc srcPointer inc srcPointer
bne .noinc1 bne .noinc1
inc srcPointer + 1 inc srcPointer + 1
.noinc1: .noinc1:
cmp .marker1 ; Marker1? cmp marker1 ; Marker1?
beq .domarker1 beq .domarker1
cmp .marker2 ; Marker2? cmp marker2 ; Marker2?
beq .domarker2 beq .domarker2
cmp .marker3 ; Marker3? cmp marker3 ; Marker3?
beq .domarker3 beq .domarker3
cmp .marker4 ; Marker4? cmp marker4 ; Marker4?
beq .domarker4 beq .domarker4
.literal: .literal:
lda .symbol lda symbol
sta (dstPointer),y ; Plain copy sta (dstPointer),y ; Plain copy
inc dstPointer inc dstPointer
bne .mainloop bne .mainloop
@ -101,15 +105,15 @@ inflate SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
sta .offset sta offset
inc .offset inc offset
lda #0 lda #0
sta .offset + 1 ; offset = (b >> 5) + 1 sta offset + 1 ; offset = (b >> 5) + 1
txa txa
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x lda .LZG_LENGTH_DECODE_LUT,x
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f] sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
jmp .docopy jmp .docopy
; marker3 - "Short copy" ; marker3 - "Short copy"
@ -130,13 +134,13 @@ inflate SUBROUTINE
lsr lsr
clc clc
adc #3 adc #3
sta .length ; length = (b >> 6) + 3 sta length ; length = (b >> 6) + 3
txa txa
and #$3f and #$3f
adc #8 adc #8
sta .offset sta offset
lda #0 lda #0
sta .offset + 1 ; offset = (b & 0x3f) + 8 sta offset + 1 ; offset = (b & 0x3f) + 8
beq .docopy beq .docopy
; marker2 - "Medium copy" ; marker2 - "Medium copy"
@ -154,7 +158,7 @@ inflate SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
sta .offset + 1 sta offset + 1
lda (srcPointer),y lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc6 bne .noinc6
@ -162,15 +166,15 @@ inflate SUBROUTINE
.noinc6: .noinc6:
clc clc
adc #8 adc #8
sta .offset sta offset
bcc .noinc7 bcc .noinc7
inc .offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8 inc offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8
.noinc7: .noinc7:
txa txa
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x lda .LZG_LENGTH_DECODE_LUT,x
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f] sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
bne .docopy bne .docopy
.literal2: .literal2:
@ -188,13 +192,13 @@ inflate SUBROUTINE
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x lda .LZG_LENGTH_DECODE_LUT,x
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f] sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
lda (srcPointer),y lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc9 bne .noinc9
inc srcPointer + 1 inc srcPointer + 1
.noinc9: .noinc9:
sta .offset + 1 sta offset + 1
lda (srcPointer),y lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc10 bne .noinc10
@ -202,31 +206,31 @@ inflate SUBROUTINE
.noinc10: .noinc10:
clc clc
adc #$08 adc #$08
sta .offset sta offset
lda .offset + 1 lda offset + 1
adc #$08 adc #$08
sta .offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056 sta offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056
; Copy corresponding data from history window ; Copy corresponding data from history window
.docopy: .docopy:
sec sec
lda dstPointer lda dstPointer
sbc .offset sbc offset
sta .copy sta copy
lda dstPointer + 1 lda dstPointer + 1
sbc .offset + 1 sbc offset + 1
sta .copy + 1 sta copy + 1
.loop1: .loop1:
lda (.copy),y lda (copy),y
sta (dstPointer),y sta (dstPointer),y
iny iny
cpy .length cpy length
bne .loop1 bne .loop1
ldy #0 ; Make sure that Y is zero ldy #0 ; Make sure that Y is zero
clc clc
lda dstPointer lda dstPointer
adc .length adc length
sta dstPointer sta dstPointer
bcc .noinc11 bcc .noinc11
inc dstPointer + 1 inc dstPointer + 1

101
src/macro.asm Normal file
View File

@ -0,0 +1,101 @@
SEG zeropageSegment
; Generic src/dst copy pointers
srcPointer WORD
dstPointer WORD
dstPointerEnd WORD
SEG programSegment
MACRO MEMSET
IF {1} != "D"
clc
lda <{1}
sta dstPointer
adc <{3}
sta dstPointerEnd
lda >{1}
sta dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ELSE
clc
lda dstPointer
adc <{3}
sta dstPointerEnd
lda dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ENDIF
lda {2}
ldy #0
.loop:
sta (dstPointer),y
inc dstPointer
bne .skipInc
inc dstPointer + 1
.skipInc:
ldx dstPointer
cpx dstPointerEnd
bne .loop
ldx dstPointer + 1
cpx dstPointerEnd + 1
bne .loop
ENDM
SEG zeroPageSegment
SEG programSegment
MACRO MEMCPY
IF {1} != "D"
clc
lda <{1}
sta dstPointer
adc <{3}
sta dstPointerEnd
lda >{1}
sta dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ELSE
clc
lda dstPointer
adc <{3}
sta dstPointerEnd
lda dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ENDIF
lda <{2}
sta srcPointer
lda >{2}
sta srcPointer + 1
ldy #$0
.loop:
lda (srcPointer),y
sta (dstPointer),y
inc dstPointer
bne .skipIncDst
inc dstPointer + 1
.skipIncDst:
inc srcPointer
bne .skipIncSrc
inc srcPointer + 1
.skipIncSrc:
ldx dstPointer
cpx dstPointerEnd
bne .loop
ldx dstPointer + 1
cpx dstPointerEnd + 1
bne .loop
ENDM
SEG programSegment
MACRO MOV_WORD_MEM
lda {2}
sta {1}
lda {2} + 1
sta {1} + 1
ENDM

View File

@ -1,80 +1,50 @@
processor 6502 processor 6502
; Platform specific code
; Code yet to be developed, example to use:
; ----------------------------------------------------------------------
#if SYSTEM = 64
; Commodore64 specific code
#else
; Commodore16 specific code
#endif
; Uninitialized zeropage segment
; ----------------------------------------------------------------------
SEG.U zeropageSegment SEG.U zeropageSegment
org $02 ORG_ZEROPAGE EQU $02
INCLUDE "zeropage.asm" org ORG_ZEROPAGE
#if VERBOSE = 1
; Locations $90-$FF in zeropage are used by kernal
ECHO "End of zeropage variables. Space left: ",($90 - .)
#endif
; SID tune (previously properly cleaned, see HVSC)
; ----------------------------------------------------------------------
SEG sidSegment SEG sidSegment
org $1000 ORG_SID EQU $1000
sidtune: org ORG_SID
INCBIN "../res.bin/amour.sid" ORG_FONT EQU $2400
#if VERBOSE = 1
ECHO "End of SIDtune at ",.,"Space left:",($2000 - .)
#endif
; Font Data
; ----------------------------------------------------------------------
SEG fontSegment SEG fontSegment
org $2000 org ORG_FONT
; This binary data that defines the font is exactly 2kB long ($800) ORG_PROGRAM EQU $2800
INCLUDE "font.asm"
; Program Segment
; ----------------------------------------------------------------------
SEG programSegment SEG programSegment
org $2800 org ORG_PROGRAM
ORG_DATA EQU $cd00
SEG.U dataSegment
org ORG_DATA
; INCLUDE
; -----------------------------------------------------------------------------
LASTINIT SET ORG_SID
INCLUDE "sidtune.asm"
ECHO "sidtune : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
LASTINIT SET ORG_FONT
INCLUDE "font.asm"
ECHO "font : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
LASTINIT SET ORG_PROGRAM
INCLUDE "program.asm" INCLUDE "program.asm"
INCLUDE "initdata.asm" INCLUDE "initdata.asm"
INCLUDE "game.asm" INCLUDE "game.asm"
INCLUDE "gameover.asm" INCLUDE "gameover.asm"
INCLUDE "introreset.asm"
INCLUDE "subroutines.asm" INCLUDE "subroutines.asm"
INCLUDE "levels.asm" INCLUDE "levels.asm"
INCLUDE "intro1.asm" INCLUDE "intro1.asm"
INCLUDE "multicolor.asm" INCLUDE "multicolor.asm"
INCLUDE "levelreset.asm" INCLUDE "levelreset.asm"
INCLUDE "outro.asm" INCLUDE "outro.asm"
#if VERBOSE = 1
ECHO "End of program segment at:",.
ECHO "PACK SIZE:",(. - $1000),"=",[(. - $1000)d]
#endif
; Data variables
; -----------------
SEG.U dataSegment
org $cd00
INCLUDE "data.asm" INCLUDE "data.asm"
#if VERBOSE = 1 INCLUDE "macro.asm"
ECHO "End of Data segment. Space left:",($ce00 - .) ECHO "program : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
#endif
; Lists
; -----------------
SEG.U listSegment
org $ce00
listX DS 256
listY DS 256
; ;
; coded 2017, 2018, 2019, 2020 ; coded 2017, 2018, 2019, 2020, 2021
; by giomba -- giomba at glgprograms.it ; by giomba -- giomba at glgprograms.it
; this software is free software and is distributed ; this software is free software and is distributed
; under the terms of GNU GPL v3 license ; under the terms of GNU GPL v3 license

View File

@ -1,9 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
processor 6502
multicolor SUBROUTINE multicolor SUBROUTINE
; Prepare data struct for MultiColor mode ; Prepare data struct for MultiColor mode
@ -43,7 +38,3 @@ multicolorOff:
and #$ef and #$ef
sta $d016 sta $d016
rts rts
#if VERBOSE = 1
ECHO "multicolor.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,7 +1,4 @@
#if VERBOSE = 1 SEG programSegment
LASTINIT SET .
#endif
; Wait for some delay ; Wait for some delay
statusDelay SUBROUTINE statusDelay SUBROUTINE
ldy delay ; load outroDelay and decrement ldy delay ; load outroDelay and decrement
@ -14,7 +11,3 @@ statusDelay SUBROUTINE
lda delayStatus lda delayStatus
sta status sta status
rts rts
#if VERBOSE = 1
ECHO "outro.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,26 +0,0 @@
processor 6502
SEG.U
org $02
INCLUDE "zeropage.asm"
SEG autostart
org $801
autostartRoutine SUBROUTINE
; this is at $801
; and it MUST be exactly at this location in order to autostart
; 10 SYS2060 ($80c) BASIC autostart
BYTE #$0b,#$08,#$0a,#$00,#$9e,#$32,#$30,#$36,#$31,#$00,#$00,#$00
; this is at (2061 dec)=($80d)
; and it MUST be exactly after the above BASIC statement
. = $80d
jmp $2800
. = $1000
INCBIN "../bin/snake.pack"
#if VERBOSE = 1
ECHO "PRG SIZE:",(. - $801 + 2),"=",[(. - $801 + 2)d]
#endif

View File

@ -1,9 +1,10 @@
#if VERBOSE = 1 SEG zeropageSegment
LASTINIT SET . ; Interrupt counter
#endif counter DS 2
; ENTRY OF PROGRAM SEG programSegment
; ---------------------------------------------------------------------- ; this is the entry point of the program and must stay at this address
org $2800
start: start:
; Clear screen, initialize keyboard, restore interrupts ; Clear screen, initialize keyboard, restore interrupts
jsr $ff81 jsr $ff81
@ -57,22 +58,45 @@ zeroFillZeroPage:
lda #ST_INTRO0 lda #ST_INTRO0
sta status sta status
; Enable interrupts
cli
; Reset screen (and other parameters) to play intro ; Reset screen (and other parameters) to play intro
jsr introreset jsr introreset
intro0running: ; Cycle here until SPACE or `Q` is pressed ; Enable interrupts
cli
menu SUBROUTINE
.menu: ; Cycle here until SPACE or `Q` is pressed
jsr $ffe4 ; GETIN jsr $ffe4 ; GETIN
cmp #$20 ; Is it SPACE? cmp #$20 ; Is it SPACE?
beq intro0end ; if yes, go to intro0end and start game (see) beq .intro0end ; if yes, go to intro0end and start game (see)
#if DEBUG = 1
cmp #$41 ; Is it A?
beq .printCounter ; if yes, print current counter
#endif
cmp #$51 ; Is it Q? cmp #$51 ; Is it Q?
bne intro0running ; If not, keep looping here, bne .menu ; If not, keep looping here,
jmp $fce2 ; else, reset the computer jmp $fce2 ; else, reset the computer
#if DEBUG = 1
.printCounter
lda counter + 1
ldy #2
jsr printByte
lda counter
ldy #4
jsr printByte
jmp .menu
#endif
; Intro is finished, now it's time to start the proper game ; Intro is finished, now it's time to start the proper game
intro0end: .intro0end:
; Are you sure? Maybe the demo-intro is not finished, yet
; We do not want to actually start unless the demo is finished,
; otherwise vertical raster line offset may be != 0
lda status
cmp #ST_MENU
bne .menu
; Set current level pointer to list start ; Set current level pointer to list start
lda #<levelsList lda #<levelsList
sta levelPointer sta levelPointer
@ -92,20 +116,21 @@ intro0end:
lda #ST_LEVEL_TITLE lda #ST_LEVEL_TITLE
sta status sta status
endless: .endless:
; Loop waiting for gameover ; Loop waiting for gameover
lda status lda status
cmp #ST_END ; is status equal to end ? cmp #ST_END ; is status equal to end ?
bne endless ; if not, just wait looping here, else... bne .endless ; if not, just wait looping here, else...
jsr introreset ; reset variables for intro jsr clearScreen
lda #ST_INTRO0
sta status ; put machine into play intro status
jmp intro0running ; and go there waiting for keypress
; Interrupt Handler lda #ST_MENURESET
sta status ; put machine into menu status
jmp .menu ; and go there waiting for keypress
; Main Raster Interrupt Handler
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
irq: irq SUBROUTINE
; Things that must be done every interrupt (50Hz) ; Things that must be done every interrupt (50Hz)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Acknoweledge IRQ ; Acknoweledge IRQ
@ -118,24 +143,84 @@ irq:
tya tya
pha pha
#if DEBUG = 1
; Change background to show how much time does music take for each interrupt
lda #1
sta $d020
#endif
; Play music first -> no audio skew if computations are slow
jsr sidtune + 3
#if DEBUG = 1 #if DEBUG = 1
; Change background to visually see the ISR timing ; Change background to visually see the ISR timing
lda #2 lda #2
sta $d020 sta $d020
#endif #endif
inc counter
bne .noIncCounter
inc counter + 1
.noIncCounter
; Check status and call appropriate sub-routine ; Check status and call appropriate sub-routine
; Sort of switch-case ; Sort of switch-case
lda status lda status
checkStatusIntro0:
cmp #ST_INTRO0 cmp #ST_INTRO0
bne checkStatusIntro1 bne checkStatusIntro1
jsr statusIntro0 jsr statusIntro0
jmp checkEndStatus jmp checkEndStatus
checkStatusIntro1: checkStatusIntro1:
cmp #ST_INTRO1 cmp #ST_INTRO1
bne checkStatusPlay bne checkStatusIntro2
jsr statusIntro1 jsr statusIntro1
jmp checkEndStatus jmp checkEndStatus
checkStatusIntro2:
cmp #ST_INTRO2
bne checkStatusIntro3
jsr statusIntro2
jmp checkEndStatus
checkStatusIntro3:
cmp #ST_INTRO3
bne checkStatusIntro4
jsr statusIntro3
jmp checkEndStatus
checkStatusIntro4:
cmp #ST_INTRO4
bne checkStatusIntro5
jsr statusIntro4
jmp checkEndStatus
checkStatusIntro5:
cmp #ST_INTRO5
bne checkStatusIntro6
jsr statusIntro5
jmp checkEndStatus
checkStatusIntro6:
cmp #ST_INTRO6
bne checkStatusIntro7
jsr statusIntro6
jmp checkEndStatus
checkStatusIntro7:
cmp #ST_INTRO7
bne checkStatusIntro8
jsr statusIntro7
jmp checkEndStatus
checkStatusIntro8:
cmp #ST_INTRO8
bne checkStatusMenuReset
jsr statusIntro8
jmp checkEndStatus
checkStatusMenuReset:
cmp #ST_MENURESET
bne checkStatusMenu
jsr statusMenuReset
jmp checkEndStatus
checkStatusMenu:
cmp #ST_MENU
bne checkStatusPlay
jsr statusMenu
jmp checkEndStatus
checkStatusPlay: checkStatusPlay:
cmp #ST_PLAY cmp #ST_PLAY
bne checkStatusDelay bne checkStatusDelay
@ -158,19 +243,6 @@ checkStatusLevelLoad:
jmp checkEndStatus jmp checkEndStatus
checkEndStatus: checkEndStatus:
#if DEBUG = 1
; Change background to show how much time does music take for each interrupt
lda #1
sta $d020
#endif
; Play music
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
; Increase random value ; Increase random value
inc random inc random
@ -189,7 +261,3 @@ checkEndStatus:
; Go to original system routine ; Go to original system routine
jmp $ea31 jmp $ea31
#if VERBOSE = 1
ECHO "program.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

6
src/sidtune.asm Normal file
View File

@ -0,0 +1,6 @@
SEG sidSegment
sidtune:
INCBIN "../res.bin/amour2.sid"
; Note: the SID tune must be properly cleaned (eg. header removed)
; See HVSC for .sid music format

View File

@ -1,15 +1,14 @@
#if VERBOSE = 1 SEG zeropageSegment
LASTINIT SET . ; Where is the snake head in video memory? Do math to calculate address
#endif ; using pointer at tileMem
tileMem WORD
; Subroutines
; ----------------------------------------------------------------------
SEG programSegment
; Clear screen -- easy ; Clear screen -- easy
clearScreen SUBROUTINE clearScreen SUBROUTINE
ldx #$ff ldx #$ff
.loop: .loop:
lda #$00 lda #$80
sta $400,x sta $400,x
sta $500,x sta $500,x
sta $600,x sta $600,x
@ -81,16 +80,23 @@ printByte SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
ora #$40 ; add 64 (see font) ora #$c0 ; add 192 (see font)
sta $400,y ; print msb char sta $400,y ; print msb char
txa ; Take least significant nibble (use previous copy) txa ; Take least significant nibble (use previous copy)
and #$0f and #$0f
ora #$40 ; add 64 (see font) ora #$c0 ; add 192 (see font)
sta $401,y ; print lsb char sta $401,y ; print lsb char
rts rts
SEG zeropageSegment
; Pointer to string
srcStringPointer WORD
; Pointer to screen position where to print intro string
dstScreenPointer DS 2
SEG programSegment
printString SUBROUTINE printString SUBROUTINE
; Print string ; Print string
; Input parameters: ; Input parameters:
@ -104,22 +110,22 @@ printString SUBROUTINE
beq .end ; if zero, then end (string must be null-terminated) beq .end ; if zero, then end (string must be null-terminated)
cmp #$20 ; is space? cmp #$20 ; is space?
bne .checkP1 bne .checkP1
lda #$0 lda #$80
jmp .print jmp .print
.checkP1: .checkP1:
cmp #$28 ; is char '(' ? cmp #$28 ; is char '(' ?
bne .checkP2 bne .checkP2
lda #$1b lda #$9b
jmp .print jmp .print
.checkP2: .checkP2:
cmp #$29 ; is char ')' ? cmp #$29 ; is char ')' ?
bne .checkP3 bne .checkP3
lda #$1c lda #$9c
jmp .print jmp .print
.checkP3 .checkP3
cmp #$2e ; is char '.' ? cmp #$2e ; is char '.' ?
bne .checkNumber bne .checkNumber
lda #$1d lda #$9d
jmp .print jmp .print
.checkNumber: ; is char a number? .checkNumber: ; is char a number?
cmp #$2f cmp #$2f
@ -129,14 +135,14 @@ printString SUBROUTINE
sec sec
sbc #$30 sbc #$30
clc clc
adc #$40 adc #$c0
jmp .print jmp .print
.nextCheck: .nextCheck:
.isLetter: .isLetter:
; defaults to an uppercase letter of ASCII set ; defaults to an uppercase letter of ASCII set
sec clc
sbc #$40 adc #$40
.print: .print:
sta (dstScreenPointer),y ; put screen code to screen sta (dstScreenPointer),y ; put screen code to screen
iny ; next char in string iny ; next char in string
@ -144,6 +150,11 @@ printString SUBROUTINE
.end: .end:
rts rts
SEG zeropageSegment
; Pointer for Pointer in the NextPointer routine
nextPointerPointer DS 2
SEG programSegment
; Increment a pointer in the zeropage ; Increment a pointer in the zeropage
; Input parameters: ; Input parameters:
; nextPointerPointer pointer to the pointer in zeropage ; nextPointerPointer pointer to the pointer in zeropage
@ -164,7 +175,3 @@ nextPointer:
sta (nextPointerPointer),y sta (nextPointerPointer),y
rts rts
#if VERBOSE = 1
ECHO "subroutines.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,31 +0,0 @@
; Zero page utility pointers
; ----------------------------------------------------------------------
; Where is the snake head in video memory? Do math to calculate address
; using pointer at tileMem,tileMem+1
tileMem DS 2
; Pointer to string
srcStringPointer DS 2
; Pointer to screen position where to print intro string
dstScreenPointer DS 2
; Pointer to level struct
levelPointer DS 2
; Pointer to video memory used in the level loading routine
levelVideoPointer DS 2
levelColorPointer DS 2
; Pointer for Pointer in the NextPointer routine
nextPointerPointer DS 2
; Pointer to string for strlen routine
strlenString DS 2
; Generic src/dst copy pointers
srcPointer DS 2
dstPointer DS 2
; Note: Locations $90-$FF in zeropage are used by kernal

View File

@ -7,11 +7,11 @@ void flush(char last, int count) {
char tile, color; char tile, color;
switch(last) { switch(last) {
case 'x': case 'x':
tile = (char)0x63; break; tile = (char)0xe3; break;
case 'f': case 'f':
tile = (char)0x62; break; tile = (char)0xe2; break;
default: default:
tile = (char)0x60; break; tile = (char)0xe0; break;
} }
cout << tile << (char)count; cout << tile << (char)count;
} }