// (C) Copyright 1979 Tripos Research Group
//     University of Cambridge
//     Computer Laboratory

// DISCCOPY command for the LSI4 floppy discs

SECTION "NCopy"

GET "LIBHDR"

GET "IOHDR"

MANIFEST
$(
dkdev   = -2
tracksize = 64*26
nsurs = 1
cyloffset = 77  // Where first logical disc starts
log.disc.size = 0  // Cylinders in logical disc
n.log.discs = 0 // no. of logical discs per pack
sector.origin = 1 // hardware no. of first sector
$)

LET start() BE
 $( LET v = VEC 50
    LET date = VEC 14
    LET stamp = VEC 2
    LET rc = 0
    LET dstr = "DF0:,DF1:,NIL:"
    LET Seg = LoadSeg("SYS:L.DAT-TO-STRINGS")
    LET fromdev, todev = ?, ?
    LET fromdev.cylbase, todev.cylbase, n.cyls.to.copy = ?, ?, ?
    LET check.blocks = ?
    LET fromdrive, todrive = ?, ?
    LET cylbuf = ?

    IF rdargs("FROM/A,TO/A/K,CHECKBLOCKS=CHKBLKS/S", v, 50)=0 DO
       error("bad args*N")

    check.blocks := v!2\=0

    // Check loading of date string overlay
    IF Seg=0 DO Error("Cannot load SYS:L.DAT-TO-STRINGS*N")
    Globin(Seg)
    // make a date string
    Start(DatStamp(Stamp), Date)
    UnloadSeg(seg)

    fromdev := findarg(dstr, v!0)
    IF fromdev=-1 | fromdev=2 DO
       error("unrecognised device FROM %S*N", v!0)
    todev := findarg(dstr, v!1)
    IF todev=-1 DO
       error("unrecognised device TO %S*N", v!1)

    fromdrive := fromdev/(n.log.discs+1)
    UNLESS todev=2 DO todrive   := todev/(n.log.discs+1)
    fromdev := fromdev REM (n.log.discs+1)
    UNLESS todev=2 DO todev   := todev REM (n.log.discs+1)

    UNLESS todev=2 IF (fromdev=0 & todev\=0) | (todev=0 & fromdev\=0) |
       (fromdrive=todrive & fromdev=todev) DO
       error("incompatible FROM and TO areas*n")

    fromdev.cylbase := fromdev=0 -> 0, cyloffset+(fromdev-1)*log.disc.size
    todev.cylbase   := todev=0   -> 0, cyloffset+(todev-1)*log.disc.size
    n.cyls.to.copy      := fromdev=0 -> cyloffset, log.disc.size

    cylbuf := getvec(tracksize-1)
    IF cylbuf=0 DO
       error("can*'t get buffer space*N")

    // calibrate drive
    seek(fromdrive, 2); seek(fromdrive, -80)
    UNLESS todev=2 DO
    $( seek(todrive,   2); seek(todrive,   -80)
    $)

    $( FOR relcyl = 0 TO n.cyls.to.copy-1 DO
         FOR sur = 0 TO nsurs-1 DO
         $( LET n = 1
            UNTIL sendpkt(-1, dkdev, act.read, 0, 0,
                      cylbuf, tracksize, fromdrive,
                      fromdev.cylbase+relcyl, sur, sector.origin)=0 DO
            $( n := n+1
               IF n>=10 DO
               $( writef("Read from drive %n cyl %N, sur %N failed*N",
                    fromdrive, fromdev.cylbase+relcyl, sur)
                  rc := 10
                  GOTO L $)
            $)
            IF n>1 DO
            $( writef("Read from drive %n cyl %N, sur %N took %N tries*N",
                      fromdrive, fromdev.cylbase+relcyl, sur, n)
               IF rc<5 DO rc := 5 $)
            IF testflags(1) DO
            $( writes("****BREAK*N")
               rc := 10
               GOTO L $)
            n := 1
||          // Write in date string to identify backup.
||          IF relcyl=0 & sur=0 DO
||             FOR i = 0 TO 14 DO
||                cylbuf![todev.cylbase=0 -> i+256, i] := date!i

            IF check.blocks THEN check.track(cylbuf, fromdev.cylbase+relcyl)

            UNLESS todev=2 DO
            UNTIL sendpkt(-1, dkdev, act.write, 0, 0,
                      cylbuf, tracksize, todrive,
                      todev.cylbase+relcyl, sur, sector.origin)=0 DO
            $( n := n+1
               IF n>=10 DO
               $( writef("Write to drive %n cyl %N, sur %N failed*N",
                  todrive, todev.cylbase+relcyl, sur)
                  rc := 10
                  GOTO L $)
            $)
            IF n>1 DO
            $( writef("Write to drive %n cyl %N, sur %N took %N tries*N",
                      todrive, todev.cylbase+relcyl, sur, n)
               IF rc<5 DO rc := 5 $)
         $)
 L: $)
    freevec(cylbuf)
    stop(rc)
 $)


AND error(f, a) BE
 $( writes("DISCCOPY: ")
    writef(f, a)
    stop(20)
 $)

AND seek(drive, cyl) BE
   sendpkt(-1, dkdev, act.seek, ?, ?,
           ?, ?, drive, cyl)

AND check.track(cylbuf, cyl) BE
   FOR i = 0 TO 5 DO check.block(cylbuf+i*256, cyl*6+i)

AND check.block(buf, key) BE
$( LET sum, value, same = 0, buf!0, TRUE
   FOR i = 0 TO 255 DO
   $( sum := sum+buf!i
      UNLESS buf!i=value DO same := FALSE
   $)
   UNLESS sum=0 | same DO
      writef("Block no. %i3 suspect*N", key)
$)


