{ Atmel SPI programmer V0.1 }
Uses
    Crt, Dos;
Const
     PRN_dat = $378;
     PRN_inp = $379;
     PRN_com = $37A;
     wdel = 800;        { port operation delay }
     CheckBreak : Boolean = True;

     EN_PRG_1 : Byte = 128 + 32 + 8 + 4;
     EN_PRG_2 : Byte = 64 + 16 + 2 + 1;

     ERASE_1 : Byte = 128 + 32 + 8 + 4;
     ERASE_2 : Byte = 4;

     ROM_RD_1 : Byte = 1;
     ROM_WR_1 : Byte = 2;

     RAM_RD_1 : Byte = 5;
     RAM_WR_1 : Byte = 6;

     DEF_ON_1 : Byte = 128 + 32 + 8 + 4;
     DEF_ON_2 : Byte = 7;

Message0 = 'Use :';
Message1 = '      spi /r file.bin - to ROM read';
Message3 = '      spi /w file.bin [/1] [/2] [/3] - to ROM write';
Message4 = '                     /1 L1=1    /2 L2=1   /3 L3 = 1';
Message2 = '      spi /e          - to erase ROM';

Var
   fdat  : file of Byte;
   fname : String;
   sDat  : Byte;
   HAdr  : Byte;
   LAdr  : Byte;
   Def_byte : Byte;
   Reslt : Byte;
   Stat  : Shortint;
   i     : Integer;
   Buf   : Array [0..8191] of Byte;
   BufSize : Word;
   x,y   : Byte;

{Read SPI byte}
function SPI_read : Byte; assembler;
asm
      mov    cx,8
      mov    dx,PRN_dat
      cli
@read:
      mov    al,80h     { clc = 1 }
      out    dx,al
      mov    bx,wdel    { wait }
@d1:
      dec    bx
      jnz    @d1
      mov    dx,PRN_inp
      in     al,dx      { get data }
      rcl    al,1
      rcl    ah,1       { ah - read result }
      mov    dx,PRN_dat
      mov    al,0       { clc = 0 }
      out    dx,al
      mov    bx,wdel    { wait }
@d2:
      dec    bx
      jnz    @d2
      loop   @read
      sti
      not    ah
      mov    al,ah      { return data }
end;

{Write SPI byte}
function SPI_write(Dout : Byte) : Byte;  assembler;
asm
      mov    cx,8
      mov    ah,Dout
      mov    dx,PRN_dat
      cli
@write:
      rcl    ah,1
      rcl    al,1
      and    al,1       { data out, clc = 0 }
      out    dx,al
      mov    bx,wdel    { wait }
@d1:
      dec    bx
      jnz    @d1
      or     al,80h     { data out, clc = 1 }
      out    dx,al
      mov    bx,wdel    { wait }
@d2:
      dec    bx
      jnz    @d2
      and    al,1       { clc = 0 }
      out    dx,al
      mov    bx,wdel    { wait }
@d3:
      dec    bx
      jnz    @d3
      loop   @write
      mov    al,0      { return OK }
      out    dx,al
      sti
end;

{Write byte as hex charters}
procedure bin_hex(var bin:byte);
var
   h,l : byte;
begin
     h:= bin shr 4;
     If h < $0A then h := h + $30
     else h:= h + $37;
     l:= bin AND $0F;
     If l < $0A then l := l + $30
     else l := l + $37;
     Write(Chr(h),Chr(l));
end;

