
{============================================================================}
{                                                                            }
{         Modul fuer BiosBasedFormatier-Programm (VERS.2.0  23.9.86)         }
{                                                                            }
{         Es errechnet die Parameter fuer das Formatier-Programm             }
{         aus dem DISK-BLOCK des BIOS , der in die TPA geladen wird.         }
{                                                                            }
{                                                                            }
{============================================================================}





{========== TYPEN- und VARIABLEN-Vereinbarungen fuer BBFMOD =================}




TYPE  bytearray=array[0..15]of byte;

      BLK_REC=record
                disktyp,
                fsektor,
                lsektor,
                lwpre,
                tth1,
                gap,
                spuren,
                wrpspur            :byte;
                spt                :integer;
                bsh,
                blm,
                exm                :byte;
                dsm,
                drm                :integer;
                al0,
                al1                :byte;
                cks,
                syso               :integer;
                psh,
                phm                :byte;
                spointer,
                tpointer           :integer;
                barray             :bytearray;
                fgap,
                fskew,
                reserved           :byte;
        end;

blk_typ=array[0..200]of blk_rec;

skew_type=array[0..159]of byte; { Datenformat der Skew-Tabellen }

itable=array[0..255]of byte;

VAR blkparameter:blk_typ;
    xdpb_anz    :byte;
    bidtable    :itable;



{ ============= Ende der TYPE- und VAR- Declarationen ============= }


procedure GET_DATA;
var blkfile : file;
{   blkpara : array[0..5000] of byte;}

   i       : integer;
begin
 assign(blkfile,'b:blkpara.dat');
 reset(blkfile);
 i := filesize(blkfile);
 blockread(blkfile,blkparameter,i);
 close(blkfile);
end;

function ggt(m,n:integer):integer;
var rest,x:integer;
begin
   rest:=0;
   repeat
      x:=m div n;
      rest:=m-n*x;
      m:=n;n:=rest;
   until rest=0;
   ggt:=m;
end;

procedure genidtable(skew,sanz,erstsektnr:integer);
var sektcount,nrokor,nfree,pos,idnr,uberlauf:integer;
    schluss:boolean;
begin
   nrokor:=sanz div ggt(sanz,skew);pos:=0;idnr:=erstsektnr;uberlauf:=1;
   schluss:=false;
   if ggt(sanz,skew)=1 then
               begin
                  repeat
                     bidtable[pos]:=idnr;
                     pos:=(pos+skew)mod sanz;idnr:=idnr+1;
                  until (idnr-erstsektnr)=sanz;
               end
            else
               begin
                  repeat
                     sektcount:=0;
                     repeat
                        bidtable[pos]:=idnr;idnr:=idnr+1;
                        pos:=(pos+skew)mod sanz;sektcount:=sektcount+1;
                     until((sektcount=nrokor)or((idnr-erstsektnr)=sanz));
                     if (idnr-erstsektnr)=sanz then schluss:=true;
                     pos:=uberlauf;uberlauf:=uberlauf+1;
                  until schluss;
               end;
end;


FUNCTION BITTEST (TESTBYTE:byte; POS:integer):boolean;
VAR b:byte;
BEGIN
   b:=1 shl POS;
   BITTEST:=(TESTBYTE and b)<>0;
END;



FUNCTION PARAMETER_BASE:integer;

{ Ermittelt die Startadresse der BIOS-Parameter         }

BEGIN
   PARAMETER_BASE:=mem[$FF4E]*$100 + mem[$FF4D];
END;


FUNCTION BIOS3 (fn,pa,pbc,pde,phl:integer):integer;

{ CP/M-3 BIOS-CALL                                        }

TYPE parameterblock=record
                        func,areg:byte;
                        bcreg,dereg,hlreg:integer;
                    end;
VAR biospb:parameterblock;
    result:integer;

BEGIN
   with biospb do begin
        func:=fn;
        areg:=pa;
        bcreg:=pbc;
        dereg:=pde;
        hlreg:=phl;
   end;
   result:=0;
   case fn of
    2,3,7,13,14,15,17,18,19,24 : result:=bdos(50,addr(biospb));
    9,16,20,22,25 :result:=bdoshl(50,addr(biospb))
   else bdos(50,addr(biospb))
   end;
   BIOS3:=result
