; adfreader.asm - essential functionality for game disk installers. ; Supports Amiga Disk Files instead of trackdisk ; © 1998-1999 Kyzer/CSG IFND FILEMODE FILEMODE=0 ENDC IFND MESSAGES MESSAGES=0 ENDC IFD NO_INCLUDES MODE_OLDFILE=1005 ; from dos/dos.i MODE_NEWFILE=1006 OFFSET_BEGINNING=-1 ERROR_NOT_A_DOS_DISK=225 _LVOOpen=-30 ; from dos/dos_lib.i _LVOClose=-36 _LVORead=-42 _LVOWrite=-48 _LVOSeek=-66 _LVOIoErr=-132 _LVOSetIoErr=-462 _LVOPrintFault=-474 _LVOReadArgs=-798 _LVOFreeArgs=-858 _LVOPutStr=-948 _LVOVPrintf=-954 _LVOCloseLibrary=-414 ; from exec/exec_lib.i _LVODoIO=-456 _LVOOpenLibrary=-552 ELSE include dos/dos.i include dos/dos_lib.i include exec/exec_lib.i ENDC DOSTRACKLEN=512*11 BUFFER MACRO ; buffername \1 equ __trk ENDM FAILURE MACRO ; [reason] IFEQ NARG suba.l a0,a0 ELSE lea \1,a0 ENDC bra __fail ENDM RAWREAD MACRO ; track lea __trk,a0 move.l \1,d0 bsr __rawrd ENDM RESYNC MACRO ; wordsync lea __trk,a0 move.l \1,d0 bsr __sync ENDM DOSREAD MACRO ; track lea __trk,a0 move.l \1,d0 bsr __dosrd ENDM IFEQ FILEMODE WRITE MACRO ; length, [offset] IFEQ NARG-2 lea __trk,a0 add.l \2,a0 ELSE lea __trk,a0 ENDC move.l \1,d0 bsr __write ENDM WRITEDOS MACRO ; track DOSREAD \1 WRITE #DOSTRACKLEN ENDM ELSE SAVEF MACRO ; filename, buffer, length lea \1,a0 lea \2,a1 move.l \3,d0 bsr __savef ENDM ENDC ;------------------------------------ call macro jsr _LVO\1(a6) endm initstk macro ; stack_symbol, stackreg link \2,#\1 move.l sp,a0 .clr\@ clr.w (a0)+ cmp.l a0,\2 bne.s .clr\@ endm stackf MACRO ; stack_symbol, stackelement_symbol, [size=4] IFND \1 \1 set 0 ENDC IFGE NARG-3 \1 set \1-(\3) ELSE \1 set \1-4 ENDC \2 equ \1 ENDM IFNE FILEMODE stackf stk, __adfname __args=__adfname __nargs=1 __tmpl macro dc.b 'ADF/A',0 endm ELSE stackf stk, __output stackf stk, __adfname __args=__adfname __nargs=2 __tmpl macro dc.b 'ADF/A,OUTPUT/A',0 endm ENDC stackf stk, __rdargs ; returned by ReadArgs() stackf stk, __adffh ; input filehandle stackf stk, __outfh ; output filehandle (NULL in filemode) stackf stk, __initsp ; initial (sp): move to sp then rts to quit stackf stk, __reason ; ptr to textual reason for failure, or NULL stackf stk, execbase ; exec.library stackf stk, dosbase ; dos.library stackf stk, __sltab, 160*4 ; sync and length table stackf stk, __otab, 160*4 ; offset table section diskreader,code link a5,#stk move.l 4.w,a6 move.l a6,execbase(a5) suba.l a1,a1 jsr -$126(a6) move.l d0,a0 lea $94(a0),a0 clr.l __reason(a5) moveq #100,d7 moveq #37,d0 lea __dosnm(pc),a1 call OpenLibrary move.l d0,dosbase(a5) beq .nodos move.l d0,a6 lea __templ(pc),a0 move.l a0,d1 lea __args(a5),a0 move.l a0,d2 REPT __nargs clr.l (a0)+ ENDR moveq #0,d3 call ReadArgs move.l d0,__rdargs(a5) beq .noargs IFEQ FILEMODE move.l __output(a5),d1 move.l #MODE_NEWFILE,d2 call Open move.l d0,__outfh(a5) beq .nofile ENDC ; open ADF file move.l __adfname(a5),d1 move.l #MODE_OLDFILE,d2 call Open move.l d0,__adffh(a5) beq .noadf move.l d0,d4 lea __sltab(a5),a2 ; check ADF header move.l d4,d1 move.l a2,d2 moveq #8,d3 call Read tst.l d0 bmi.s .notadf cmp.l #"UAE-",(a2) bne.s .notext cmp.l #"-ADF",4(a2) bne.s .notext ; read sync/len table move.l d4,d1 move.l a2,d2 move.l #160*4,d3 call Read tst.l d0 bmi.s .notadf ; fill offsets table lea (8+160*4).w,a0 ; track 0 data immediately follows table/header lea __otab(a5),a1 move.w #160-1,d0 moveq #0,d1 .loop move.l a0,(a1)+ ; put offset move.l (a2)+,d1 adda.w d1,a0 ; add length of track to offset dbra d0,.loop bra.s .begin .notext lea DOSTRACKLEN.w,a3 ; also support DOS-only ADFs lea __otab(a5),a1 move.w #160-1,d0 .loop2 move.l a3,(a2)+ ; sync=$0000, length=DOSTRACKLEN move.l a0,(a1)+ ; put offset add.l a3,a0 dbra d0,.loop2 .begin bsr __main move.l dosbase(a5),a6 IFNE MESSAGES pea 10<<24 move.l sp,d1 call PutStr ; print a newline addq.l #4,sp ENDC .notadf move.l __adffh(a5),d1 call Close .noadf IFEQ FILEMODE move.l __outfh(a5),d1 call Close .nofile ENDC move.l __rdargs(a5),d1 call FreeArgs .noargs moveq #0,d7 ; returncode = 0 call IoErr move.l d0,d1 beq.s .nofail bpl.s .real ; sometimes Read() sets error to -1 moveq #0,d1 bra.s .nofail .real moveq #20,d7 ; returncode = 20 .nofail move.l __reason(a5),d2 call PrintFault move.l a6,a1 move.l execbase(a5),a6 call CloseLibrary .nodos move.l d7,d0 unlk a5 rts IFNE MESSAGES __prtrk movem.l d0-d2/a0,-(sp) lea __msg(pc),a0 move.l a0,d1 move.l sp,d2 ; points at D0 on the stack move.l dosbase(a5),a6 call VPrintf movem.l (sp)+,d0-d2/a0 rts ENDC ;------------------------------------ ; a0 = buffer, d0 = track __dosrd movem.l d2/d3/a2/a3/a6,-(sp) IFNE MESSAGES bsr.s __prtrk ENDC add.l d0,d0 add.l d0,d0 lea __sltab(a5),a2 lea __otab(a5),a3 tst.w (a2,d0.w) beq.s __rdcom ; continue if DOS track __rdfai lea errtrk(pc),a0 bra.s __fail ;------------------------------------ ; a0 = buffer, d0 = track __rawrd movem.l d2/d3/a2/a3/a6,-(sp) IFNE MESSAGES bsr.s __prtrk ENDC add.l d0,d0 add.l d0,d0 lea __sltab(a5),a2 lea __otab(a5),a3 move.w (a2,d0.w),(a0)+ beq.s __rdfai ; fail if DOS track __rdcom move.w d0,-(sp) move.l __adffh(a5),d1 move.l (a3,d0.w),d2 ; get offset in disk file moveq #OFFSET_BEGINNING,d3 move.l dosbase(a5),a6 move.l a0,-(sp) call Seek move.l __adffh(a5),d1 move.l (sp)+,d2 moveq #0,d3 move.w (sp)+,d3 move.w 2(a2,d3.w),d3 call Read tst.l d0 bmi.s __rdfai movem.l (sp)+,d2/d3/a2/a3/a6 rts ;------------------------------------ ; a0 = failure reason __fail move.l a0,d0 beq.s .noreas move.l d0,__reason(a5) move.l dosbase(a5),a6 move.l #ERROR_NOT_A_DOS_DISK,d1 call SetIoErr .noreas move.l __initsp(a5),sp rts IFNE FILEMODE ;------------------------------------ ; a0 = filename, a1 = buffer, d0 = length __savef movem.l d2-d4/a6,-(sp) move.l a0,d1 move.l a1,d3 ; d3 = buffer move.l d0,d4 ; d4 = length move.l #MODE_NEWFILE,d2 move.l dosbase(a5),a6 call Open move.l d0,d1 ; d1 = filehandle move.l d3,d2 ; d2 = buffer move.l d4,d3 ; d3 = length move.l d0,d4 ; d4 = filehandle beq.s __fail call Write move.l d0,d3 move.l d4,d1 call Close tst.l d3 bmi.s __fail movem.l (sp)+,d2-d4/a6 rts ELSE ;------------------------------------ ; a0 = buffer, d0 = length __write movem.l d2-d3/a6,-(sp) move.l a0,d2 move.l d0,d3 move.l __outfh(a5),d1 move.l dosbase(a5),a6 call Write tst.l d0 bmi.s __fail movem.l (sp)+,d2-d3/a6 rts ENDC ;------------------------------------ ; a0 = buffer d0 = sync __sync movem.l d2-d3,-(sp) move.l a0,a1 subq #2,a0 beq.s .done move.w #($7ffe/2)-1,d2 ; search entire trackbuffer .nxtwrd moveq #16-1,d3 ; find a BIT distance... (0-15) .nxtbit move.l (a0),d1 ; and a BYTE distance.. (0-$7ffe) lsr.l d3,d1 cmp.w d0,d1 ; ... for which we find the SYNCWORD beq.s .synced dbra d3,.nxtbit addq.l #2,a0 dbra d2,.nxtwrd lea .err(pc),a0 ; searched through all 32k... bra.s __fail ; ...no sync marker found .synced move.l (a0),d1 ; match; now we shift all the remaining addq.l #2,a0 ; trackdata backwards by this BIT and lsr.l d3,d1 ; BYTE distance, so the first word in move.w d1,(a1)+ ; the trackbuffer is the SYNCWORD dbra d2,.synced movem.l (sp)+,d2-d3 .done rts .err dc.b "can't find sync mark",0 errtrk dc.b "can't read track",0 __dosnm dc.b "dos.library",0 __templ __tmpl IFNE MESSAGES __msg dc.b "reading track %ld",13,0 ENDC cnop 0,4 ; create 32kb CHIP BSS hunk for trackbuffer section trackbuf,bss,chip __trk ds.b $7ffe ; return to main code section section diskreader,code __main move.l sp,__initsp(a5)