Begin
   Writeln('ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»');
   Writeln('º  Atmel At89S8252 SPI programmer V1.0 (c)Chum_A - 2000  º');
   Writeln('ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼');
   Port[PRN_com] := 1; { chip reset }
   Port[PRN_dat] := 0; { clc = 0, dat = 0}
   If not ((ParamStr(1) = '/e') or
          ((ParamStr(1) = '/w') and (ParamStr(2) <> '')) or
          ((ParamStr(1) = '/r') and (ParamStr(2) <> '')))
                             then begin
                                   Writeln;
                                   Writeln(Message0);
                                   Writeln(Message1);
                                   Writeln(Message2);
                                   Writeln(Message3);
                                   Writeln(Message4);
                                   Halt(1);
                              end;
     Delay(100);                        { init chip }
           sDat := SPI_write(EN_PRG_1);
           sDat := SPI_write(EN_PRG_2);
           sDat := SPI_write(EN_PRG_2);
     i := 0;
     Stat := 0;
     x := WhereX;
     y := WhereY;
     fname := ParamStr(2);

    If ParamStr(1) = '/e' then begin { erase chip }
           Writeln('Erase chip ROM');
           sDat := SPI_write(ERASE_1);
           sDat := SPI_write(ERASE_2);
           sDat := SPI_write(ERASE_2);
           delay(2000);
   end; {erase chip}

    If ParamStr(1) = '/r' then begin {read device}
     Write('Read -> ',Stat,'%');
     For HAdr := 0 to $1F do
      begin
         For LAdr := 0 to $FF do
          begin
           sDat := SPI_write(ROM_RD_1 OR (HAdr SHL 3));
           sDat := SPI_write(LAdr);
           Buf[i] := SPI_read;
           Inc(i);
          end;
       Stat := Stat + 3;
       GotoXY(x,y);
       Write('Read -> ',Stat,'%');
      end;
     GotoXY(x,y);
     Writeln('Read -> 100%');
     Assign(fdat,fname);
     Rewrite(fdat);
     For i := 0 to 8191 do Write(fdat,Buf[i]);
     Close(fdat);
 end; {read device}

    If ParamStr(1) = '/w' then begin {write device}
     Write('Write -> ',Stat,'%');
     Assign(fdat,fname);
     Reset(fdat);
     i := 0;
     Repeat
      Read(fdat,Buf[i]);
      Inc(i);
     Until eof(fdat);
     Close(fdat);
     BufSize := i;

     HAdr := 0;
     LAdr := 0;
     i := 0;

     Repeat
 { Compare BUF - ROM }
           sDat := SPI_write(ROM_RD_1 OR (HAdr SHL 3));
           sDat := SPI_write(LAdr);
           sDat := SPI_read;
           If Buf[i] <> sDat then
  begin { Write current adress }
           sDat := SPI_write(ROM_WR_1 OR (HAdr SHL 3));
           sDat := SPI_write(LAdr);
           sDat := SPI_write(Buf[i]);
           delay(3);
 { Check ROM }
           sDat := SPI_write(ROM_RD_1 OR (HAdr SHL 3));
           sDat := SPI_write(LAdr);
           sDat := SPI_read;
           If Buf[i] <> sDat then begin
                                      Writeln;
                                      Write(' Error at ');
                                      Bin_Hex(HAdr);
                                      Bin_Hex(LAdr);
                                      Write(' : write / read - ');
                                      Bin_Hex(Buf[i]);
                                      Write(' / ');
                                      Bin_Hex(sDat);
                                      Writeln;
                                      x := WhereX;
                                      y := WhereY;
                                 end;
  end; { Write current adress }
           If LAdr = $FF then begin             { compute next Adr}
                                   LAdr := 0;
                                   Inc(HAdr);
                                   Stat := Stat + 3;
                                   GotoXY(x,y);
                                   Write('Write -> ',Stat,'%');
                              end
                          else
                              Inc(LAdr);
           Inc(i);
           Dec(BufSize);
     Until BufSize = 0;
     GotoXY(x,y);
     Writeln('Write -> 100%');
     Def_byte := DEF_ON_2;
     If ParamStr(3) = '/1' then Def_byte := Def_Byte OR $80;
     If ParamStr(4) = '/2' then Def_byte := Def_Byte OR $40;
     If ParamStr(5) = '/3' then Def_byte := Def_Byte OR $20;
     If Def_byte <> DEF_ON_2 then begin
                                   GotoXY(x,y);
                                   Writeln('Write code protect');
                                   sDat := SPI_write(DEF_ON_1);
                                   sDat := SPI_write(DEF_ON_2);
                                   sDat := SPI_write(DEF_ON_2);
                                  end;
 end; {write device}

     Port[PRN_com] := 0;        { /chip reset }
     Writeln('Bye !');
END.