From 3814ca6f8598342c2cda4f8ffec09f75c0b1d932 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Sun, 13 Dec 2020 19:49:00 -0500 Subject: [PATCH] duke: hook in title screen --- duke/Makefile | 20 +- duke/common_defines.inc | 3 + duke/duke_title.s | 251 ++++++++++++++ duke/hello.bas | 15 +- duke/loader.s | 702 ++++++++++++++++++++++++++++++++++++++++ duke/wait_a_bit.s | 27 ++ 6 files changed, 1014 insertions(+), 4 deletions(-) create mode 100644 duke/common_defines.inc create mode 100644 duke/duke_title.s create mode 100644 duke/loader.s create mode 100644 duke/wait_a_bit.s diff --git a/duke/Makefile b/duke/Makefile index 3a46f038..a321c6aa 100644 --- a/duke/Makefile +++ b/duke/Makefile @@ -8,11 +8,12 @@ LZSA = ~/research/lzsa/lzsa/lzsa all: duke.dsk -duke.dsk: HELLO DUKE +duke.dsk: HELLO LOADER DUKE_TITLE DUKE cp empty.dsk duke.dsk $(DOS33) -y duke.dsk SAVE A HELLO + $(DOS33) -y duke.dsk BSAVE -a 0x1000 LOADER $(DOS33) -y duke.dsk BSAVE -a 0x2000 DUKE - $(DOS33) -y duke.dsk BSAVE -a 0x4000 ./title/NEW_TITLEC.BIN TITLE + $(DOS33) -y duke.dsk BSAVE -a 0x4000 DUKE_TITLE ### @@ -21,6 +22,21 @@ HELLO: hello.bas #### +LOADER: loader.o + ld65 -o LOADER loader.o -C ../linker_scripts/apple2_1000.inc + +loader.o: loader.s + ca65 -o loader.o loader.s -l loader.lst + +#### + +DUKE_TITLE: duke_title.o + ld65 -o DUKE_TITLE duke_title.o -C ../linker_scripts/apple2_4000.inc + +duke_title.o: duke_title.s zp.inc hardware.inc + ca65 -o duke_title.o duke_title.s -l duke_title.lst + +#### DUKE: duke.o ld65 -o DUKE duke.o -C ../linker_scripts/apple2_2000.inc diff --git a/duke/common_defines.inc b/duke/common_defines.inc new file mode 100644 index 00000000..742f7361 --- /dev/null +++ b/duke/common_defines.inc @@ -0,0 +1,3 @@ +LOAD_TITLE = 0 +LOAD_DUKE1 = 1 + diff --git a/duke/duke_title.s b/duke/duke_title.s new file mode 100644 index 00000000..87b597d3 --- /dev/null +++ b/duke/duke_title.s @@ -0,0 +1,251 @@ +; Duke Title + +; loads a HGR version of the title + +; by deater (Vince Weaver) + +; Zero Page + .include "zp.inc" + .include "hardware.inc" + .include "common_defines.inc" + +duke_title_start: + ;=================== + ; init screen + ;=================== + + jsr TEXT + jsr HOME + bit KEYRESET + + bit SET_GR + bit PAGE0 + bit HIRES + bit FULLGR + + ;=================== + ; machine workarounds + ;=================== + ; mostly IIgs + ;=================== + ; thanks to 4am who provided this code from Total Replay + + lda ROM_MACHINEID + cmp #$06 + bne not_a_iigs + sec + jsr $FE1F ; check for IIgs + bcs not_a_iigs + + ; gr/text page2 handling broken on early IIgs models + ; this enables the workaround + + jsr ROM_TEXT2COPY ; set alternate display mode on IIgs + cli ; enable VBL interrupts + + ; also set background color to black instead of blue + lda NEWVIDEO + and #%00011111 ; bit 7 = 0 -> IIgs Apple II-compat video modes + ; bit 6 = 0 -> IIgs 128K memory map same as IIe + ; bit 5 = 0 -> IIgs DHGR is color, not mono + ; bits 0-4 unchanged + sta NEWVIDEO + lda #$F0 + sta TBCOLOR ; white text on black background + lda #$00 + sta CLOCKCTL ; black border + sta CLOCKCTL ; set twice for VidHD + +not_a_iigs: + + ;=================== + ; Load hires graphics + ;=================== +reload_everything: + + lda #new_title + sta getsrc_smc+2 ; LZSA_SRC_HI + + lda #$20 + + jsr decompress_lzsa2_fast + + ;=================================== + ; detect if we have a language card + ; and load sound into it if possible + ;=================================== + +; lda #0 +; sta SOUND_STATUS ; clear out, sound enabled + +; jsr detect_language_card +; bcs no_language_card + + ; update sound status +; lda SOUND_STATUS +; ora #SOUND_IN_LC +; sta SOUND_STATUS + + ; load sounds into LC + + ; read ram, write ram, use $d000 bank1 +; bit $C08B +; bit $C08B + +; lda #linking_noise_compressed +; sta getsrc_smc+2 + +; lda #$D0 ; decompress to $D000 + +; jsr decompress_lzsa2_fast + +;blah: + + ; read rom, nowrite, use $d000 bank1 +; bit $C08A + +no_language_card: + + ;=================================== + ; Setup Mockingboard + ;=================================== +; lda #0 +; sta DONE_PLAYING +; sta LOOP + + ; detect mockingboard +; jsr mockingboard_detect + +; bcc mockingboard_notfound + +mockingboard_found: +;; jsr mockingboard_patch ; patch to work in slots other than 4? + +; lda SOUND_STATUS +; ora #SOUND_MOCKINGBOARD +; sta SOUND_STATUS + + ;======================= + ; Set up 50Hz interrupt + ;======================== + +; jsr mockingboard_init +; jsr mockingboard_setup_interrupt + + ;============================ + ; Init the Mockingboard + ;============================ + +; jsr reset_ay_both +; jsr clear_ay_both + + ;================== + ; init song + ;================== + +; jsr pt3_init_song + +; jmp done_setup_sound + + +mockingboard_notfound: + + +done_setup_sound: + + + + ;=================================== + ; Do Intro Sequence + ;=================================== + + ; wait a bit at LOAD screen + + lda #100 + jsr wait_a_bit + + +done_intro: + + ; restore to full screen (no text) + + bit FULLGR + bit LORES + + ;============================ + ; init vars + +; jsr init_state + + ;============================ + ; set up initial location + + lda #LOAD_DUKE1 + sta WHICH_LOAD ; start at first level + + rts + + + ;========================== + ; includes + ;========================== + + .include "gr_pageflip.s" + .include "gr_copy.s" + .include "wait_a_bit.s" + .include "gr_offsets.s" + .include "decompress_fast_v2.s" + +; .include "init_state.s" +; .include "graphics_title/title_graphics.inc" +; .include "lc_detect.s" + + + ; pt3 player +; .include "pt3_lib_core.s" +; .include "pt3_lib_init.s" +; .include "interrupt_handler.s" +; .include "pt3_lib_mockingboard_detect.s" +; .include "pt3_lib_mockingboard_setup.s" + + +; .include "wait_a_bit.s" + + +new_title: +.incbin "title/new_title.lzsa" + + + ;==================================== + ; draw a screen and wait + ;==================================== + ; X = low of lzsa + ; Y = high of lzsa + ; A = pause delay + +draw_and_wait: + pha + stx getsrc_smc+1 + sty getsrc_smc+2 + lda #$c ; load to page $c00 + jsr decompress_lzsa2_fast + + jsr gr_copy_to_current + + jsr page_flip + pla + jsr wait_a_bit + rts + + + +;PT3_LOC = theme_music + +;.align $100 +;theme_music: +;.incbin "audio/theme.pt3" + diff --git a/duke/hello.bas b/duke/hello.bas index 145ea099..755f70fe 100644 --- a/duke/hello.bas +++ b/duke/hello.bas @@ -1,4 +1,15 @@ 5 HOME 10 PRINT "LOADING DUKE V0.02" -20 PRINT:PRINT -30 PRINT CHR$(4);"BRUN DUKE" +20 PRINT " DUKE NUKEM PROOF-OF-CONCEPT DEMAKE" +30 PRINT:PRINT +70 PRINT "BASED ON DUKE NUKEM1 BY APOGEE" +80 PRINT "APPLE II PORT: VINCE WEAVER" +90 PRINT "DISK CODE : QKUMBA" +94 PRINT "LZSA CODE : EMMANUEL MARTY" +95 PRINT +100 PRINT " ______" +110 PRINT " A \/\/\/ SOFTWARE PRODUCTION" +115 PRINT +120 PRINT " HTTP://WWW.DEATER.NET/WEAVE/VMWPROD" +130 PRINT CHR$(4);"BRUN LOADER" + diff --git a/duke/loader.s b/duke/loader.s new file mode 100644 index 00000000..30a9b3a4 --- /dev/null +++ b/duke/loader.s @@ -0,0 +1,702 @@ +; Loader for DUKE + +.include "zp.inc" +.include "hardware.inc" +.include "common_defines.inc" + +nibtbl = $300 ; nothing uses the bottom 128 bytes of $300, do they? +bit2tbl = $380 ; bit2tbl: .res 86 ; = nibtbl+128 +filbuf = $3D6 ; filbuf: .res 4 ; = bit2tbl+86 + +; read any file slot 6 version +; based on FASTLD6 and RTS copyright (c) Peter Ferrie 2011-2013,2018 + +; modified to assembled with ca65 -- vmw +; added code to patch it to run from current disk slot -- vmw + +; WHICH_LOAD = $7E ; thing to load +; adrlo = $26 ; constant from boot prom +; adrhi = $27 ; constant from boot prom +; tmpsec = $3c ; constant from boot prom +; reqsec = $3d ; constant from boot prom +; sizelo = $44 +; sizehi = $45 +; secsize = $46 +; namlo = $f8 +; namhi = $f9 +; TEMPY = $fa +; step = $fd ; state for stepper motor +; tmptrk = $fe ; temporary copy of current track +; phase = $ff ; current phase for /seek +; OUTL = $fe ; for picking filename +; OUTH = $ff + + dirbuf = $c00 + ; note, don't put this immediately below + ; the value being read as destaddr-4 + ; is temporarily overwritten during read + ; process + + + FILENAME = $280 + + ;=================================================== + ;=================================================== + ; START / INIT + ;=================================================== + ;=================================================== + +loader_start: + + lda #LOAD_TITLE + sta WHICH_LOAD + + jsr init ; unhook DOS, init nibble table + + + ;=================================================== + ;=================================================== + ; SETUP THE FILENAME + ;=================================================== + ;=================================================== + +which_load_loop: + + + + ; update the which-file error message +; lda WHICH_LOAD +; tay +; lda which_disk,Y +; sta error_string+19 + + lda WHICH_LOAD + asl + + tay + lda filenames,Y + sta OUTL + lda filenames+1,Y + sta OUTH + + lda WHICH_LOAD + bne load_other + +load_intro: + lda #<$4000 + sta entry_smc+1 + lda #>$4000 + sta entry_smc+2 + jmp actual_load + +load_other: + lda #<$2000 + sta entry_smc+1 + lda #>$2000 + sta entry_smc+2 + +actual_load: + + ;=================================================== + ;=================================================== + ; SET UP DOS3.3 FILENAME + ;=================================================== + ;=================================================== + +load_file_and_execute: + + jsr opendir_filename + +entry_smc: + jsr $1000 ; jump to common entry point + + ; hope they updated the WHICH_LOAD value + + jmp which_load_loop + + + ;============================== + ; setup filename then open/load + +opendir_filename: + + ; clear out the filename with $A0 (space) + + lda #FILENAME + sta namhi + + ldy #29 +wipe_filename_loop: + lda #$A0 + sta (namlo),Y + dey + bpl wipe_filename_loop + + ldy #0 +copy_filename_loop: + lda (OUTL),Y + beq copy_filename_done + ora #$80 + sta (namlo),Y + iny + bne copy_filename_loop + +copy_filename_done: + jsr opendir ; open and read entire file into memory + + rts + +filenames: + .word intro_filename + .word duke1_filename + +intro_filename: + .byte "DUKE_TITLE",0 +duke1_filename: + .byte "DUKE",0 + + + ;=================================================== + ;=================================================== + ; INIT (build nibble table) + ;=================================================== + ;=================================================== + + ;unhook DOS and build nibble table + +init: + ; patch to use current drive + + ; locate input paramater list + jsr $3E3 + ; result is in A:Y + sta $FF + sty $FE + ldy #1 + lda ($FE),y + + ; list+1 should have slot<<8 + + + ora #$80 ; add in $80 + + ; c0e0 + sta mlsmc06+1 + + ; c0e8 + clc + adc #8 + sta mlsmc02+1 + sta mlsmc07+1 + + ; c0e9 + clc + adc #1 + sta mlsmc01+1 + + ; c0ec + clc + adc #3 + sta mlsmc03+1 + sta mlsmc04+1 + sta mlsmc05+1 + + jsr $fe93 ; clear COUT + jsr $fe89 ; clear KEYIN + + ;======================== + ; Create nibble table + ; Note: the table starts 16 bytes in, and is sparse + ; so it doesn't entirely look like the DOS33 table at + + ldy #0 + ldx #3 +L1: stx $3c ; store tempx (3?) + txa ; a=x (a=3) + asl ; a*=2 (a=6) + bit $3c ; a&tempx, set N/V (a=6) + beq L3 ; if 0, skip to L3 + ora $3c ; a|=tempx (a=7) + eor #$ff ; a=~a (a=f8) + and #$7e ; a&=0x7e 0111 1110 (a=78) +L2: bcs L3 ; this set way back at asl?? + lsr ; a>>1 a=3c c=0 + ; a=1e c=0 + ; a=0f c=0 + ; a=07 c=1 + bne L2 ; if a!=0 goto l2 + tya ; if a==0, a=y + sta nibtbl, x ; write out to table + iny ; increment y +L3: inx ; increment x x=4, a=0f + bpl L1 ; loop while high bit not set + + rts + + + ;=================================================== + ;=================================================== + ; file not found + ;=================================================== + ;=================================================== + +file_not_found: + +mlsmc07:lda $c0e8 ; turn off drive motor? + + jsr TEXT + jsr HOME + + ldy #0 + + lda #error_string + sta OUTH + +quick_print: + lda (OUTL),Y + beq quick_print_done + jsr COUT1 + iny + jmp quick_print + +quick_print_done: +; rts + +; jsr quick_print + +fnf_keypress: + lda KEYPRESS + bpl fnf_keypress + bit KEYRESET + + jmp which_load_loop + +; offset for disk number is 19 +error_string: +.byte "PLEASE INSERT DISK 1, PRESS RETURN",0 + + + + + + ;=================================================== + ;=================================================== + ; OPENDIR: actually load the file + ;=================================================== + ;=================================================== + + ; turn on drive and read volume table of contents +opendir: +mlsmc01:lda $c0e9 ; turn slot#6 drive on + ldx #0 + stx adrlo ; zero out adrlo + stx secsize ; zero out secsize + lda #$11 ; a=$11 (VTOC) + jsr readdirsec +firstent: + + lda dirbuf+1 + + ; lock if entry not found +entry_not_found: + beq file_not_found + + ; read directory sector + + ldx dirbuf+2 + jsr seekread1 + ldy #7 ;number of directory entries in a sector + ldx #$2b ;offset of filename in directory entry +nextent: + tya + pha ; was **phy** + txa + pha ; was **phx** + ldy #$1d + + ; match name backwards (slower but smaller) + +L4: + lda (namlo), y + cmp dirbuf, x + beq foundname + pla + + ; move to next directory in this block, if possible + + clc + adc #$23 + tax + pla + tay ; was **ply** + dey + bne nextent + beq firstent ; was **bra** + +foundname: + dex + dey + bpl L4 + pla + tay ; was **ply** + pla + + ; read track/sector list + + lda dirbuf-32, y + ldx dirbuf-31, y + jsr seekread1 + + ; read load offset and length info only, initially + + lda #filbuf + jsr seekread + + ; reduce load offset by 4, to account for offset and length + + sec + lda filbuf + sbc #4 + sta adrlo + + lda filbuf+1 + sbc #0 + sta adrhi + + ; save on stack bytes that will be overwritten by extra read + + ldy #3 +L5: + lda (adrlo), y + pha + dey + bpl L5 + + lda adrhi + pha + lda adrlo + pha + + ; increase load size by 4, to account for offst and length + + lda filbuf+2 + adc #3 + sta sizelo + sta secsize + + lda filbuf+3 + adc #0 + sta sizehi + beq readfirst + lda #0 ; was **stz secsize** + sta secsize + +readfirst: + ldy #$0c + + ; read a file sector + +readnext: + tya + pha + lda dirbuf, y ; A = track + ldx dirbuf+1, y ; x = sector + jsr seekread1 + pla + tay + + ; if low count is non-zero then we are done + ; (can happen only for partial last block) + + lda secsize + bne readdone + + ; continue if more than $100 bytes left + + dec sizehi + bne L6 + + ; set read size to min(length, $100) + + lda sizelo + beq readdone + sta secsize +L6: + inc adrhi + iny + iny + bne readnext + + ; save current address for after t/s read + + lda adrhi + pha + lda adrlo + pha + lda #0 + sta adrlo ; was **stz adrlo** + + ; read next track/sector sector + + lda dirbuf+1 + ldx dirbuf+2 + jsr readdirsec + clc + + ; restore current address +readdone: + pla + sta adrlo ; code originally had this backwards + pla + sta adrhi + bcc readfirst + +mlsmc02:lda $c0e8 + + ; restore from stack bytes that were overwritten by extra read + + ldx #3 + ldy #0 +L7: + pla + sta (adrlo), y + iny + dex + bpl L7 + rts + + + ;====================== + ; readdirsec + ;====================== + ; a = track? + ; x = sector? +readdirsec: + ldy #>dirbuf +seekread: + sty adrhi +seekread1: + sta phase + lda sectbl, x + sta reqsec + jsr readadr + + ; if track does not match, then seek + + cpx phase + beq checksec + jsr seek + + + ;========================================= + ; re merge in with qkumba's recent changes + ; to fix seek problem? + ;========================================= + + ; [re-]read sector + +re_read_addr: + jsr readadr +checksec: + cmp reqsec + bne re_read_addr + + ;========================= + ; read sector data + ;========================= + +readdata: + jsr readd5aa + eor #$ad ; zero A if match + bne re_read_addr + +L12: +mlsmc03:ldx $c0ec ; read until valid data (high bit set) + bpl L12 + eor nibtbl-$80, x + sta bit2tbl-$aa, y + iny + bne L12 +L13: +mlsmc04:ldx $c0ec ; read until valid data (high bit set) + bpl L13 + eor nibtbl-$80, x + sta (adrlo), y ; the real address + iny + cpy secsize + bne L13 + ldy #0 +L14: + ldx #$a9 +L15: + inx + beq L14 + lda (adrlo), y + lsr bit2tbl-$aa, x + rol + lsr bit2tbl-$aa, x + rol + sta (adrlo), y + iny + cpy secsize + bne L15 + rts + + ; no tricks here, just the regular stuff + + ;======================= + ; readaddr -- read the address field + ;======================= + ; Find address field, put track in cutrk, sector in tmpsec + +readadr: + jsr readd5aa + cmp #$96 + bne readadr + ldy #3 ; three? + ; first read volume/volume + ; then track/track + ; then sector/sector? +adr_read_two_bytes: + tax + jsr readnib + rol + sta tmpsec + jsr readnib + and tmpsec + dey + bne adr_read_two_bytes + rts + + ;======================== + ; make sure we see the $D5 $AA pattern + +readd5aa: +L16: + jsr readnib +L17: + cmp #$d5 + bne L16 + jsr readnib + cmp #$aa + bne L17 + tay ; we need Y=#$AA later + +readnib: +mlsmc05:lda $c0ec ; read until valid (high bit set) + bpl readnib + +seekret: + rts + + ;===================== + ; SEEK + ;===================== + ; current track in X? + ; desired track in phase + +seek: + ldy #0 + sty step + asl phase ; multiply by two + txa ; current track? + asl ; mul by two +copy_cur: + tax + sta tmptrk + sec + sbc phase + beq L22 + bcs L18 + eor #$ff + inx + bcc L19 +L18: + sbc #1 + dex +L19: + cmp step + bcc L20 + lda step +L20: + cmp #8 + bcs L21 + tay + sec +L21: + txa + pha + ldx step1, y +L22: + php + bne L24 +L23: + clc + lda tmptrk + ldx step2, y +L24: + stx tmpsec + and #3 + rol + tax + lsr +mlsmc06:lda $c0e0, x +L25: + ldx #$12 +L26: + dex + bpl L26 + dec tmpsec + bne L25 + bcs L23 + plp + beq seekret + pla + inc step + bne copy_cur + + + +step1: .byte $01, $30, $28, $24, $20, $1e, $1d, $1c +step2: .byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c + +sectbl: .byte $00,$0d,$0b,$09,$07,$05,$03,$01,$0e,$0c,$0a,$08,$06,$04,$02,$0f + + +; From $BA96 of DOS33 +;nibtbl: .res 128 ; = * +; .byte $00,$01,$98,$99,$02,$03,$9C,$04 ; $BA96 ; 00 +; .byte $05,$06,$A0,$A1,$A2,$A4,$A4,$A5 ; $BA9E ; 08 +; .byte $07,$08,$A8,$A9,$AA,$09,$0A,$0B ; $BAA6 ; 10 +; .byte $0C,$0D,$B0,$B1,$0E,$0F,$10,$11 ; $BAAE ; 18 +; .byte $12,$13,$B8,$14,$15,$16,$17,$18 ; $BAB6 ; 20 +; .byte $19,$1A,$C0,$C1,$C2,$C3,$C4,$C5 ; $BABE ; 28 +; .byte $C6,$C7,$C8,$C9,$CA,$1B,$CC,$1C ; $BAC6 ; 30 +; .byte $1D,$1E,$D0,$D1,$D2,$1E,$D4,$D5 ; $BACE ; 38 +; .byte $20,$21,$D8,$22,$23,$24,$25,$26 ; $BAD6 ; 40 +; .byte $27,$28,$E0,$E1,$E2,$E3,$E4,$29 ; $BADE ; 48 +; .byte $2A,$2B,$E8,$2C,$2D,$2E,$2F,$30 ; $BAE6 ; 50 +; .byte $31,$32,$F0,$F1,$33,$34,$35,$36 ; $BAEE ; 58 +; .byte $37,$38,$F8,$39,$3A,$3B,$3C,$3D ; $BAF6 ; 60 +; .byte $3E,$3F,$13,$00,$01,$02,$01,$00 ; $BAFE ; 68 +; .byte $00,$00,$00,$00,$00,$00,$00,$00 +; .byte $00,$00,$00,$00,$00,$00,$00,$00 + + +;bit2tbl: .res 86 ; = nibtbl+128 +;filbuf: .res 4 ; = bit2tbl+86 + ;dataend = filbuf+4 + +loader_end: + +.assert (16, error, "loader too big" diff --git a/duke/wait_a_bit.s b/duke/wait_a_bit.s new file mode 100644 index 00000000..f71370ad --- /dev/null +++ b/duke/wait_a_bit.s @@ -0,0 +1,27 @@ + ;==================================== + ; wait for keypress or a few seconds + ;==================================== + +wait_a_bit: + + bit KEYRESET + tax + +keyloop: + lda #200 ; delay a bit + jsr WAIT + + lda KEYPRESS + bmi done_keyloop + +; bmi keypress_exit + + dex + bne keyloop + +done_keyloop: + + bit KEYRESET + + rts +