diff --git a/dlowres_mode7/Makefile b/dlowres_mode7/Makefile new file mode 100644 index 00000000..a0202ffd --- /dev/null +++ b/dlowres_mode7/Makefile @@ -0,0 +1,27 @@ +include ../Makefile.inc + +DOS33 = ../dos33fs-utils/dos33 +PNG2GR = ../gr-utils/png2gr +PNG2RLE = ../gr-utils/png2rle + +all: dlowres_mode7.dsk + +$(DOS33): + cd ../dos33fs-utils && make + +dlowres_mode7.dsk: $(DOS33) DLOWRES_MODE7 + $(DOS33) -y dlowres_mode7.dsk BSAVE -a 0x1000 DLOWRES_MODE7 + +### + +DLOWRES_MODE7: dlowres_mode7.o + ld65 -o DLOWRES_MODE7 dlowres_mode7.o -C ./apple2_1000.inc + +dlowres_mode7.o: dlowres_mode7.s \ + dlowres_flying.s fast_multiply.s \ + dlowres_utils.s dlowres_zp.inc + ca65 -o dlowres_mode7.o dlowres_mode7.s -l dlowres_mode7.lst + +clean: + rm -f *~ *.o *.lst + diff --git a/dlowres_mode7/apple2_1000.inc b/dlowres_mode7/apple2_1000.inc new file mode 100644 index 00000000..e22976de --- /dev/null +++ b/dlowres_mode7/apple2_1000.inc @@ -0,0 +1,12 @@ +MEMORY { + ZP: start = $00, size = $1A, type = rw; + RAM: start = $1000, size = $8E00, file = %O; +} + +SEGMENTS { +CODE: load = RAM, type = ro; +RODATA: load = RAM, type = ro; +DATA: load = RAM, type = rw; +BSS: load = RAM, type = bss, define = yes; +ZEROPAGE: load = ZP, type = zp; +} diff --git a/dlowres_mode7/dlowres_flying.s b/dlowres_mode7/dlowres_flying.s new file mode 100644 index 00000000..9435f8eb --- /dev/null +++ b/dlowres_mode7/dlowres_flying.s @@ -0,0 +1,1256 @@ +;=========== +; CONSTANTS +;=========== +CONST_SHIPX EQU 15 +CONST_TILE_W EQU 64 +CONST_TILE_H EQU 64 +CONST_MAP_MASK_X EQU (CONST_TILE_W - 1) +CONST_MAP_MASK_Y EQU (CONST_TILE_H - 1) +CONST_LOWRES_W EQU 40 +CONST_LOWRES_H EQU 40 +CONST_BETA_I EQU $ff +CONST_BETA_F EQU $80 +CONST_SCALE_I EQU $14 +CONST_SCALE_F EQU $00 +CONST_LOWRES_HALF_I EQU $ec ; -(LOWRES_W/2) +CONST_LOWRES_HALF_F EQU $00 + +flying_start: + + ;=================== + ; Clear screen/pages + ;=================== + + jsr clear_screens +; jsr set_gr_page0 + + ;===================== + ; Set Up Double Lowres + ;===================== + + lda SET_GR ; graphics C050 + lda LORES ; lores C056 + lda TEXTGR ; mixset C053 + sta EIGHTYSTORE_OFF ; 80store C001 + sta EIGHTYCOL ; 80col C00d + lda AN3 ; AN3 C05E + + + jsr init_multiply_tables + + ;=============== + ; Init Variables + ;=============== + lda #20 + sta SHIPY + lda #0 + sta TURNING + sta ANGLE + sta SPACEX_I + sta SPACEY_I + sta CX_I + sta CX_F + sta CY_I + sta CY_F + sta DRAW_SPLASH + sta SPEED + sta SPLASH_COUNT + + lda #1 + sta ANGLE + + lda #2 ; initialize sky both pages + sta DRAW_SKY + + lda #4 ; starts out at 4.5 + sta SPACEZ_I + lda #$80 + sta SPACEZ_F + + jsr update_z_factor + +flying_loop: + + lda SPLASH_COUNT ; 3 + beq flying_keyboard ; 2nt/3 + dec SPLASH_COUNT ; decrement splash count ; 5 + +flying_keyboard: + + jsr get_key ; get keypress ; 6 + + lda LASTKEY ; 3 + +; cmp #('Q') ; if quit, then return +; bne skipskip +; rts + +;skipskip: + + cmp #('W') ; 2 + bne check_down ; 3/2nt + + ;=========== + ; UP PRESSED + ;=========== + + lda SHIPY + cmp #17 + bcc check_down ; bgt, if shipy>16 + dec SHIPY + dec SHIPY ; move ship up + inc SPACEZ_I ; incement height + jsr update_z_factor + lda #0 + sta SPLASH_COUNT + +check_down: + cmp #('S') + bne check_left + + ;============= + ; DOWN PRESSED + ;============= + + lda SHIPY + cmp #28 + bcs splashy ; ble, if shipy < 28 + inc SHIPY + inc SHIPY ; move ship down + dec SPACEZ_I ; decrement height + jsr update_z_factor + bcc check_left + +splashy: + lda #10 + sta SPLASH_COUNT + +check_left: + cmp #('A') + bne check_right + + ;============= + ; LEFT PRESSED + ;============= + + lda TURNING + bmi turn_left + beq turn_left + + lda #$0 + sta TURNING + clv + bvc check_right + +turn_left: + lda #253 ; -3 + sta TURNING + + dec ANGLE + +check_right: + cmp #('D') + bne check_speedup + + ;============== + ; RIGHT PRESSED + ;============== + + lda TURNING ;; FIXME: optimize me + bpl turn_right + lda #0 + sta TURNING + clv + bvc check_speedup + +turn_right: + lda #3 + sta TURNING + + inc ANGLE + +check_speedup: + cmp #('Z') + bne check_speeddown + + ;========= + ; SPEED UP + ;========= + lda #$8 + cmp SPEED + beq check_speeddown + inc SPEED + +check_speeddown: + cmp #('X') + bne check_brake + + ;=========== + ; SPEED DOWN + ;=========== + + lda SPEED + beq check_brake + dec SPEED + +check_brake: + cmp #(' '+128) + bne check_land + + ;============ + ; BRAKE + ;============ + lda #$0 + sta SPEED + +check_land: + cmp #13 + bne check_help + + ;===== + ; LAND + ;===== + + ; finds value in space_x.i,space_y.i + ; returns color in A + lda CX_I + sta SPACEX_I + lda CY_I + sta SPACEY_I + + jsr lookup_map + + cmp #COLOR_BOTH_LIGHTGREEN + bne must_land_on_grass + +landing_loop: + + jsr draw_background_mode7 + + ; Draw Shadow + lda #>shadow_forward + sta INH + lda #ship_forward + sta INH + lda #(grass_string) + sta OUTH + lda #<(grass_string) + sta OUTL + + jsr print_both_pages ; "NEED TO LAND ON GRASS!" + +check_help: + cmp #('H') + bne check_done + + ;===== + ; HELP + ;===== + +; jsr print_help + + lda #2 + sta DRAW_SKY + +check_done: + + ;================ + ; Wrap the Angle + ;================ + ; FIXME: only do this in right/left routine? + lda ANGLE ; 3 + and #$f ; 2 + sta ANGLE ; 3 + + ;================ + ; Handle Movement + ;================ + +speed_move: + ldx SPEED ; 3 + beq draw_background ; 2nt/3 + ;============= + lda ANGLE ; dx.i=fixed_sin[(angle+4)&0xf].i; // cos() ; 3 + clc ; 2 + adc #4 ; 2 + and #$f ; 2 + asl ; 2 + tay ; 2 + lda fixed_sin_scale,Y ; 4 + sta DX_I ; 3 + iny ; dx.f=fixed_sin[(angle+4)&0xf].f; // cos() ; 2 + lda fixed_sin_scale,Y ; 4 + sta DX_F ; 3 + + lda ANGLE ; dy.i=fixed_sin[angle&0xf].i; // sin() ; 3 + and #$f ; 2 + asl ; 2 + tay ; 2 + lda fixed_sin_scale,Y ; 4 + sta DY_I ; 3 + iny ; dx.f=fixed_sin[angle&0xf].f; // sin() ; 2 + lda fixed_sin_scale,Y ; 4 + sta DY_F ; 3 + ;============ + ; 54 +speed_loop: + + clc ; fixed_add(&cx,&dx,&cx); ; 2 + lda CX_F ; 3 + adc DX_F ; 3 + sta CX_F ; 3 + lda CX_I ; 3 + adc DX_I ; 3 + sta CX_I ; 3 + + clc ; fixed_add(&cy,&dy,&cy); ; 2 + lda CY_F ; 3 + adc DY_F ; 3 + sta CY_F ; 3 + lda CY_I ; 3 + adc DY_I ; 3 + sta CY_I ; 3 + + dex ; 2 + bne speed_loop ; 2nt/3 + ;============ + ; 45 + + ;==================== + ; Draw the background + ;==================== +draw_background: + jsr draw_background_mode7 ; 6 + +check_over_water: + ; See if we are over water + lda CX_I ; 3 + sta SPACEX_I ; 3 + lda CY_I ; 3 + sta SPACEY_I ; 3 + + jsr lookup_map ; 6 + + sec ; 2 + sbc #COLOR_BOTH_DARKBLUE ; 2 + sta OVER_LAND ; 3 + ;=========== + ; 31 + + ; Calculate whether to draw the splash + + lda #0 ; set splash drawing to 0 ; 2 + sta DRAW_SPLASH ; 3 + + lda SPEED ; if speed==0, no splash ; 3 + beq no_splash ; 2nt/3 + + lda TURNING ; 3 + beq no_turning_splash ; 2nt/3 + + lda SHIPY ; 3 + cmp #27 ; 2 + bcc no_turning_splash ; blt if shipy<25 skip ; 2nt/3 + + lda #1 ; 2 + sta SPLASH_COUNT ; 3 + +no_turning_splash: + lda OVER_LAND ; no splash if over land ; 3 + bne no_splash ; 2nt/3 + + lda SPLASH_COUNT ; no splash if splash_count expired ; 3 + beq no_splash ; 2nt/3 + + lda #1 ; 2 + sta DRAW_SPLASH ; 3 + +no_splash: + + ;============== + ; Draw the ship + ;============== + + clv ; 2 + lda TURNING ; 3 + beq draw_ship_forward ; 2nt/3 + bpl draw_ship_right ; 2nt/3 + bmi draw_ship_left ;; FIXME: optimize order ; 2nt/3 + +draw_ship_forward: + lda DRAW_SPLASH ; 2 + beq no_forward_splash ; 2nt/3 + + ; Draw Splash + lda #>splash_forward ; 2 + sta INH ; 3 + lda #shadow_forward ; 2 + sta INH ; 3 + lda #ship_forward ; 2 + sta INH ; 3 + lda #splash_right ; 2 + sta INH ; 3 + lda #shadow_right ; 2 + sta INH ; 3 + lda #ship_right ; 2 + sta INH ; 3 + lda #splash_left ; 2 + sta INH ; 3 + lda #shadow_left ; 2 + sta INH ; 3 + lda #ship_left ; 2 + sta INH ; 3 + lda #((I*I)/4) +; square2_lo = <(((I-255)*(I-255))/4) +; square2_hi = >(((I-255)*(I-255))/4) + +; Note: DOS3.3 starts at $9600 + +square1_lo EQU $8E00 +square1_hi EQU $9000 +square2_lo EQU $9200 +square2_hi EQU $9400 + +; for(i=0;i<512;i++) { +; square1_lo[i]=((i*i)/4)&0xff; +; square1_hi[i]=(((i*i)/4)>>8)&0xff; +; square2_lo[i]=( ((i-255)*(i-255))/4)&0xff; +; square2_hi[i]=(( ((i-255)*(i-255))/4)>>8)&0xff; +; } + +init_multiply_tables: + + ; Build the add tables + + ldx #$00 + txa + .byte $c9 ; CMP #immediate - skip TYA and clear carry flag +lb1: tya + adc #$00 ; 0 +ml1: sta square1_hi,x ; square1_hi[0]=0 + tay ; y=0 + cmp #$40 ; subtract 64 and update flags (c=0) + txa ; a=0 + ror ; rotate +ml9: adc #$00 ; add 0 + sta ml9+1 ; update add value + inx ; x=1 +ml0: sta square1_lo,x ; square1_lo[0]=1 + bne lb1 ; if not zero, loop + inc ml0+2 ; increment values + inc ml1+2 ; increment values + clc ; c=0 + iny ; y=1 + bne lb1 ; loop + + ; Build the subtract tables based on the existing one + + ldx #$00 + ldy #$ff +second_table: + lda square1_hi+1,x + sta square2_hi+$100,x + lda square1_hi,x + sta square2_hi,y + lda square1_lo+1,x + sta square2_lo+$100,x + lda square1_lo,x + sta square2_lo,y + dey + inx + bne second_table + + + rts + + +; Fast 16x16 bit unsigned multiplication, 32-bit result +; Input: NUM1H:NUM1L * NUM2H:NUM2L +; Result: RESULT3:RESULT2:RESULT1:RESULT0 +; +; Does self-modifying code to hard-code NUM1H:NUM1L into the code +; carry=0: re-use previous NUM1H:NUM1L +; carry=1: reload NUM1H:NUM1L (58 cycles slower) +; +; clobbered: RESULT, X, A, C +; Allocation setup: T1,T2 and RESULT preferably on Zero-page. +; +; NUM1H (x_i), NUM1L (x_f) +; NUM2H (y_i), NUM2L (y_f) + +; NUM1L * NUM2L = AAaa +; NUM1L * NUM2H = BBbb +; NUM1H * NUM2L = CCcc +; NUM1H * NUM2H = DDdd +; +; AAaa +; BBbb +; CCcc +; + DDdd +; ---------- +; RESULT + +;fixed_16x16_mul_unsigned: + +multiply: + + bcc num1_same_as_last_time ; 2nt/3 + + ;============================ + ; Set up self-modifying code + ; this changes the code to be hard-coded to multiply by NUM1H:NUM1L + ;============================ + + lda NUM1L ; load the low byte ; 3 + sta sm1a+1 ; 3 + sta sm3a+1 ; 3 + sta sm5a+1 ; 3 + sta sm7a+1 ; 3 + eor #$ff ; invert the bits for subtracting ; 2 + sta sm2a+1 ; 3 + sta sm4a+1 ; 3 + sta sm6a+1 ; 3 + sta sm8a+1 ; 3 + lda NUM1H ; load the high byte ; 3 + sta sm1b+1 ; 3 + sta sm3b+1 ; 3 + sta sm5b+1 ; 3 +; sta sm7b+1 ; + eor #$ff ; invert the bits for subtractin ; 2 + sta sm2b+1 ; 3 + sta sm4b+1 ; 3 + sta sm6b+1 ; 3 +; sta sm8b+1 ; + ;=========== + ; 52 + +num1_same_as_last_time: + + ;========================== + ; Perform NUM1L * NUM2L = AAaa + ;========================== + + ldx NUM2L ; (low le) ; 3 + sec ; 2 +sm1a: + lda square1_lo,x ; 4 +sm2a: + sbc square2_lo,x ; 4 + + ; a is _aa + +; sta RESULT+0 ; + +sm3a: + lda square1_hi,x ; 4 +sm4a: + sbc square2_hi,x ; 4 + ; a is _AA + sta _AA+1 ; 3 + ;=========== + ; 24 + + ; Perform NUM1H * NUM2L = CCcc + sec ; 2 +sm1b: + lda square1_lo,x ; 4 +sm2b: + sbc square2_lo,x ; 4 + ; a is _cc + sta _cc+1 ; 3 +sm3b: + lda square1_hi,x ; 4 +sm4b: + sbc square2_hi,x ; 4 + ; a is _CC + sta _CC+1 ; 3 + ;=========== + ; 24 + + ;========================== + ; Perform NUM1L * NUM2H = BBbb + ;========================== + ldx NUM2H ; 3 + sec ; 2 +sm5a: + lda square1_lo,x ; 4 +sm6a: + sbc square2_lo,x ; 4 + ; a is _bb + sta _bb+1 ; 3 + +sm7a: + lda square1_hi,x ; 4 +sm8a: + sbc square2_hi,x ; 4 + ; a is _BB + sta _BB+1 ; 3 + ;=========== + ; 27 + + ;========================== + ; Perform NUM1H * NUM2H = DDdd + ;========================== + sec ; 2 +sm5b: + lda square1_lo,x ; 4 +sm6b: + sbc square2_lo,x ; 4 + ; a is _dd + sta _dd+1 ; 3 +;sm7b: +; lda square1_hi,x ; +;sm8b: +; sbc square2_hi,x ; + ; a = _DD +; sta RESULT+3 ; + ;=========== + ; 13 + + ;=========================================== + ; Add the separate multiplications together + ;=========================================== + + clc ; 2 +_AA: + lda #0 ; loading _AA ; 2 +_bb: + adc #0 ; adding in _bb ; 2 + sta RESULT+1 ; 3 + ;========== + ; 9 + ; product[2]=_BB+_CC+c + +_BB: + lda #0 ; loading _BB ; 2 +_CC: + adc #0 ; adding in _CC ; 2 + sta RESULT+2 ; 3 + ;=========== + ; 7 + + ; product[3]=_DD+c + +; bcc dd_no_carry1 ; +; inc RESULT+3 ; + clc ; 2 + ;============= + ; 2 +dd_no_carry1: + + ; product[1]=_AA+_bb+_cc + +_cc: + lda #0 ; load _cc ; 2 + adc RESULT+1 ; 3 + sta RESULT+1 ; 3 + + ; product[2]=_BB+_CC+_dd+c + +_dd: + lda #0 ; load _dd ; 2 + adc RESULT+2 ; 3 + sta RESULT+2 ; 3 + + ;=========== + ; 16 + ; product[3]=_DD+c + + +; bcc dd_no_carry2 ; +; inc RESULT+3 ; + + ;============= + ; 0 + +dd_no_carry2: + +; *z_i=product[1]; +; *z_f=product[0]; + +; rts ; 6 + + + ;================= + ; Signed multiply + ;================= + +;multiply: + +; jsr fixed_16x16_mul_unsigned ; 6 + + lda NUM1H ; x_i ; 3 + ;=========== + ; 12 + + + bpl x_positive ;^3/2nt + + sec ; 2 + lda RESULT+2 ; 3 + sbc NUM2L ; 3 + sta RESULT+2 ; 3 +; lda RESULT+3 ; +; sbc NUM2H ; +; sta RESULT+3 ; + ;============ + ; 10 + +x_positive: + + lda NUM2H ; y_i ; 3 + ;============ + ; ; 6 + + bpl y_positive ;^3/2nt + + + sec ; 2 + lda RESULT+2 ; 3 + sbc NUM1L ; 3 + sta RESULT+2 ; 3 +; lda RESULT+3 ; +; sbc NUM1H ; +; sta RESULT+3 ; + ;=========== + ; 10 + +y_positive: + ldx RESULT+2 ; *z_i=product[2]; ; 3 + lda RESULT+1 ; *z_f=product[1]; ; 3 + + rts ; 6 + ;========== + ; 12 +