$MODCAL$
$ALLOW_PACKED ON$
$RANGE OFF$ $STACKCHECK OFF$

MODULE SYS_BOOT;
EXPORT
  TYPE
    string12 = string[12];
  function sysboot(name,msus,lanid:string12):integer;
IMPLEMENT
IMPORT SYSGLOBALS,ASM,IODECLARATIONS;
  function sysboot(name,msus,lanid:string12):integer;
    CONST
      hp98643 = 21;
    TYPE
      msus_type = packed record
		    case integer of
		    1:(df       : 0..7;         { directory format }
		       dt       : 0..31;        { device type }
		       unum     : byte;         { unit number }
		       scode    : byte;         { select code }
		       baddr    : byte);        { bus address }
		    2:(pad1     : byte;
		       vol      : 0..15;    { volume number }
		       un       : 0..15);   { unit number }
		    3:(bytes    : packed array [1..4] of char);
		  end;
      name_type = packed array [1..10] of char;
      lanid_type= packed array [1..6] of char;
      lanid_ptr = ^lanid_type;
    VAR
      bootmsus [hex('FFFFFEDC')] : msus_type;
      sysname  [hex('FFFFFDC2')] : name_type;
      farea    [hex('FFFFFED4')] : lanid_ptr;
      bootrec : record
		  case boolean of
		  false :( boot : procedure);
		  true  :( op1,op2 : integer);
		end;
      newmsus : msus_type;
      newname : name_type;
      i,
      mlen,
      number  : integer;

      { input is pre-filtered to be 0..9, A..F, a..f }
      function chr_hex(c:char):integer;
	begin
	  if (c>='0') and (c<='9') then chr_hex := ord(c)-ord('0')
	  else
	  if (c>='A') and (c<='F') then chr_hex := ord(c)-ord('A')+10
				   else chr_hex := ord(c)-ord('a')+10
	end; { chr_hex }

      procedure fsunit_msus(fsunit : unitnum; var msus : msus_type);
	begin
	  if (fsunit<0) or (fsunit>maxunit) then escape(2);
	  with unitable^[fsunit] do
	  begin
	    msus.df    := 0;
	    msus.scode := sc;
	    msus.baddr := ba;
	    msus.unum  := du;
	    case letter of
	      'B':begin { BUBBLE }
		    msus.dt := 22;
		  end;
	      'E':begin { EPROM }
		    msus.dt := 20;
		    msus.unum := dv;
		  { bootrom uses unit, table uses volume }
		  end;
	      'F':begin { 9885 }
		    msus.dt := 6;
		  end;
	      'G':begin { SRM }
		    msus.df := 7; msus.dt := 1;
		  end;
	      'H':begin { 9895 }
		    msus.dt := 4;
		  end;
	      'J',{ PRINTER }
	      'R':{ RAM }
		  escape(2);
	      'M':begin { internal mini }
		    msus.dt := 0;
		  end;
	      'N':begin { 8290X }
		    msus.dt := 5;
		  end;
	      'Q':begin { C280 }
		    msus.vol := dv; msus.un := du;
		  { must force disc access to determine sector size }
		  { will hang system if intlevel is too high }
		    if intlevel>2 then escape(2);
		    call(dam,uvid,fsunit,getvolumename);
		    if (ioresult<>0) or
		       (strlen(uvid)=0) or
		       (dvrtemp2<8) then escape(2)
		    else
		    if dvrtemp2=8 then msus.dt := 16
				  else msus.dt := 17;
		  end;
	      'S':begin { SCSI }
		    msus.dt := 14;
		  end;
	      'U':begin { 913X_A }
		    msus.dt := 7;
		  end;
	      'V':begin { 913X_B }
		    msus.dt := 8;
		  end;
	      'W':begin { 913X_C }
		    msus.dt := 9;
		  end;
	      otherwise
		escape(2);
	    end; { case }
	  end;
	end; { fsunit_msus }

    BEGIN { SYSBOOT }
      try
	bootrec.op1 := hex('1C0'); bootrec.op2 := 0;

	{ process the system name }
	name := strrtrim(strltrim(name));
	if strlen(name)>10 then escape(1); { bad system name }
	if name<>'' then
	begin
	  newname := '          ';
	  for i := 1 to strlen(name) do
	    newname[i] := name[i];
	end
	else newname := sysname;

	{ process the MSUS }
	newmsus := bootmsus; {default the MSUS}
	msus := strrtrim(strltrim(msus)); { trim leading & trailing blanks }
	mlen := strlen(msus);

	try
	  if (mlen>0) then
	  begin
	    if msus[1]='#' then
	    begin { file system unit }
	      if (mlen=2) or (mlen=3) then strread(msus,2,i,number)
				      else escape(2);
	      fsunit_msus(number,newmsus);
	    end
	    else
	    if msus[1]='$' then
	    begin  { constructed MSUS }
	      if mlen<>9 then escape(2); { must have 8 digits }
	      for i := 2 to 9 do
	      if not(msus[i] in ['0'..'9','A'..'F','a'..'f'])
		then escape(2);
	      for i := 2 to 9 do
	      begin
		if odd(i) then
		begin
		  number := (number*16)+chr_hex(msus[i]);
		  newmsus.bytes[i div 2] := chr(number);
		end
		else number := chr_hex(msus[i]);
	      end;
	    end
	    else
	    escape(2);
	  end;
	recover
	  if (escapecode = -10) or
	     (escapecode = -8) then escape(2) { bad MSUS }
			       else escape(escapecode);
       { process the lanid }
	try
	  if strlen(lanid)>0 then
	  begin
	    if strlen(lanid)<>12 then escape(3);
	    for i := 1 to 12 do
	      if not(lanid[i] in ['0'..'9','A'..'F','a'..'f'])
		then escape(3);
	    for i := 1 to 12 do
	    begin
	      if not odd(i) then
	      begin
		number := (number*16)+chr_hex(lanid[i]);
		if i=2 then
		  if odd(number) then escape(3); { can't be multicast }
		farea^[i div 2] := chr(number);
	      end
	      else number := chr_hex(lanid[i]);
	    end;
	  end;
	recover
	  if (escapecode = -10) or
	     (escapecode = -8) then escape(3) { bad LAN address }
			       else escape(escapecode);

	sysname := newname;
	bootmsus := newmsus;
	ci_switch;
	cache_mode(false);      { setup bootrom environment }
	call(bootrec.boot);
      recover
	begin
	  if (escapecode>0) and
	     (escapecode<4) then sysboot := escapecode
			    else escape(escapecode);
	end;
    END; { SYSBOOT }

END. { MODULE SYS_BOOT }


