XTCFMODE Source

From Lo-tech Wiki
Revision as of 11:11, 21 April 2021 by Admin (talk | contribs) (1 revision imported)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Source code for the XTCFMODE utility, which can be compiled using Turbo Pascal 6. Compiled code can be downloaded here.

Code

Program XTCFMode;

{For XT-CF family of adapters, lists current mode and changes the mode.
 Dependent on XTIDE Universal BIOS, version 2 or newer.}

uses dos, crt;

type
  tSectorBuffer = Array[0..511] of BYTE;
  pSectorBuffer = ^tSectorBuffer;

const 
  Version                              = '0.32';
  Author                               = 'James Pearce';
  BuildDate                            = '05-May-13';
  HelpNameOnly                         = 1;
  HelpQuick                            = 2;
  HelpFull                             = 4;
  XTCF_8BIT_PIO_MODE                   = $00;
  XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD  = $01;
  XTCF_DMA_MODE                        = $02;
  INVALID_MODE                         = $04;
  DEVICE_ERROR                         = $08;

var
  VERBOSE : BOOLEAN;


Procedure PrintHelp(mode : byte);
begin
  WriteLn('XTCFMODE - transfer mode utility for XT-CF family of adapters.');
  WriteLn('See http://www.lo-tech.co.uk/XT-CF');
  WriteLn;
  If mode = HelpFull then
  begin
    WriteLn;
    WriteLn('To display current mode:   xtcfmode [BIOS_drive_number]');
    WriteLn('To change mode:            xtcfmode [BIOS_drive_number] set [mode]');
    WriteLn('   where [mode] is one of:');
    Write('     ',XTCF_8BIT_PIO_MODE);
    WriteLn(' - for PIO 8-bit (slowest & safest)');
    Write('     ',XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD);
    WriteLn(' - for PIO 16-bit (faster on most systems, but depends on proper BIU');
    WriteLn('         implementation on system board - won''t work with AT&T PC6300)');
    Write('     ',XTCF_DMA_MODE);
    WriteLn(' - for DMA mode (via channel 3, supported by XT-CFv3 adapter only);');
    WriteLn('         fastest on 8088 hardware');
    WriteLn;
    WriteLn('Specify [BIOS_drive_number] in hex, i.e. 80h, 81h etc');
  end;{if mode =}
end;{procedure PrintHelp}


Function GetMode( Device : Byte ) : byte;
var
  Regs : Registers;
begin
  with regs do begin
    ah := $1E; {XT-CF functions}
    al := 2;   {get XT-CF transfer mode}
    dl := Device;
  end;
  Intr($13,regs);
  if regs.flags and FCarry = FCarry then GetMode := DEVICE_ERROR
  else GetMode := regs.DH; {return mode}
  WriteLn('Read mode: ', regs.DH);
  WriteLn('Block mode sectors: ', regs.DL);
end;{function GetMode}


Function SetMode( Device, Mode : Byte ) : Byte;
var
  regs : registers;
begin
  with regs do begin
    ah := $1E;
    al := 1; {set mode}
    dl := Device;
    dh := Mode;
  end;{with}
  Intr($13,regs);
  if regs.flags and FCarry = FCarry then SetMode := DEVICE_ERROR
  else SetMode := Mode; {return mode set}
end;{function}



