{---------------------------------------------------------------------}
{<<<<<<<<<<<<<<<<<<<<<<<< Msk v5.1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}
{---------------------------------------------------------------------}
{                                                                     }
{  Mise … jour  : 11 Dec 95                                           }
{  Version      : MSK2CIF.PAS                                         }
{  By           : Etienne SICARD                                      }
{                                                                     }
{  Objet        : Convert MSK files into CIF files                    }
{                                                                     }
{---------------------------------------------------------------------}

program msk2cif(input,output);

USES dos;


CONST
   pwell   = 1; nwell   = 2; diffp   = 3; diffn   = 4;
   contact = 5; poly    = 6; metal   = 7; via     = 8;
   metal2  = 9; basep   = 10;basen   = 11; gatep  = 12;
   gaten   = 13;passiv = 14; poly2   = 15; null = 0;


TYPE
   stringType = string[64];

VAR
   IOError    : integer;
   mo,dd,yy,js: word;
   hh,mi,ss,ms: word;
   lambda       : real;
   gateLength : real;
   i,layer      : integer;
   oldLayer   : integer;
   xb,yb      : real;
   xh,yh      : real;
   layerCount : ARRAY[1..15] of integer;
   layerNames : ARRAY[1..15] OF stringType;

   boxCount   : integer;
   outputFile : text;
   inputFile  : text;
   layerFile  : text;
   filename   : stringType;
   st         : stringType;
   ch,ch1,ch2    : char;
   dvia,dcontact : real;
   sizeVia       : real;
   sizeContact : real;
   cellName  : stringType;



PROCEDURE AddAppendix(VAR nm:StringType;app:StringType);
VAR
  i      : integer;
  test   : boolean;

BEGIN
  test:=false;

  FOR i:=1 to length(nm) do
  IF nm[i]='.' then
  BEGIN
      nm[i+1]:=app[1];
      nm[i+2]:=app[2];
      nm[i+3]:=app[3];
      test := TRUE
  END;

  IF not test then
     nm:=nm+'.'+app
END;






PROCEDURE ReadValue(VAR i:integer);
VAR
  signe    : integer;
  ch       : char;
  localTest: boolean;

BEGIN
  i:=0;
  signe:=1;
  read(InputFile,ch);

  while (ch=' ')AND(Not EOLN(InputFile)) do read(InputFile,ch);
  if ch='+' then read(InputFile,ch);
  if ch='-' then
  BEGIN
      signe:=-1;
      read(InputFile,ch)
  END;

  localTest := ch IN ['0'..'9'];
  while LocalTest DO
  BEGIN
     i := i*10+ord(ch)-48;
     localTest :=Not EOLN(InputFile);
     IF localTest THEN read(InputFile,ch);
     localTest :=localTest AND (ch in ['0'..'9']);
  END;

  i:=i*signe
END;




PROCEDURE ReadREC;
VAR
   i      : integer;
   txt1   : stringType;
   ch     : char;
   i1,j1  : integer;
   i2,j2  : integer;
   xd,yd  : longInt;
   x0,y0  : longInt;
   code   : string[2];
   st     : stringType;

BEGIN
   code:='  ';
   read(InputFile,ch);
   ReadValue(i1);  { Left lower corner }
   ReadValue(j1);
   ReadValue(i2);  { size X }
   ReadValue(j2);  { size Y }

   readln(InputFile,code[1],code[2]);

   IF code='PA' THEN layer := passiv ELSE
   IF code='NW' THEN layer := nwell ELSE
   IF code='PW' THEN layer := pwell  ELSE
   IF code='DP' THEN layer := diffp ELSE
   IF code='DN' THEN layer := diffn ELSE
   IF code='CO' THEN layer := contact ELSE
   IF code='PO' THEN layer := poly ELSE
   IF code='ME' THEN layer := metal ELSE
   IF code='VI' THEN layer := via ELSE
   IF code='M2' THEN layer := metal2 ELSE
   IF code='BP' THEN layer := basep ELSE
   IF code='BN' THEN layer := basen;

   Inc(layerCount[layer]);

   IF layer<>oldLayer THEN
   BEGIN
      oldLayer := layer;
      st := LayerNames[layer];
      writeln(OutputFile,'L ',st,';');
   END;

{ Scale the coordinates and computes the box center ... }

   xd := round(1000*lambda*i2);
   yd := round(1000*lambda*j2);
   x0 := round(1000*lambda*(i1+i2/2));
   y0 := round(1000*lambda*(j1+j2/2));

{ Adjust the coordinates to fit the contact minimum and }
{ maximum rules : contacts are drawn by MSK with a default 2 * lambda }

   IF layer=contact THEN
   BEGIN
      xd := xd + round(dcontact);
      yd := yd + round(dcontact);
   END;


