diff --git a/demos/wargames/Makefile b/demos/wargames/Makefile index c0a7f7d4..bc1b6ed4 100644 --- a/demos/wargames/Makefile +++ b/demos/wargames/Makefile @@ -3,22 +3,33 @@ include ../../Makefile.inc DOS33 = ../../utils/dos33fs-utils/dos33 TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft EMPTY_DISK = ../../empty_disk/empty.dsk +PNG2HGR = ../../utils/hgr-utils/png2hgr +LZSA = ~/research/lzsa/lzsa/lzsa + all: wargames.dsk wargames.dsk: HELLO WARGAMES - cp $(EMPTY_DISK) speech.dsk - $(DOS33) -y speech.dsk SAVE A HELLO - $(DOS33) -y speech.dsk BSAVE -a 0x1000 WARGAMES + cp $(EMPTY_DISK) wargames.dsk + $(DOS33) -y wargames.dsk SAVE A HELLO + $(DOS33) -y wargames.dsk BSAVE -a 0x1000 WARGAMES ### WARGAMES: wargames.o ld65 -o WARGAMES wargames.o -C ../../linker_scripts/apple2_1000.inc -wargames.o: wargames.s ssi263.inc ssi263_detect.s ssi263_simple_speech.s +wargames.o: wargames.s ssi263.inc ssi263_detect.s ssi263_simple_speech.s \ + map.lzsa ca65 -o wargames.o wargames.s -l wargames.lst +### + +map.lzsa: map.hgr + $(LZSA) -r -f2 map.hgr map.lzsa + +map.hgr: map.png + $(PNG2HGR) map.png > map.hgr ### diff --git a/demos/wargames/circles.s b/demos/wargames/circles.s new file mode 100644 index 00000000..83eff2c9 --- /dev/null +++ b/demos/wargames/circles.s @@ -0,0 +1,315 @@ +; VGI_Circles + +TEMP0 = $80 +TEMP1 = $81 +TEMP2 = $82 +TEMP3 = $83 +TEMP4 = $84 +TEMP5 = $85 + +P0 = $86 +P1 = $87 +P2 = $88 +P3 = $89 + + +XX = TEMP0 +MINUSXX = TEMP1 +YY = TEMP2 +MINUSYY = TEMP3 +D = TEMP4 +COUNT = TEMP5 + + ;======================== + ; VGI circle + ;======================== + +; VGI_CCOLOR = P0 +; VGI_CX = P1 +; VGI_CY = P2 +; VGI_CR = P3 + +vgi_circle: + ldx VGI_CCOLOR + lda COLORTBL,X + sta HGR_COLOR + + ;=============================== + ; draw circle + ;=============================== + ; draw circle at (CX,CY) of radius R + ; signed 8-bit math so problems if R > 64? + + ; XX=0 YY=R + ; D=3-2*R + ; GOTO6 + + lda #0 + sta XX + + lda VGI_CR + sta YY + + lda #3 + sec + sbc VGI_CR + sbc VGI_CR + sta D + + jmp do_plots + +circle_loop: + ; X=X+1 + + inc XX + + ; IF D>0 THEN Y=Y-1:D=D+4*(X-Y)+10 + lda D + bmi else + + dec YY + + lda XX + sec + sbc YY + asl + asl + clc + adc D + adc #10 + jmp store_D + +else: + ; ELSE D=D+4*X+6 + lda XX + asl + asl + clc + adc D + adc #6 +store_D: + sta D + +do_plots: + ; setup constants + + lda XX + eor #$FF + sta MINUSXX + inc MINUSXX + + lda YY + eor #$FF + sta MINUSYY + inc MINUSYY + + ; HPLOT CX+X,CY+Y + ; HPLOT CX-X,CY+Y + ; HPLOT CX+X,CY-Y + ; HPLOT CX-X,CY-Y + ; HPLOT CX+Y,CY+X + ; HPLOT CX-Y,CY+X + ; HPLOT CX+Y,CY-X + ; HPLOT CX-Y,CY-X + + ; calc X co-ord + + lda #7 + sta COUNT +pos_loop: + lda COUNT + and #$4 + lsr + tay + + lda COUNT + lsr + bcc xnoc + iny +xnoc: + lda VGI_CX + clc + adc XX,Y + tax + + ; calc y co-ord + + lda COUNT + lsr + eor #$2 + tay + + lda VGI_CY + clc + adc XX,Y + + ldy #0 + + jsr HPLOT0 ; plot at (Y,X), (A) + + dec COUNT + bpl pos_loop + + + ; IFY>=XTHEN4 + lda YY + cmp XX + bcs circle_loop + + rts + + + + + ;======================== + ; VGI circle + ;======================== + ; VGI_CCOLOR = P0 + ; VGI_CX = P1 + ; VGI_CY = P2 + ; VGI_CR = P3 + +vgi_filled_circle: + ldx VGI_CCOLOR + lda COLORTBL,X + sta HGR_COLOR + + ;=============================== + ; draw filled circle + ;=============================== + ; draw filled circle at (CX,CY) of radius R + ; signed 8-bit math so problems if R > 64? + + + ; XX=0 YY=R + ; D=3-2*R + ; GOTO6 + + lda #0 + sta XX + + lda VGI_CR + sta YY + + lda #3 + sec + sbc VGI_CR + sbc VGI_CR + sta D + + jmp do_filled_plots + +filled_circle_loop: + ; X=X+1 + + inc XX + + ; IF D>0 THEN Y=Y-1:D=D+4*(X-Y)+10 + lda D + bmi filled_else + + dec YY + + lda XX + sec + sbc YY + asl + asl + clc + adc D + adc #10 + jmp store_filled_D + +filled_else: + ; ELSE D=D+4*X+6 + lda XX + asl + asl + clc + adc D + adc #6 +store_filled_D: + sta D + +do_filled_plots: + ; setup constants + + lda XX + eor #$FF + sta MINUSXX + inc MINUSXX + + lda YY + eor #$FF + sta MINUSYY + inc MINUSYY + + ; HPLOT CX+X,CY+Y + ; HPLOT CX-X,CY+Y + ; HPLOT CX+X,CY-Y + ; HPLOT CX-X,CY-Y + ; HPLOT CX+Y,CY+X + ; HPLOT CX-Y,CY+X + ; HPLOT CX+Y,CY-X + ; HPLOT CX-Y,CY-X + + + + + lda #3 + sta COUNT +filled_pos_loop: + + ; calc left side + + ; calc X co-ord + + lda COUNT + ora #$1 + eor #$2 + tay + lda VGI_CX + clc + adc XX,Y + tax + + ; calc y co-ord + + ldy COUNT + lda VGI_CY + clc + adc XX,Y + + ldy #0 + +; pha ; save Y value for later + + jsr HPLOT0 ; plot at (Y,X), (A) + + + ; calc right side + lda COUNT + and #$2 + eor #$2 + tay + lda XX,Y + asl + + ldy #0 + ldx #0 + + jsr HLINRL ; plot relative (X,A), (Y) + ; so in our case (0,XX*2),0 + + + + dec COUNT + bpl filled_pos_loop + + + ; IFY>=XTHEN4 + lda YY + cmp XX + bcs filled_circle_loop + + rts diff --git a/demos/wargames/decompress_fast_v2.s b/demos/wargames/decompress_fast_v2.s new file mode 100644 index 00000000..fb2f24ad --- /dev/null +++ b/demos/wargames/decompress_fast_v2.s @@ -0,0 +1,370 @@ +; note -- modified by Vince Weaver to assemble with ca65 +; in this case, A = page to decompress to +; getsrc_smc+1, getsrc_smc+2 is src location + +; ----------------------------------------------------------------------------- +; Decompress raw LZSA2 block. +; Create one with lzsa -r -f2 +; +; in: +; * LZSA_SRC_LO and LZSA_SRC_HI contain the compressed raw block address +; * LZSA_DST_LO and LZSA_DST_HI contain the destination buffer address +; +; out: +; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1 +; +; ----------------------------------------------------------------------------- +; Backward decompression is also supported, use lzsa -r -b -f2 +; To use it, also define BACKWARD_DECOMPRESS=1 before including this code! +; +; in: +; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data +; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer +; +; out: +; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1 +; +; ----------------------------------------------------------------------------- +; +; Copyright (C) 2019 Emmanuel Marty, Peter Ferrie +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source distribution. +; ----------------------------------------------------------------------------- + +;NIBCOUNT = $FC ; zero-page location for temp offset + +decompress_lzsa2_fast: + + sta LZSA_DST_HI + + ldy #$00 + sty LZSA_DST_LO + sty NIBCOUNT + +decode_token: + jsr getsrc ; read token byte: XYZ|LL|MMM + pha ; preserve token on stack + + and #$18 ; isolate literals count (LL) + beq no_literals ; skip if no literals to copy + cmp #$18 ; LITERALS_RUN_LEN_V2? + bcc prepare_copy_literals ; if less, count is directly embedded in token + + jsr getnibble ; get extra literals length nibble + ; add nibble to len from token + adc #$02 ; (LITERALS_RUN_LEN_V2) minus carry + cmp #$12 ; LITERALS_RUN_LEN_V2 + 15 ? + bcc prepare_copy_literals_direct ; if less, literals count is complete + + jsr getsrc ; get extra byte of variable literals count + ; the carry is always set by the CMP above + ; GETSRC doesn't change it + sbc #$EE ; overflow? + jmp prepare_copy_literals_direct + +prepare_copy_literals_large: + ; handle 16 bits literals count + ; literals count = directly these 16 bits + jsr getlargesrc ; grab low 8 bits in X, high 8 bits in A + tay ; put high 8 bits in Y + bcs prepare_copy_literals_high ; (*same as JMP PREPARE_COPY_LITERALS_HIGH but shorter) + +prepare_copy_literals: + lsr ; shift literals count into place + lsr + lsr + +prepare_copy_literals_direct: + tax + bcs prepare_copy_literals_large ; if so, literals count is large + +prepare_copy_literals_high: + txa + beq copy_literals + iny + +copy_literals: + jsr getput ; copy one byte of literals + dex + bne copy_literals + dey + bne copy_literals + +no_literals: + pla ; retrieve token from stack + pha ; preserve token again + asl + bcs repmatch_or_large_offset ; 1YZ: rep-match or 13/16 bit offset + + asl ; 0YZ: 5 or 9 bit offset + bcs offset_9_bit + + ; 00Z: 5 bit offset + + ldx #$FF ; set offset bits 15-8 to 1 + + jsr getcombinedbits ; rotate Z bit into bit 0, read nibble for bits 4-1 + ora #$E0 ; set bits 7-5 to 1 + bne got_offset_lo ; go store low byte of match offset and prepare match + +offset_9_bit: ; 01Z: 9 bit offset + ;;asl ; shift Z (offset bit 8) in place + rol + rol + and #$01 + eor #$FF ; set offset bits 15-9 to 1 + bne got_offset_hi ; go store high byte, read low byte of match offset and prepare match + ; (*same as JMP GOT_OFFSET_HI but shorter) + +repmatch_or_large_offset: + asl ; 13 bit offset? + bcs repmatch_or_16bit ; handle rep-match or 16-bit offset if not + + ; 10Z: 13 bit offset + + jsr getcombinedbits ; rotate Z bit into bit 8, read nibble for bits 12-9 + adc #$DE ; set bits 15-13 to 1 and substract 2 (to substract 512) + bne got_offset_hi ; go store high byte, read low byte of match offset and prepare match + ; (*same as JMP GOT_OFFSET_HI but shorter) + +repmatch_or_16bit: ; rep-match or 16 bit offset + ;;ASL ; XYZ=111? + bmi rep_match ; reuse previous offset if so (rep-match) + + ; 110: handle 16 bit offset + jsr getsrc ; grab high 8 bits +got_offset_hi: + tax + jsr getsrc ; grab low 8 bits +got_offset_lo: + sta OFFSLO ; store low byte of match offset + stx OFFSHI ; store high byte of match offset + +rep_match: +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression - substract match offset + + sec ; add dest + match offset + lda putdst+1 ; low 8 bits +OFFSLO = *+1 + sbc #$AA + sta copy_match_loop+1 ; store back reference address + lda putdst+2 +OFFSHI = *+1 + sbc #$AA ; high 8 bits + sta copy_match_loop+2 ; store high 8 bits of address + sec + +.else + + ; Forward decompression - add match offset + + clc ; add dest + match offset + lda putdst+1 ; low 8 bits +OFFSLO = *+1 + adc #$AA + sta copy_match_loop+1 ; store back reference address +OFFSHI = *+1 + lda #$AA ; high 8 bits + adc putdst+2 + sta copy_match_loop+2 ; store high 8 bits of address +.endif + + pla ; retrieve token from stack again + and #$07 ; isolate match len (MMM) + adc #$01 ; add MIN_MATCH_SIZE_V2 and carry + cmp #$09 ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2? + bcc prepare_copy_match ; if less, length is directly embedded in token + + jsr getnibble ; get extra match length nibble + ; add nibble to len from token + adc #$08 ; (MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2) minus carry + cmp #$18 ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2 + 15? + bcc prepare_copy_match ; if less, match length is complete + + jsr getsrc ; get extra byte of variable match length + ; the carry is always set by the CMP above + ; GETSRC doesn't change it + sbc #$E8 ; overflow? + +prepare_copy_match: + tax + bcc prepare_copy_match_y ; if not, the match length is complete + beq decompression_done ; if EOD code, bail + + ; Handle 16 bits match length + jsr getlargesrc ; grab low 8 bits in X, high 8 bits in A + tay ; put high 8 bits in Y + +prepare_copy_match_y: + txa + beq copy_match_loop + iny + +copy_match_loop: + lda $AAAA ; get one byte of backreference + jsr putdst ; copy to destination + +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- put backreference bytes backward + + lda copy_match_loop+1 + beq getmatch_adj_hi +getmatch_done: + dec copy_match_loop+1 + +.else + + ; Forward decompression -- put backreference bytes forward + + inc copy_match_loop+1 + beq getmatch_adj_hi +getmatch_done: + +.endif + + dex + bne copy_match_loop + dey + bne copy_match_loop + jmp decode_token + +.ifdef BACKWARD_DECOMPRESS + +getmatch_adj_hi: + dec copy_match_loop+2 + jmp getmatch_done + +.else + +getmatch_adj_hi: + inc copy_match_loop+2 + jmp getmatch_done +.endif + +getcombinedbits: + eor #$80 + asl + php + + jsr getnibble ; get nibble into bits 0-3 (for offset bits 1-4) + plp ; merge Z bit as the carry bit (for offset bit 0) +combinedbitz: + rol ; nibble -> bits 1-4; carry(!Z bit) -> bit 0 ; carry cleared +decompression_done: + rts + +getnibble: +NIBBLES = *+1 + lda #$AA + lsr NIBCOUNT + bcc need_nibbles + and #$0F ; isolate low 4 bits of nibble + rts + +need_nibbles: + inc NIBCOUNT + jsr getsrc ; get 2 nibbles + sta NIBBLES + lsr + lsr + lsr + lsr + sec + rts + +.ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- get and put bytes backward + +getput: + jsr getsrc +putdst: +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + sta $AAAA + lda putdst+1 + beq putdst_adj_hi + dec putdst+1 + rts + +putdst_adj_hi: + dec putdst+2 + dec putdst+1 + rts + +getlargesrc: + jsr getsrc ; grab low 8 bits + tax ; move to X + ; fall through grab high 8 bits + +getsrc: +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + lda $AAAA + pha + lda getsrc+1 + beq getsrc_adj_hi + dec getsrc+1 + pla + rts + +getsrc_adj_hi: + dec getsrc+2 + dec getsrc+1 + pla + rts + +.else + + ; Forward decompression -- get and put bytes forward + +getput: + jsr getsrc +putdst: +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + sta $AAAA + inc putdst+1 + beq putdst_adj_hi + rts + +putdst_adj_hi: + inc putdst+2 + rts + +getlargesrc: + jsr getsrc ; grab low 8 bits + tax ; move to X + ; fall through grab high 8 bits + +getsrc: +getsrc_smc: +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + lda $AAAA + inc getsrc+1 + beq getsrc_adj_hi + rts + +getsrc_adj_hi: + inc getsrc+2 + rts +.endif + diff --git a/demos/wargames/hardware.inc b/demos/wargames/hardware.inc index b52d7281..c68306bb 100644 --- a/demos/wargames/hardware.inc +++ b/demos/wargames/hardware.inc @@ -30,14 +30,14 @@ PTRIG = $C070 ;NORMAL = $F273 HGR2 = $F3D8 -;HGR = $F3E2 +HGR = $F3E2 ;BKGND0 = $F3F4 ; clear current page to A HPOSN = $F411 ; (Y,X),(A) (values stores in HGRX,XH,Y) HPLOT0 = $F457 ; plot at (Y,X), (A) ;COLOR_SHIFT = $F47E -;HLINRL = $F530 ; (X,A),(Y) +HLINRL = $F530 ; (X,A),(Y) ;HGLIN = $F53A ; line to (X,A),(Y) -;COLORTBL = $F6F6 +COLORTBL = $F6F6 ; MONITOR ROUTINES diff --git a/demos/wargames/map_plain.png b/demos/wargames/map_plain.png new file mode 100644 index 00000000..e4534f99 Binary files /dev/null and b/demos/wargames/map_plain.png differ diff --git a/demos/wargames/wargames.s b/demos/wargames/wargames.s index b007cf17..f03a696b 100644 --- a/demos/wargames/wargames.s +++ b/demos/wargames/wargames.s @@ -5,10 +5,206 @@ .include "hardware.inc" +VGI_CCOLOR = P0 +VGI_CX = P1 +VGI_CY = P2 +VGI_CR = P3 + +NIBCOUNT = $09 + +HGR_COLOR = $E4 + +MISSILE_LOW = $FD +MISSILE_HIGH = $FE +FRAME = $FF + +STATUS_WAITING = $00 +STATUS_MOVING = $01 +STATUS_EXPLODING = $02 +STATUS_DONE = $FF + +MISSILE_STATUS = 0 +MISSILE_START_FRAME = 1 +MISSILE_X = 2 +MISSILE_X_FRAC = 3 +MISSILE_Y = 4 +MISSILE_Y_FRAC = 5 +MISSILE_DX_H = 6 +MISSILE_DX_L = 7 +MISSILE_DY_H = 8 +MISSILE_DY_L = 9 +MISSILE_DEST_X = 10 +MISSILE_DEST_Y = 11 +MISSILE_RADIUS = 12 + + .include "ssi263.inc" -speech_test: +wargames: + + jsr HGR + + lda #map_lzsa + sta getsrc_smc+2 + + lda #$20 + + jsr decompress_lzsa2_fast + + + lda #0 + sta FRAME +missile_loop: + + lda #missiles + sta MISSILE_HIGH + + ldy #0 + lda (MISSILE_LOW),Y + + ; see if totally done + bpl keep_going + jmp done_missile_loop +keep_going: + cmp #1 + beq missile_ready + cmp #2 + beq missile_explode + + ; else 0, see if match + + ldy #MISSILE_START_FRAME + lda (MISSILE_LOW),Y + cmp FRAME + beq missile_activate + jmp done_missile_loop ; not ready + +missile_activate: + + ; make it ready + lda #STATUS_MOVING + ldy #MISSILE_STATUS + sta (MISSILE_LOW),Y + + +missile_ready: + +missile_draw: + + ldy #MISSILE_X + lda (MISSILE_LOW),Y + tax + + ldy #MISSILE_Y + lda (MISSILE_LOW),Y + + ldy #0 + + jsr HPLOT0 ; plot at (Y,X), (A) + +missile_move: + + ; add X + clc + ldy #MISSILE_DX_L + lda (MISSILE_LOW),Y + ldy #MISSILE_X_FRAC + adc (MISSILE_LOW),Y + sta (MISSILE_LOW),Y + + ldy #MISSILE_DX_H + lda (MISSILE_LOW),Y + ldy #MISSILE_X + adc (MISSILE_LOW),Y + sta (MISSILE_LOW),Y + + ; add Y + clc + ldy #MISSILE_DY_L + lda (MISSILE_LOW),Y + ldy #MISSILE_Y_FRAC + adc (MISSILE_LOW),Y + sta (MISSILE_LOW),Y + + ldy #MISSILE_DY_H + lda (MISSILE_LOW),Y + ldy #MISSILE_Y + adc (MISSILE_LOW),Y + sta (MISSILE_LOW),Y + + + ; see if at end + ldy #MISSILE_Y + lda (MISSILE_LOW),Y + ldy #MISSILE_DEST_Y + cmp (MISSILE_LOW),Y + bne not_match + + ldy #MISSILE_X + lda (MISSILE_LOW),Y + ldy #MISSILE_DEST_X + cmp (MISSILE_LOW),Y + bne not_match + +is_match: + lda #STATUS_EXPLODING + ldy #MISSILE_STATUS + sta (MISSILE_LOW),Y +not_match: + jmp done_missile_loop + +missile_explode: + + lda #7 + sta VGI_CCOLOR + + ldy #MISSILE_RADIUS + lda (MISSILE_LOW),Y + clc + adc #1 + sta (MISSILE_LOW),Y + + sta VGI_CR + + cmp #15 + bcc not_done_explosion + + lda #STATUS_DONE + ldy #MISSILE_STATUS + sta (MISSILE_LOW),Y + +not_done_explosion: + + + ldy #MISSILE_X + lda (MISSILE_LOW),Y + sta VGI_CX + + ldy #MISSILE_Y + lda (MISSILE_LOW),Y + sta VGI_CY + + jsr vgi_filled_circle + + +done_missile_loop: + + lda #50 + jsr WAIT + + inc FRAME + beq done_missiles + + jmp missile_loop + +done_missiles: + + ;========================================= jsr HOME @@ -53,6 +249,10 @@ wait_until_keypress: .include "ssi263_simple_speech.s" +.include "decompress_fast_v2.s" + +.include "circles.s" + ; the document ; "Phonetic Speech Dictionary for the SC-01 Speech Synthesizer" ; sc01-dictionary.pdf @@ -200,3 +400,39 @@ trogdor: .byte $FF +map_lzsa: + .incbin "map.lzsa" + + +header: + .byte "STRATEGY: WINNER:",0 + .byte "USSR FIRST STRIKE",0 + .byte "U.S. FIRST STRIKE",0 + .byte "NATO / WARSAW PACT",0 + .byte "FAR EAST STRATEGY",0 + + +ending: + .byte "GREETINGS PROFESSOR FALKEN",0 + .byte "A STRANGE GAME",0 + .byte "THE ONLY WINNING MOVE IS" + .byte "NOT TO PLAY.",0 + + +code: + .byte "CPE1704TKS",0 + + + + +missiles: + .byte $00 ; status + .byte $10 ; start frame + .byte 10,$10 ; x-location + .byte 50,$10 ; y-location + .byte $01,$00 ; deltax + .byte $00,$00 ; deltay + .byte 100,50 ; destination + .byte $00 ; radius + .byte $00,$00,$00 ; padding +