END;





PROCEDURE LOAD_DISK_BLK ;

(*  Diese Procedure laedt den DISK-BLOCK (max. 8k) in die TPA *)
{ Bringt bestehende Diskparameter in Arbeitsvariable Blkparameter
  setzt alle vorhandenen Skew-Pointer auf relative Adressen um
  ermittelt die Anzahl der schon bestehenden Formate.                }

VAR i:integer;
    test:byte;

BEGIN
{ Speicherbereich von Blkparameter mit Diskparametern aus BIOS laden }
   i:=BIOS3(30,0,0,addr(blkparameter),0);
{ Die Anzahl der Diskformate zaehlen .                                }
   xdpb_anz:=0;
   while blkparameter[xdpb_anz].disktyp <> 8 do xdpb_anz:=xdpb_anz+1;
{ Die Skew-Pointer werden auf die relative Adresse justiert        }
   for i:= 0 to xdpb_anz-1 do
        with blkparameter[i] do
                begin
                   spointer:=spointer - PARAMETER_BASE;
                end;
END;




FUNCTION GET_HEADID (NR,HEADNR:integer):byte;

(* Liefert den Wert fuer HEADID , wahrscheinlich in der Form
   HEADID:=GETHEAD ( 0/1 );                                  *)

BEGIN
  with blkparameter[NR] do begin
   if HEADNR=0 then
                 if BITTEST(disktyp,4) then GET_HEADID:=1
                                       else GET_HEADID:=0
               else                
                 if BITTEST(tth1,4) then GET_HEADID:=1
                                    else GET_HEADID:=0
  end { with }
END;





FUNCTION GET_SPURANZ (NR:integer):byte;

(* Liefet die Anzahl der Spuren zurueck. Wird benoetigt fuer
   Schleifenzaehler in SEITFORM  und VERIFIZIERE              *)

BEGIN
   GET_SPURANZ:=blkparameter[NR].spuren;
END;





FUNCTION GET_WRPRECOMP_SPUR (NR:integer):byte;

(* Liefert die Nummer der Spur, ab der die Writeprecompensation
   einsetzen soll.                                              *)

BEGIN
   with blkparameter[NR] do begin
        if wrpspur>spuren then wrpspur:=spuren+1;
        GET_WRPRECOMP_SPUR:=wrpspur;
   end
END;



FUNCTION GET_WRPRECOMP (NR:integer):byte;

{ Liefert den Wert der Write-precompensation als Byte aus 0..7  }

BEGIN
   with blkparameter[NR] do begin
        if wrpspur>spuren then GET_WRPRECOMP:=0
                          else GET_WRPRECOMP:=(lwpre and $07);
   end
END;




FUNCTION GET_DECIMAL_SECTORSIZE (NR:integer):integer;

(* Liefert den dezimalen Wert der Sektorgroesse, zur Berechnung
   ob der Vergleich in einem oder zwei Durchgaengen erfolgen muss *)

BEGIN
   with blkparameter[NR] do begin
        case (disktyp and $07) of
         0 : GET_DECIMAL_SECTORSIZE:=128;
         1 : GET_DECIMAL_SECTORSIZE:=256;
         2 : GET_DECIMAL_SECTORSIZE:=512;
         3 : GET_DECIMAL_SECTORSIZE:=1024;
        end;
   end
END;




FUNCTION GET_SEKT_ANZ (NR:integer):byte;

(* Liefert die Anzahl der Sektoren pro Spur.  *)

BEGIN
   with blkparameter[NR] do begin
        GET_SEKT_ANZ:=spt div (phm+1);
   end;
END;




FUNCTION GET_SKEW (NR:integer):byte;

(* Liefert den physikalischen Skew-Faktor.     *)

BEGIN
   GET_SKEW:=blkparameter[NR].fskew
END;




FUNCTION GET_CODED_SECTOR_SIZE (NR:integer):byte;