FUNCTION ReadSectors(drive, head, track, sector, numtoread : Byte; buff: Pointer): Byte; assembler;
{function courtesy of Trixter - http://trixter.oldskool.org/}
{ drive = 0 for drive A:, 1 = B:,   }
{ 80h = first hard drive.           }
ASM
  mov  ah,02h
  mov  al,numtoread
  les  bx,buff     { es:bx -> buffer }
  mov  ch,track
  mov  cl,sector
  mov  dh,head
  mov  dl,drive
  int  13h
  {numsectors read in al, status in ah, cf=0 if successful}
END;


function BuffersMatch(Buff1, Buff2 : pSectorBuffer) : Boolean;
var
  i,j,a,b,k   : word;
  Error : Boolean;
begin
  If VERBOSE then WriteLn('Comparing buffers...');
  Error := false;
  for i := 0 to Pred(SizeOf(tSectorBuffer)) do
    if Buff1^[i] <> Buff2^[i] then
    begin
      Error := true;
      k := i;
      i := Pred(SizeOf(tSectorBuffer));
    end;{if}
  BuffersMatch := Not Error;
  If VERBOSE then begin
    Write('Buffers ');
    if Error then begin
      WriteLn('did not match.  Trace:');
      WriteLn('Ofs     Buff1     Buff2');
      if k > 10 then a := k - 10 else a := 0;
      if k < 500 then b := k + 10 else b := 511;
      for j := a to b do
        WriteLn(j,'    ',Buff1^[j],'     ',Buff2^[j]);
    end else Write('matched.');
  end;
end;{function}


Function ParamSpecified(s : string) : boolean;
{returns true is s was specified in a command line parameter,
 either directly or via - or /, e.g. these are equivalent: h, -h, /h}
var
  i,x   : byte;
  found : boolean;
  comp  : string;
begin
  found := false;
  for x := 1 to length(s) do s[x] := UpCase(s[x]);
  for i := 1 to ParamCount do
  begin
    comp := ParamStr(i);
    for x := 1 to length(s) do comp[x] := UpCase(comp[x]);
    if (comp[1] = '/') or (comp[1] = '-') then
      if length(comp) > 1 then comp := copy( comp,2,pred(length(comp)) )
      else comp := '';
    if comp = s then found := true;
    if found then i := ParamCount;
  end;{for}
  ParamSpecified := found;
end;{function ParamSpecified}


var
  res, Device, mode : byte;
  valres            : integer;
  error             : Boolean;
  Buffer1, Buffer2  : pSectorBuffer;
  Ch                : Char;


begin
  If (ParamCount = 0) or (ParamSpecified('?')) or (ParamSpecified('h')) then
    PrintHelp(HelpFull)
  else begin
    Device := 0;
    {first check for verbose mode}
    if ParamSpecified('vv') then VERBOSE := TRUE else VERBOSE := FALSE;

    {user gave some parameters, so see what we're doing}
    if VERBOSE then WriteLn('Checking parameters...');
    if (ParamStr(1) = '80') or (ParamStr(1) = '80h') then Device := $80;
    if (ParamStr(1) = '81') or (ParamStr(1) = '81h') then Device := $81;
    if (ParamStr(1) = '82') or (ParamStr(1) = '82h') then Device := $82;
    if (ParamStr(1) = '83') or (ParamStr(1) = '83h') then Device := $83;
    
    if Device = 0 then
    begin
      if VERBOSE then WriteLn('Device still 0 - exiting');
      PrintHelp(HelpFull)
    end else begin
      if (ParamSpecified('set')) and (ParamCount >= 3) then
      begin
        Val(ParamStr(3),mode,valres);
        if valres <> 0 then PrintHelp(HelpFull)
        else begin
          {all looks OK}
          {if BIU_OFFLOAD was specified, also perform a disk read test to confirm if it's supported}
          If VERBOSE then WriteLn('Allocating buffers');
          New(Buffer1); New(Buffer2);

          error := false;
          if Mode = XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD then
          begin
            {first perform a read against sector 1, which hopefully should always have something on it}
            If VERBOSE then WriteLn('Attempting to read 1st sector of selected device');
            if ReadSectors(Device,0,0,1,1,Buffer1) AND $00FF <> 1 then Error := true;
          end;
          if not error then
          begin
            case SetMode(Device,Mode) of
              XTCF_8BIT_PIO_MODE                   :  WriteLn('8-bit PIO mode selected.');
              XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD  :  WriteLn('8-bit PIO with BIU offload mode selected.');
              XTCF_DMA_MODE                        :  WriteLn('DMA mode selected.');
              INVALID_MODE                         :  begin 
                                                        WriteLn('Invalid mode specified.');
                                                        Error := true;
                                                      end;
              DEVICE_ERROR                         :  begin 
                                                        WriteLn('Selected device not XT-CF.');
                                                        Error := true;
                                                      end;
            end;{case}
            If VERBOSE then
            begin
              if error then WriteLn('Error flag set - SetMode() failed.  Continuing anyhow.')
              else WriteLn('SetMode() succeeded.');
            end;{if VERBOSE}
            if (Mode = XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD) and (not error) then
            begin
              {read sector 1 again, and check it matched the first read}
              If VERBOSE then WriteLn('Attempting to read 1st sector of selected device again');
              if ReadSectors(Device,0,0,1,1,Buffer2) AND $00FF <> 1 then Error := true;
              if not error then
              begin
                If VERBOSE then WriteLn('Read second buffer OK');
                if not BuffersMatch(Buffer1,Buffer2) then
                begin
                  WriteLn('It appears that BIU offload mode is not supported on this machine.');
                  Write('Reset to 8-bit PIO <Y/N>? ');
                  Repeat Ch := UpCase(ReadKey) until Ch in ['Y','N'];
                  WriteLn(Ch);
                  if Ch = 'Y' then
                  begin
                    if SetMode(Device,XTCF_8BIT_PIO_MODE) <> XTCF_8BIT_PIO_MODE then
                    begin
                      WriteLn('WARNING: Unable to return device to 8-bit PIO mode.  Restart system to');
                      Write('         avoid system corruption.');
                      repeat Ch := ReadKey; until Ch = 'C'; {soft hang}
                    end else WriteLn('8-bit PIO mode selected.');
                  end;{if Ch='Y'}
                end;{if not BuffersMatch}
              end;{if not error}
            end;
          If VERBOSE then WriteLn('About to dispose of buffers');
          Dispose(Buffer1); Dispose(Buffer2);
          If VERBOSE then WriteLn('Buffer RAM freed');
          end {if not error}
          else WriteLn('Error encountered reading from specified device.');
        end;{if/else}
      end {if ParamSpecified('set')}
      else if ParamCount = 1 then
      begin
        PrintHelp(HelpNameOnly);
        Write('Device ',ParamStr(1),': ');
        case GetMode(Device) of
          XTCF_8BIT_PIO_MODE                   :  WriteLn('8-bit PIO');
          XTCF_8BIT_PIO_MODE_WITH_BIU_OFFLOAD  :  WriteLn('8-bit PIO with BIU offload');
          XTCF_DMA_MODE                        :  WriteLn('DMA');
          DEVICE_ERROR                         :  WriteLn('Device is not XT-CF.');
        end;{case}
      end {if ParamCount}
      else PrintHelp(HelpFull);
    end;{if Device = 0/Else}
  end;{if ParamCount = 0}
  If VERBOSE then WriteLn('Program terminating - returning control to OS.');
END.{Program}

See Also