.title copflp .enabl lc ;+ ; ; Copy floppy images to/from files (or each other). ; ; By John Wilson. ; ; *FILE.DAT " mov #file,r0 ;assume file tstb oflop ;is output a floppy? beq 210$ ;no mov #sd,r0 ;assume SD tstb dens ;right? beq 200$ mov #dd,r0 ;DD 200$: .print mov #floppy,r0 ;it's a floppy 210$: .print .print #crlf ;EOL ; loop: ; read next group of 4 tracks tstb iflop ;is input file a floppy? bne 30$ ;yes ; reading from file mov #readw,r0 ;read a bufferload .readw bcs 10$ add #4,rtrk ;update cmp r0,rwc ;is this what we wanted? beq 20$ ;yes, happy ; didn't get it all, only excuse is if we're on track 76. cmp rtrk,#76.+4 ;are we? bne 10$ ;no mov trksiz,r1 ;get # bytes in a sector asr r1 ;/2=acceptable word count cmp r0,r1 ;at least big enough? bhis 50$ ;yes 10$: .print #ioerr jmp mloop 20$: movb rwc+1,r0 ;get blk count add r0,rblk ;update br 50$ 30$: ; reading from floppy mov buf,r5 ;get buf addr 40$: call rdtrk ;read a track add trksiz,r5 ;bump addr inc rtrk ;bump track # cmp rtrk,#76. ;off end of disk? bhi 50$ ;yes bit #3,rtrk ;up to next mult of 4 yet? bne 40$ ;loop if not 50$: ; write next group of 4 tracks tstb oflop ;writing to floppy? bne 70$ ; writing to file mov #writw,r0 ;pt at area cmp wtrk,#76. ;writing track 76.? bne 60$ mov trksiz,r1 ;yes, get size in bytes asr r1 ;/2=words mov r1,wwc ;set word count .writw bcs 10$ br 90$ ;done 60$: .writw bcs 10$ add #4,wtrk ;bump track count movb wwc+1,r0 ;get blk count add r0,wblk ;update br loop 70$: ; writing to floppy mov buf,r5 ;get buf addr 80$: call wrtrk ;write a track add trksiz,r5 ;bump addr inc wtrk ;bump track # cmp wtrk,#76. ;off end of disk? bhi 90$ ;yes bit #3,wtrk ;up to next mult of 4 yet? bne 80$ ;loop if not br loop 90$: .close #0 .close #3 jmp mloop ; .sbttl floppy I/O routines ;+ ; ; Read next track from floppy. ; ; r5 buffer ; ;- rdtrk: mov rtrk,r2 ;get current track # mul #6,r2 ;track *6 (in r3) mov #26.,r4 ;sector count div r4,r2 ;... mod 26. (in r3) 10$: ; read sector indexed by r3 (r4=loop counter, r5=buf base) movb sectab(r3),r1 ;get sector # mov r1,rsec ;save it mov #rflop,r0 ;pt at area .spfun ;read the sector bcs 50$ 20$: dec r1 ;start from 0 mul secsiz,r1 ;find starting offset into buf add r5,r1 ;add base mov #secbuf,r0 ;ptr mov secsiz,r2 ;get sector size asr r2 ;/2=WC 30$: mov (r0)+,(r1)+ ;copy sector into place sob r2,30$ inc r3 ;bump index cmp r3,#26. ;off end of table? blo 40$ clr r3 ;yes, start over 40$: sob r4,10$ ;loop rts pc 50$: decb errcnt ;count the error beq 60$ .print #ignerr ;ignore it br 20$ 60$: .print #ioerr ;I/O error jmp mloop ;+ ; ; Write next track to floppy. ; ; r5 buffer ; ;- wrtrk: mov wtrk,r2 ;get current track # mul #6,r2 ;track *6 (in r3) mov #26.,r4 ;sector count div r4,r2 ;... mod 26. (in r3) 10$: ; write sector indexed by r3 (r4=loop counter, r5=buf base) movb sectab(r3),r1 ;get sector # mov r1,wsec ;save it dec r1 ;start from 0 mul secsiz,r1 ;find starting offset into buf add r5,r1 ;add base mov #secbuf-2,r0 ;ptr clr (r0)+ ;clear deleted data flag word mov secsiz,r2 ;get sector size asr r2 ;/2=WC 20$: mov (r1)+,(r0)+ ;copy sector into buffer sob r2,20$ mov #wflop,r0 ;pt at area .spfun ;write the sector bcs 40$ inc r3 ;bump index cmp r3,#26. ;off end of table? blo 30$ clr r3 ;yes, start over 30$: sob r4,10$ ;loop rts pc 40$: .print #ioerr ;I/O error jmp mloop ; .sbttl filename routines ;+ ; ; Skip white space. ; ; r5 ptr (updated on return) ; r0 returns first non-blank char, or C=1 if all blank ; ;- skip: movb (r5)+,r0 ;grab a char beq 10$ cmp r0,#<' > ;blank or ctrl char? blos skip ;ignore if so, otherwise C=0 dec r5 ;back up (w/o affecting C) rts pc 10$: dec r5 ;back to NUL sec ;EOL rts pc ;+ ; ; Parse a filename. ; ; On entry: ; r5 source pointer ; r4 buffer for dev/filename ; ; C=1 if filename is bad. ; ;- fname: mov #^RDK ,(r4)+ ;set default device clr (r4)+ ;zap file & ext clr (r4)+ clr (r4) sub #4,r4 ;back up to filename ; file or device name first call rad50 ;get it cmp r0,#': ;device? bne 10$ ;no mov r1,-2(r4) ;set it call rad50 ;get filename tst r1 ;got anything bne 10$ ;OK cmp r0,#'. ;no filename, make sure there's no "." bne 20$ ;no, OK br 30$ ;syntax error if so 10$: mov r1,(r4)+ ;it must be the filename (or null string) beq 30$ ;(null filename illegal w/no dev name) mov r2,(r4)+ mov #^RDSK,(r4) ;got a filename, so def ext = ".DSK" cmp r0,#'. ;extension given? bne 20$ ;no call rad50 ;yes, eat it mov r1,(r4) ;save it 20$: dec r5 ;unget stopping character clc ;OK rts pc 30$: sec ;error return rts pc ;+ ; ; Parse a radix-50 string. ; ; r5 source pointer ; ; On return: ; r0 char we stopped on ; r1 1st 3 chars of string ; r2 2nd 3 chars of string ; r5 points to char in r0 +1 ; ;- rad50: clr r1 ;init buf clr r2 call chr50 ;get a char bcs 20$ ;yow asl r0 ;lookup 1st char mov rad50a(r0),r1 ;get it call chr50 ;get 2nd bcs 20$ ;end of string asl r0 ;lookup 2nd add rad50b(r0),r1 call chr50 ;3rd bcs 20$ add r0,r1 call chr50 ;4th bcs 20$ asl r0 mov rad50a(r0),r2 call chr50 ;5th bcs 20$ asl r0 add rad50b(r0),r2 call chr50 ;6th bcs 20$ add r0,r2 10$: call chr50 ;skip anything left bcc 10$ 20$: rts pc ;+ ; ; Get a char and cvt to radix 50 in r0. ; ; C=1 if we failed (non-RAD50 char), char in r0. ; ;- chr50: movb (r5)+,r0 ;get it cmp r0,#<' > ;blank? beq chr50 ;yes, ignore cmp r0,#'0 ;digit? blo 10$ cmp r0,#'9 blos 20$ cmp r0,#'A ;u.c. letter? blo 10$ cmp r0,#'Z blos 30$ cmp r0,#'a ;l.c. letter? blo 10$ cmp r0,#'z blos 40$ 10$: sec ;error return, non-RAD50 character rts pc 20$: ; digit sub #'0-<^R 0>,r0 ;convert (C=0) rts pc 30$: ; upper case letter sub #'A-<^R A>,r0 ;convert (C=0) rts pc 40$: ; lower case letter sub #'a-<^R A>,r0 ;convert (C=0) rts pc ;+ ; ; Make sure the device at (R5) is loaded, update BUF with free core loc. ; ; C=1 if invalid dev, otherwise R0 returns handler index. ; ;- ldev: .dstat #dstat,r5 ;see if handler is loaded bcs 20$ ;invalid tst dstat+4 ;is it loaded? bne 10$ ;yes (C=0 from TST) ; device is non-resident, load it in .fetch buf,r5 ;no, load it (set C) bcs 20$ mov r0,buf ;update free core ptr .dstat #dstat,r5 ;NOW this should work bcs 20$ ;huh? 10$: movb dstat,r0 ;[get device handler index] 20$: rts pc ; .sbttl pure data ; rad50a: ; 1st char rad50 lookup table .rad50 " A B C D E F G " .rad50 "H I J K L M N O " .rad50 "P Q R S T U V W " .rad50 "X Y Z $ . 0 1 " .rad50 "2 3 4 5 6 7 8 9 " ; rad50b: ; 2nd char rad50 lookup table .rad50 " A B C D E F G " .rad50 " H I J K L M N O " .rad50 " P Q R S T U V W " .rad50 " X Y Z $ . 0 1 " .rad50 " 2 3 4 5 6 7 8 9 " ; earea: .byte 0,2 ;.ENTER, channel 0 .word oname ;dev+filename .word -1 ;allocation length .word -1 ;add file at EOT on magtape ; larea0: .byte 0,1 ;.LOOKUP, channel 0 .word oname ;dev+filename .word -1 ; larea: .byte 3,1 ;.LOOKUP, channel 3 .word iname ;dev+filename .word -1 ;start at head position on magtape ; cstato: .byte 0,27 ;.CSTAT,,channel 0 .word secbuf ; cstati: .byte 3,27 ;.CSTAT,,channel 3 .word secbuf ; sectab: .byte 1,3,5,7,9.,11.,13.,15.,17.,19.,21.,23.,25. .byte 2,4,6,8.,10.,12.,14.,16.,18.,20.,22.,24.,26. ; banner: .ascii /COPFLP V01.11 by John Wilson/ crlf: .byte 0 prompt: .ascii /*/<200> ;program prompt vers: .asciz /COPFLP V01.11/ punt: .asciz /?Syntax error/ operr: .asciz /?Error opening input file/ crerr: .asciz /?Error creating output file/ ioerr: .asciz '?I/O error' ignerr: .asciz /%Read error, sector ignored/ dconf: .asciz /?Density conflict/ nomem: .asciz /?Insufficient memory/ file: .ascii /FILE/<200> floppy: .ascii / FLOPPY/<200> sd: .ascii /SD/<200> dd: .ascii /DD/<200> arrow: .ascii / => /<200> ; .sbttl impure data ; .even sflop: ; get device density .byte 0,32 ;.SPFUN,,channel n .word 0 .word secbuf ;494. or 988. will be deposited in SECBUF .word 1 .byte 377,373 ;code,,377 .word 0 ;.WAIT ; wflop: ; write a sector .byte 0,32 ;.SPFUN,,channel 0 wsec: .word 0 .word secbuf-2 ;buf addr wtrk: .word 0 .byte 377,376 ;code,,377 (code=375 to write del'd data mark) .word 0 ;.WAIT ; rflop: ; read a sector .byte 3,32 ;.SPFUN,,channel 3 rsec: .word 0 .word secbuf-2 ;buf addr rtrk: .word 0 .byte 377,377 ;code,,377 .word 0 ;.WAIT ; writw: .byte 0,11 ;.WRITW,,channel 0 wblk: .word 0 ;blk wca: .word 0 ;buf wwc: .word 0 ;word count .word 0 ;.WAIT ; readw: .byte 3,10 ;.READW,,channel 3 rblk: .word 0 ;blk rca: .word 0 ;buf rwc: .word 0 ;word count .word 0 ; .sbttl pure storage ; iflop: .blkb ;NZ => input is a floppy drive idev: .blkb ;handler index of input device oflop: .blkb ;NZ => output is a floppy drive odev: .blkb ;handler index of output device dens: .blkb ;0 => SD, 1 => DD errcnt: .blkb ;# read errors before giving up lbuf: .blkb 81. ;space for input line ; .even secsiz: .blkw ;length of a sector in bytes trksiz: .blkw ;length of a track in bytes ; iname: .blkw 4 ;input dev+filename in .RAD50 oname: .blkw 4 ;output dev+filename in .RAD50 dstat: .blkw 4 ;.DSTAT area ; buf: .blkw ;addr of I/O buffer ; .blkw ;flag word secbuf: .blkb 400 ;sector buffer ; devhnd= . .end start