unit picunit;                                   {PIC-programmer unit, v23}
interface                                       {By Jens Dyekj‘r Madsen}
type
  pgmmemtype = array[0..$3ff] of word;          {Program memory type}
  datmemtype = array[0..$3f] of word;           {Data memory type}
  cfgmemtype = array[0..$7] of word;            {Config memory type}

var
  com: byte;                                    {COM port}
  pgmmem: pgmmemtype;                           {Program memory}
  datmem: datmemtype;                           {Data memory}
  cfgmem: cfgmemtype;                           {Config memory}

procedure eraseall;                             {Erase code}
procedure readcfg;                              {Read config}
procedure readall;                              {Read code+data}
procedure progcfg;                              {Program config}
procedure progall;                              {Program code+data}
function hwerror: boolean;                      {True if error}


implementation
uses delays,jdm84io;                             {Use delay and I/O}

const                                           {Define Commands}
  LoadCfg  = $1600;                             {Load Configuration}
  LoadPgm  = $1602;                             {Load Data for Program Memory}
  ReadPgm  = $1604;                             {Read Data from Program Memory}
  IncAdr   = $0606;                             {Increment Address}
  Begpgm   = $0608;                             {Begin Programming}
  LoadData = $1603;                             {Load Data for Data Memory}
  ReadData = $1605;                             {Read Data from Data Memory}
  ErasePgm = $0609;                             {Bulk Erase Program Memory}
  EraseData= $060b;                             {Bulk Erase Data Memory}
  EraseAll1= $0601;                             {EraseAll, first}
  EraseAll2= $0607;                             {EraseAll, next}

                                                {Define time constants}
  t10m = 200;                                   {10ms, programming time}

var
  data: integer;                                {Return data}

procedure start;                                {Start}
begin
  setcom(com);                                  {Setup com-port}
  mclr;                                         {Reset}
end;

procedure stop;                                 {Stop}
begin
  mclr;                                         {Reset}
  timerstop;                                    {Stop timers}
end;

procedure pgm(cmd, d: integer);                 {Read/write commands serial}
var
  c: longint;                                   {Shift variable}
  i: integer;                                   {Count variable}
begin
  c:=lo(cmd)+longint(d) shl 7;                  {Setup bits}
  data:=0;                                      {Clear input bits}
  for i:=1 to hi(cmd) do                        {Shift bits}
  begin
    data:=data shr 1 + din shl 13;              {Read data}
    dout(c and 1);                              {Write data}
    c:=c shr 1;                                 {Next bit}
  end;
end;

function hwerror: boolean;                      {Programmer ok}
begin
  start;                                        {Start}
  hwerror:=(err<>0);                            {Error if not ok}
  stop;                                         {Stop}
end;

procedure rdmem(VAR memory; cmd,count:integer); {Read data to memory}
var
  mem: array[0..$3ff] of word absolute memory;  {Memory}
  adr: integer;                                 {Adress counter}
begin
  for adr:=0 to count do                        {Adress 0..count}
  begin
    pgm(cmd,-1);                                 {Read}
    mem[adr]:=data;                             {Store data}
    pgm(incadr,0);                              {Next adress}
  end;
end;

procedure progmem(VAR memory; rdcmd, ldcmd, count:integer);
var
  mem: array[0..$3ff] of word absolute memory;
  adr: integer;                                 {Adress counter}
begin
  for adr:=0 to count do                        {Adress 0..count}
  begin
    pgm(rdcmd,-1);                               {Read}
    if data<>mem[adr] then                      {Need to be programmed?}
    begin
      pgm(ldcmd,mem[adr]);                      {Load}
      pgm(begpgm,0);                            {Begin programming}
      waitdelay(t10m);                          {Delay 10ms}
    end;
    pgm(incadr,0);                              {Next adress}
  end;
end;

procedure eraseall;                             {Erase code}
var
  i: integer;                                   {Adress counter}
begin
  start;                                        {Start, Reset}
  pgm(loadcfg,$3fff);                           {Setup config word}
  for i:=1 to 7 do pgm(incadr,0);               {Adress at config word}
  pgm(Loadpgm,$3fff);                           {Load config word}
  pgm(EraseAll1,0);                             {Start erase}
  pgm(EraseAll2,0);
  pgm(begpgm,0);                                {Start programming}
  waitdelay(t10m);                              {Delay 10ms}
  pgm(EraseAll1,0);                             {Stop erase}
  pgm(EraseAll2,0);
  stop;                                         {Stop}
end;

procedure readcfg;                              {Read config}
begin
  start;                                        {Start, Reset}
  pgm(loadcfg,0);                               {Config area}
  rdmem(cfgmem,readpgm,7);                      {Read config}
  stop;                                         {Stop}
end;

procedure readall;                              {Read code+data}
begin
  start;                                        {Start, Reset}
  rdmem(pgmmem,readpgm,$3ff);                   {Read program}
  rdmem(datmem,readdata,$3f);                   {Read data}
  stop;                                         {Stop}
end;

procedure progcfg;                              {Program config}
begin
  start;                                        {Start, Reset}
  pgm(loadcfg,0);                               {Config area}
  progmem(cfgmem,readpgm,loadpgm,7);            {PGM config}
  stop;                                         {Stop}
end;

procedure progall;                              {Program code+data}
begin
  start;                                        {Start, Reset}
  progmem(pgmmem,readpgm,loadpgm,$3ff);         {PGM program}
  progmem(datmem,readdata,loaddata,$3f);        {PGM data}
  stop;                                         {Stop}
end;

end.