(* Liefert die Sektorgroesse gemaess der Controler-konvention
   in 2-bit codiert.                                                *)

BEGIN
   GET_CODED_SECTOR_SIZE:=(blkparameter[NR].disktyp and $03)
END;




FUNCTION GET_FORMAT_GAP (NR:integer):byte;

(* Liefert den Wert des Format-Gap's in HEX.                        *)

BEGIN
   GET_FORMAT_GAP:=blkparameter[NR].fgap
END;




FUNCTION GET_TRACK_METH (NR:integer):byte;

{ Liefert die Nummer des verwendeten TRACK-Verfahrens  }

BEGIN
   GET_TRACK_METH:=(blkparameter[NR].tth1 and $07)
END;



FUNCTION GET_SANZ_1_SEIT (NR:integer):byte;

{ Liefert 0 wenn kein Sektor auf dieser Seite ist. Analysiert die
  log. Skew-Tabelle. }
VAR j,stelle,count:integer;
BEGIN
   j:=0;count:=0;
   repeat
      stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
      if (mem[stelle]<$80) then count:=count+1;
      j:=j+1;
   until j=GET_SEKT_ANZ(NR);
   GET_SANZ_1_SEIT:=count;
END;


FUNCTION GET_SANZ_2_SEIT (NR:integer):byte;

{ Liefert 0 wenn kein Sektor auf dieser Seite ist. Analysiert die
  log. Skew-Tabelle.  }

VAR j,stelle,count:integer;
BEGIN
   j:=0;count:=0;
   repeat
      stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
      if (mem[stelle]>$7f) then count:=count+1;
      j:=j+1;
   until j=GET_SEKT_ANZ(NR);
   GET_SANZ_2_SEIT:=count;
END;




FUNCTION GET_1_NR_2_SEIT (NR:integer):byte;
VAR i,j,stelle,stop:integer;
BEGIN
   j:=0;i:=$ff;stop:=GET_SEKT_ANZ(NR);
   repeat
      stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
      if ((mem[stelle]>$7f) and (mem[stelle]<i)) then i:=mem[stelle];
      j:=j+1;
   until j=stop;
   GET_1_NR_2_SEIT:=i-$80;
END;



FUNCTION GET_NR_1_SEKT (NR:integer):byte;

{   Liefert die Nummer des Sektors mit der niedrigsten Sektornummer.  }

BEGIN
   GET_NR_1_SEKT:=blkparameter[NR].fsektor
END;





FUNCTION GET_NR_L_SEKT (NR:integer):byte;

{   Liefert die Nummer des Sektors mit der hoechsten Sektornummer.  }

BEGIN
   GET_NR_L_SEKT:=blkparameter[NR].lsektor
END;


FUNCTION GET_SS_DS (NR:integer):byte;

{ Liefert den Wert fuer Single-(VS=0\RS=1)oder-Double(VRS=2)-Sided   }
VAR j:integer;
    V,R:boolean;
BEGIN
  with blkparameter[NR] do begin
   if (tth1 and $07)<>0 then  { TRACK-Verfahren <> 0 }
      begin
         if (spt*(spuren-syso))=((dsm+1)*(blm+1)) then GET_SS_DS:=0
                else GET_SS_DS:=2;
      end
    else  { TRACK-Verfahren=0 }
     begin
      j:=0;V:=false;R:=false;
      repeat
         if mem[addr(blkparameter)+blkparameter[NR].spointer+j]<$80
            then V:=true else R:=true;
         j:=j+1;
      until j=GET_SEKT_ANZ(NR);
      if (V and R) then GET_SS_DS:=2
           else begin if R then GET_SS_DS:=1;
                      if V then GET_SS_DS:=0;
                end;
     end; { End-of-else }
  end;
END;



FUNCTION GET_DENSITY (NR:integer):boolean;

{ Liefert den Wert fuer Density }

BEGIN
   GET_DENSITY:=BITTEST(blkparameter[NR].disktyp,6)
END;




PROCEDURE SET_BIDTABLE (NR,SEITE:integer);

{ Fuellt unter beruecksichtigung des TRACK-Verfahrens und eventueller
  Luecken in der Sektor-Nummerierung die Tabelle BIDTABLE, die zur
  Formatierung benutzt wird. Bei Trackverfahren=0 wird ,je nach SEITE,
  eine BIDTABLE aus den Sektoren <$80 oder >=$80 erzeugt }
VAR i,j:byte;
    stelle:integer;
    btpos:byte;
    found:boolean;
BEGIN
   with blkparameter[NR] do begin
    if (tth1 and $07)<>0 then   { TRACK-Verfahren <> 0 }
      if (GET_SEKT_ANZ(NR)-((GET_NR_L_SEKT(NR)+1)-GET_NR_1_SEKT(NR)))=0
        then { keine Luecken }
             genidtable(GET_SKEW(NR),GET_SEKT_ANZ(NR),GET_NR_1_SEKT(NR))
        else { Lueckenhafte Sektornummerierung }
             begin
                i:=GET_NR_1_SEKT(NR)-1;
                for btpos:=0 to (GET_SEKT_ANZ(NR)-1)do begin
                   repeat
                     i:=i+1;found:=false;j:=0;
                     repeat
                       j:=j+1;
                       stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
                       if mem[stelle]=i then
                                begin found:=true;
                                      bidtable[btpos]:=i end;
                        until (found or(j=GET_SEKT_ANZ(NR)));
                   until (found or (i=GET_NR_L_SEKT(NR)));
                end;
             end { end-of-TRACK-Verfahren <>0 }
        else { TRACK-Verfahren = 0 }
              if SEITE=1 then begin
                   j:=0;i:=0;
                   repeat
                      stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
                      if mem[stelle]<$80 then begin
                          bidtable[i]:=mem[stelle];i:=i+1;end;
                      j:=j+1;
                   until j=GET_SEKT_ANZ(NR);
                 end { end-of-SEITE=1 }
                else begin
                   j:=0;i:=0;
                   repeat
                      stelle:=addr(blkparameter)+blkparameter[NR].spointer+j;
                      if mem[stelle]>$7f then begin
                          bidtable[i]:=mem[stelle]-$80;i:=i+1;end;
                      j:=j+1;
                   until j=GET_SEKT_ANZ(NR);
                end; { end-of-SEITE=2 }
   end
END;


var i,NR,hilf:integer;
begin
LOAD_DISK_BLK;
read(kbd,NR);
while NR<>100 do begin
   for i:=0 to 15 do write(char(blkparameter[NR].barray[i]));
   write(GET_HEADID(NR,0));writeln(GET_HEADID(NR,1));
   writeln(GET_SPURANZ(NR));
   writeln(GET_WRPRECOMP_SPUR(NR));
   writeln(GET_WRPRECOMP(NR));
   writeln(GET_DECIMAL_SECTORSIZE(NR));
   writeln(GET_CODED_SECTOR_SIZE(NR));
   writeln(GET_SEKT_ANZ(NR));
   writeln(GET_SKEW(NR));
   writeln(GET_FORMAT_GAP(NR));
   writeln(GET_NR_1_SEKT(NR));
   writeln(GET_NR_L_SEKT(NR));
   writeln(GET_SANZ_1_SEIT(NR));
   writeln(GET_SANZ_2_SEIT(NR));
   writeln(GET_DENSITY(NR));
   writeln(GET_SS_DS(NR));
   writeln(GET_TRACK_METH(NR));
   SET_BIDTABLE(NR,1);
   for i:=0 to 30 do write(bidtable[i],' ');
writeln;
   SET_BIDTABLE(NR,2);
   for i:=0 to 30 do write(bidtable[i],' ');
writeln;
for i:=0 to 30 do
write(' ',mem[addr(blkparameter)+blkparameter[NR].spointer+i]);
writeln;
if ((GET_SS_DS(NR)=2)and(GET_TRACK_METH(NR)=0))then writeln(GET_1_NR_2_SEIT(NR));
read(kbd,NR);end;
end.