unit jdm84io;                                   { JDM84 IO-routines, v23}
interface                                       { By Jens Dyekj‘r Madsen}
{$s-}
const
  err: byte = 0;                                { Returns error value   }
  base: word = 0;                               { Com-port base adress  }
  din: byte = 0;                                { Returns PIC16C84 data }

procedure setcom(n: byte);                      { Setup com-port        }
procedure mclr;                                 { Reset                 }
procedure dout(val: byte);                      { Output PIC16C84 data  }
procedure sda(val: byte);                       { Set SDA = val         }
procedure scl(val: byte);                       { Set SCL = val         }
function rda: byte;                             { Return SDA            }


implementation

uses delays;                                    { Uses delay routines   }

const
  t100u = 2;                                    { 100æs delay           }
  t200m = 4000;                                 { 0.2s power on delay   }
  run: byte = 0;                                { Run state             }

var
  lastout: byte;                                { Saves last output     }
  i: integer;                                   { Counter               }

procedure cli;  inline($fa);                    { Disable interrupts    }
procedure sti;  inline($fb);                    { Enable interrupts     }


{ Initialize routines }

procedure setcom(n: byte);                      { Setup com-port        }
begin
  err:=3;                                       { Error 3 if no comport }
  if (n=0) or (n>4) then exit;                  { Check comport value   }
  base:=memw[$40:2*pred(n)];                    { Setup RS232 port      }
  err:=byte(base=0);                            { Return error value    }
  run:=0;                                       { Not run               }
end;

procedure mclr;                                 { Reset / start         }
var
  mstate: array[1..4] of byte;                  { Saves modem state     }
begin
  timerstart;                                   { Initialize timers     }
  run:=0;                                       { Not run               }
  err:=1;                                       { Assume error 1        }
  if base=0 then exit;                          { Exit if comport error }
  err:=2;                                       { Assume error 2        }
  for i:=2 to 4 do mstate[i]:=port[base+i];     { Store modem state     }
  port[base+2]:=6;                              { Disable fifo          }
  port[base+3]:=3;                              { 8 bit, no parity      }
  mstate[1]:=port[base+1];                      { Store IER             }
  port[base+1]:=0;                              { No interrupts         }
  port[base+4]:=0;                              { RTS low, DTR low      }
  shortdelay;                                   { Wait                  }
  if port[base+6] and $10 <> 0 then             { Check if modem        }
  begin
    for i:=1 to 4 do port[base+i]:=mstate[i];   { Restore modem state   }
    exit;                                       { and exit              }
  end;
  for i:=0 to 20 do                             { Clock data out, EEPROM}
  begin
    port[base+4]:=succ((i and 1)shl 1);         { DTR high, Toggle RTS  }
    shortdelay;                                 { Wait                  }
  end;
  for i:=1 to 10 do                             { Check if programmer ok}
  begin
    port[base+4]:=i and 1;                      { RTS low, Toggle DTR   }
    shortdelay;                                 { Wait                  }
    if ((port[base+6] shr 4)xor i) and 1<>0 then
    begin
      for i:=1 to 4 do port[base+i]:=mstate[i]; { Restore modem state   }
      exit;                                     { and exit              }
    end;
  end;                                          { RTS low, DTR low      }
  port[base+3]:=$80;                            { Setup baudrate        }
  port[base]:=1;                                { to 115 Kbaud          }
  port[base+1]:=0;
  port[base+3]:=3;                              { 8 bit, no parity      }
  err:=0;                                       { Check is ok           }
  run:=1;                                       { Run is ok             }
  lastout:=0;                                   { Update lastout        }
end;


{ PIC16C84 routines }

procedure dout(val: byte);                      { Output PIC16C84 data  }
begin
  if run=0 then exit;                           { Exit if not run       }
  if run=1 then                                 { If not program mode   }
  begin
    port[base+3]:=$43;                          { Enable Break, no reset}
    waitdelay(t200m);                           { Power on Delay, 200ms }
    port[base+3]:=3;                            { Start reset           }
    cli;                                        { Use short reset       }
    for i:=1 to 3 do                            { pulses                }
    begin                                       { to not start auto go  }
      port[base]:=0;                                    { Output zero   }
      repeat until boolean(port[base+5] and $20);       { Wait on empty }
    end;
    port[base+3]:=$43;                          { Enable break, no reset}
    sti;                                        { Interrupts ok         }
    waitdelay(t100u);                           { Wait                  }
    run:=2;                                     { Program mode enabled  }
  end;
  cli;                                          { Disable interrupts    }
  port[base+4]:=val or 2;                       { Output value, Clk high}
  shortdelay;                                   { Wait                  }
  din:=(port[base+6] shr 4) and 1;              { Return data           }
  port[base+4]:=val and din;                    { Output value, Clk low }
  sti;                                          { Interrupts ok         }
  shortdelay;                                   { Recharge              }
  if din<>val then for i:=1 to 4 do shortdelay; { Extra rechage delay   }
end;


{ EEPROM (I2C) routines }

function rda: byte;                             { Read data             }
begin
  if run=0 then rda:=0 else                     { Return zero if not run}
    rda:=(port[base+6] shr 4) and 1;            { Setup rda value       }
end;

procedure sda(val: byte);                       { Set SDA = val         }
begin
  if run=0 then exit;                           { Exit if not run       }
  lastout:=(lastout and $fe) or val;            { Update lastout        }
  port[base+4]:=lastout;                        { Output lastout        }
  shortdelay;                                   { Short delay           }
end;

procedure scl(val: byte);                       { Set SCL = val         }
begin
  if run=0 then exit;                           { Exit if not run       }
  lastout:=(lastout and $fd) or 2*val;          { Update lastout        }
  port[base+4]:=lastout;                        { Output lastout        }
  shortdelay;                                   { Short delay           }
end;

end.