{ Then same for vias : they are drawn by MSK with 3 * lambda }
{ Only small vias; big ones for pads not touch }

   IF (layer=via)AND(xd<10000) THEN
   BEGIN
      xd := xd + round(dvia);
      yd := yd + round(dvia);
   END;

   writeln(OutputFile,'B ',xd,' ',yd,' ',x0,',',y0,';');
   Inc(boxCount);
   IF (boxCount MOD 64)=0 THEN
    writeln('. ',boxCount,' box(es) converted');
END;


PROCEDURE ReadLayerNames;
VAR
   i : integer;
   ch : char;

BEGIN
   Assign(layerFile,'MSK2CIF.LAY');
   Reset(layerFile);
   IOError := IOResult;
   IF IOError<>0 THEN
   BEGIN
      writeln('# Error: "MSK2CIF.LAY" layer description file open error...');
      Halt;
   END;
   WHILE NOT eof(layerFile) DO
   BEGIN
      Read(layerFile,i,ch);
      IF i<=0 THEN i:=1 ELSE IF i>15 THEN i:=15;
      Readln(layerFile,LayerNames[i]);
{
      writeln('# layer nø ',i,': "',LayerNames[i],'"');
}
   END;
   Close(layerFile);
END;


{---(MskToCif)-----------------------------------------------------}
BEGIN
   writeln;
   writeln('MSK2CIF Version 2.1 by Etienne SICARD');
   writeln('Convert MSK to CIF...');

{ Did you give a name parameter ? }

   filename:= paramStr(1);
   IF (length(filename)=0) THEN
   BEGIN
      write('Enter MSK input file:');
      readln(filename);
   END;

{ Open the input file }

   AddAppendix(filename,'MSK');
   Assign(inputFile,filename);
   Reset(inputFile);
   IOError := IOResult;
   IF IOError<>0 THEN
   BEGIN
      writeln('# Error: "',filename,'" input file open error...');
      Halt;
   END;

{ Open the output file }

   boxCount := 0;
   AddAppendix(filename,'CIF');
   Assign(OutputFile,filename);
   rewrite(OutputFile);
   IOError:=IOResult;

   IF IOError<>0 THEN
   BEGIN
      writeln('# Error: "',filename,'" output file open error...');
      Halt;
   END;


   write('Enter technology (æm):');
   readln(gateLength);
   lambda := gateLength/2;

{ Oversize or undersize the contact in order to fit }
{ the minimum and maximum size rule }

   writeln;
   write('Enter minimum and maximum CONTACT size (æm):');
   readln(sizeContact);
   dcontact := sizeContact-2*lambda;
   dcontact := dcontact*1000;

{ Same for vias ... }

   write('Enter minimum and maximum VIA size (æm):');
   readln(sizeVia);
   dvia := sizeVia -3*lambda;
   dvia:= dvia*1000;

   boxCount := 0;
   oldLayer := null;

   FOR i:=1 TO 15 DO
   BEGIN
      layerCount[i] := 0;
      layerNames[i] := '?'
   END;

   ReadLayerNames;

   GetDate(yy,mo,dd,js);
   GetTime(hh,mi,ss,ms);
   writeln(OutputFile,'( Conversion from MSK v5.1 to Cif )');
   writeln(OutputFile,'( Version ',dd:2,'.',mo:2,'.',yy:2,'  ',hh:2,':',mi:2,')');
   writeln(OutputFile);

   writeln;
   writeln(OutputFile,'DS 1 1 1;');

{ Give the top cell name }

   write('Enter the top cell name :');
   readln(cellName);

   writeln(OutputFile,'9 ',cellName,' ;');

   WHILE NOT Eof(inputFile) DO
   BEGIN
      read(InputFile,ch,ch1,ch2);
      if (ch='R')AND(ch1='E') then ReadREC else
      readln(InputFile)
   END;
   writeln(outputFile,'DF;');
   writeln(outputFile,'E');
   writeln('. ',boxCount,' box(es) converted');

{ Statistics... }

   writeln;
   writeln('Statistics');

   FOR i:=1 TO 15 DO
    IF layerCount[i]<>0 THEN
    BEGIN
       CASE i OF
        1 : st := 'pwell';
        2 : st := 'nwell';
        3 : st := 'diffp';
        4 : st := 'diffn';
        5 : st := 'contact';
        6 : st := 'poly';
        7 : st := 'metal';
        8 : st := 'via';
        9 : st := 'metal2';
       10 : st := 'basep';
       11 : st := 'basen';
       END;
       writeln('. ',layerCount[i],' ',st,' boxes');
    END;
   writeln;

   Close(InputFile);
   Close(OutputFile);
END.

{----(MSK2CIF)-------------------------------------------------}

