Browse Source

+ ppu stuff

peter 27 years ago
parent
commit
efd2514366
1 changed files with 198 additions and 120 deletions
  1. 198 120
      docs/prog.tex

+ 198 - 120
docs/prog.tex

@@ -2559,130 +2559,213 @@ point mode have not been extensively tested as of version 0.99.5.
 
 
 \chapter{Anatomy of a unit file}
 \chapter{Anatomy of a unit file}
 \label{ch:AppA}
 \label{ch:AppA}
-A unit file consists of basically five parts:
+
+The best and most updated documentation about the ppu files can be found
+in \file{ppu.pas and \file{ppudump.pp} which can be found in
+\dir{rtl/utils/}.
+
+To read or write the ppufile, you can use the ppu unit \file{ppu.pas}
+which has an object called tppufile which holds all routines that deal
+with ppufile handling. Describing the layout of a ppufile, the methods
+which can be used for it are described.
+
+A unit file consists of basically five or six parts:
 \begin{enumerate}
 \begin{enumerate}
 \item A unit header.
 \item A unit header.
-\item A file references part. This contains the references to used units
-and sources with name, checksum and time stamps.
+\item A file interface part.
 \item A definition part. Contains all type and procedure definitions.
 \item A definition part. Contains all type and procedure definitions.
-\item A Symbol part. Contains all symbol names and references to their
+\item A symbol part. Contains all symbol names and references to their
 definitions.
 definitions.
-\item A list of units that are in the implementation part.
+\item A browser part. Contains all references from this unit to other
+units and inside this unit. Only available when the uf_has_browser flag is
+set in the unit flags
+\item A file implementation part (currently unused).
+implementation part.
 \end{enumerate}
 \end{enumerate}
 
 
-The header consists of a sequence of 20 bytes, together they give some
-information about the unit file, the compiler version that was used to
-generate the unit file, etc. The complete layout can be found in
-\seet{UnitHeader}. The header is generated by the compiler, and changes only
-when the compiler changes. The current and up-to-date header definition can
-be found in the \file{files.pas} source file of the compiler. Look in this
-file for the \var{unitheader} constant declaration.
-\begin{FPCltable}{ll}{Unit header structure.}{UnitHeader} \hline
-Byte & What is stored \\ \hline
-0..3 & The letters 'PPU' in upper case. This acts as a check. \\
-4..6 & The unit format as a 3 letter sequence : e.g. '0','1,'2' for format
-12. \\
-7,8 & The compiler version and release numbers as bytes. \\
-9 & The target OS number. \\
-10 & Unit flags.\\
-11..14 & Checksum (as a longint). \\
-15,16 & unused (equal to 255). \\
-17..20 & Marks start of unit file. \\ \hline
-\end{FPCltable}
-After the header, in the second part, first the list of all source files for
-the unit is written. Each name is written as a direct copy of the string in
-memory, i.e. a length bytes, and then all characters of the string. This
-list includes any file that was included in the unit source with the
-\var{\{\$i file\}} directive. The list is terminated with a \var{\$ff} byte
-marker.
-After this, the list of units in the \var{uses} clause is written,
-together with their checksums. The file is written as a string, the checksum
-as a longint (i.e. four bytes). Again this list is terminated with a
-\var{\$ff} byte marker.
-
-After that, in the third part, the definitions of all types, variables,
-constants, procedures and functions are written to the unit file.
-
-They are written in the following manner: First a byte is written, which
-determines the kind of definition that follows. then follows, as a series of
-bytes, a type-dependent description of the definition. The exact byte order
-for each type can be found in \seet{DefDef}
-
-\begin{FPCltable}{lccl}{Description of definition fields}{DefDef} \\hline
-Type & Start byte & Size & Stored fields \\ \hline\hline
-Pointer & 3 & 4 & Reference to the type pointer points to. \\ \hline
-Base type & 2 & 9 & 
-\begin{tabular}[t]{l}
-1 byte to indicate base type. \\
-4-byte start range \\
-4-byte end range \\
-\end{tabular}\\ \hline
-Array type &5 & 16 & 
-\begin{tabular}[t]{l}
-4-byte reference to element type. \\ 
-4-byte reference to range type.\\
-4-byte start range (longint) \\
-4-byte end range (longint)\\
-\end{tabular} \\ \hline
-Procedure & 6 & ? &
-\begin{tabular}[t]{l} 
-4-byte reference to the return type definition. \\
-2 byte Word containing modifiers. \\
-2 byte Word containing number of parameters. \\
-5 bytes per parameter.\\
-1 byte : used registers. \\
-String containing the mangled name. \\
-8 bytes.
-\end{tabular}
-\\ \hline
-Procedural type & 21 & ? &
-\begin{tabular}[t]{l} 
-4-byte reference to the return type definition. \\
-2 byte Word containing modifiers. \\
-2 byte Word containing number of parameters. \\
-5 bytes per parameter.  \\
-\end{tabular} 
-\\ \hline
-String & 9 & 1 & 1 byte containing the length of the string. \\
-Record & 15 & variable & 
-\begin{tabular}[t]{l}
-Longint indicating record length \\
-list of fields, to be read as unit in itself. \\
-\var{\$ff} end marker.
-\end{tabular} \\ \hline
-Class & 18 & variable & 
-\begin{tabular}[t]{l}
-Longint indicating data length \\
-String with mangled name of class.\\
-4 byte reference to ancestor class.\\
-list of fields, to be read as unit in itself. \\
-\var{\$ff} end marker.
-\end{tabular} \\ \hline
-file & 16 & 1(+4) & 
-\begin{tabular}[t]{l}
-1 byte for type of file. \\
-4-byte reference to type of typed file. 
-\end{tabular}\\ \hline
-Enumeration & 19 & 4 & Biggest element. \\ \hline
-set & 20 & 5 & 
-\begin{tabular}[t]{l}
-4-byte reference to set element type. \\
-1 byte flag.
-\end{tabular} \\ \hline \hline 
-\end{FPCltable}
-This list of definitions is again terminated with a \var{\$ff} byte marker. 
 
 
-After that, a list of symbols is given, together with a reference to a
-definition. This represents the names of the declarations, and the
-definition they refer to.
+We will first create an object ppufile which will be used below. We are
+opening unit test.ppu as an example.
 
 
-A reference consists of 2 words : the first word indicates the unit number
-(as it appears in the uses clause), and the second word is the number of the
-definition in that unit. A \var{nil} reference is stored as \var{\$ffffffff}. 
+var
+  ppufile : pppufile;
+begin
+{ Initialize object }
+  ppufile:=new(pppufile,init('test.ppu');
+{ open the unit and read the header, returns false when it fails }
+  if not ppufile.open then
+    error('error opening unit test.ppu');
+
+{ here we can read the unit }
+
+{ close unit }
+  ppufile.close;
+{ release object }
+  dispose(ppufile,done);
+end;
 
 
-After this follows again a \var{\$ff} byte terminated list of filenames: The
-names of the units in the \var{uses} clause of the implementation section.
 
 
+Note: When a function fails (for example not enough bytes left in an
+entry) it sets the ppufile.error variable.
+
+
+The header constist of a record containing 24 bytes:
+
+tppuheader=packed record                                                      
+    id       : array[1..3] of char; { = 'PPU' }                                 
+    ver      : array[1..3] of char;                                             
+    compiler : word;                                                            
+    cpu      : word;                                                            
+    target   : word;                                                            
+    flags    : longint;                                                         
+    size     : longint; { size of the ppufile without header }                  
+    checksum : longint; { checksum for this ppufile }                           
+  end;                 
+
+The header is already read by the ppufile.open command. You can access all
+fields using ppufile.header which holds the current header record
+
+id	 this is allways 'PPU', function:
+          function ppufile.CheckPPUId:boolean;
+ver	 ppu version, currently '015'
+	  function ppufile.GetPPUVersion:longint; (returns 15)
+compiler compiler version used to create the unit. Doesn't contain the
+	 patchlevel. Currently 0.99 where 0 is the high byte and 99 the
+	 low byte
+cpu	 cpu for which this unit is created.
+          0 = i386
+          1 = m68k
+target   target for which this unit is created, this depends also on the
+	 cpu! 
+	 For i386:
+	  0 : Go32v1
+	  1 : Go32V2
+	  2 : Linux-i386
+	  3 : OS/2
+          4 : Win32
+         For m68k:
+	  0 : Amiga
+	  1 : Mac68k
+	  2 : Atari
+	  3 : Linux-m68k
+flags	 the unit flags, contains a combination of the uf_ constants which
+	 are definied in ppu.pas
+size	 size of this unit without this header
+checksum checksum of the interface parts of this unit, which determine if
+         a unit is changed or not, so other units can see if they need to
+	 be recompiled
+
+
+After this header follow the sections. All sections work the same! 
+A section contains of entries and is ended with also an entry, but
+containing the specific ibend constant (see ppu.pas for a list).
+
+Each entry starts with an entryheader.
+  tppuentry=packed record                                                       
+    id   : byte;                                                                
+    nr   : byte;                                                                
+    size : longint;                                                             
+  end;      
+
+id	this is 1 or 2 and can be check if it the entry is correctly
+	found. 1 means its a main entry, which says that it is part of the
+	basic layout as explained before. 2 toggles that it it a sub entry
+	of a record or object
+nr	contains the ib constant number which determines what kind of
+	entry it is
+size	size of this entry without the header, can be used to skip entries
+	very easily.
+
+
+To read an entry you can simply call ppufile.readentry:byte it returns the
+tppuentry.nr field, which holds the type of the entry. A common way how
+this works is (example is for the symbols):
+
+  repeat
+    b:=ppufile.readentry;
+    case b of
+   ib<etc> : begin
+             end;
+ ibendsyms : break;
+    end;
+  until false;
+
+Then you can parse each entry type yourself. ppufile.readentry will take
+care of skipping unread byte in the entry an read the next entry
+correctly! A special function is skipuntilentry(untilb:byte):boolean;
+which will read the ppufile until it finds entry untilb in the main
+entrys.
+
+Parsing an entry can be done with ppufile.get<type> functions. The
+available functions are:
+    procedure ppufile.getdata(var b;len:longint);
+    function  getbyte:byte;                                                     
+    function  getword:word;                                                     
+    function  getlongint:longint;                                               
+    function  getreal:ppureal;                                                  
+    function  getstring:string;      
+
+To check if you're at the end of an entry you can use the following
+function:
+    function  EndOfEntry:boolean;                                               
+
+Note 1: ppureal is the bestreal that is possible for the cpu where the
+unit is created for. Currently its extended for i386 and single for m68k.
+Note 2: the ibobjectdef and ibrecorddef have stored a definition and
+symbol section for themselves. So you'll need a recursive call. See
+ppudump.pas for a good implementation.
+
+For a complete list of entrys and what their fields contain can be found
+in ppudump.pp
+
+
+
+Creating ppufiles.
+
+To create a new ppufile works almost the same as writing. First you need
+to init the object and call create:
+  ppufile:=new(pppufile,'output.ppu');
+  ppufile.create;
+
+After that you can simply write all needed entries. You'll have to take
+care that you write at least the basic entries for the sections:
+
+  ibendinterface
+  ibenddefs
+  ibendsyms
+  ibendbrowser (only when you've set uf_has_browser!)
+  ibendimplementation
+  ibend
+
+Writing an entry is a little different than reading it. You need to first
+put everything in the entry with ppufile.put<type>:
+    procedure putdata(var b;len:longint);                                       
+    procedure putbyte(b:byte);                                                  
+    procedure putword(w:word);                                                  
+    procedure putlongint(l:longint);                                            
+    procedure putreal(d:ppureal);                                               
+    procedure putstring(s:string);      
+After putting all the things in the entry you need to call
+ppufile.writeentry(ibnr:byte) where ibnr is the entry number you're 
+writing.
+
+At the end of the file you need to call ppufile.writeheader to write the
+new header to the file. This takes automaticly care of the new size of the
+ppufile. When that's also done you can call ppufile.close and dispose the
+object.
+
+Extra functions/variables available for writing are:
+    ppufile.NewHeader;                                           
+    ppufile.NewEntry;   
+this will give you a clean header or entry. Normally called automaticly
+in ppufile.writeentry(), so you can't forget it.
+    ppufile.flush;                                                            
+to flush the current buffers to the disk
+    ppufile.do_crc:boolean;
+set to false if you don't want that the crc is updated, this is necessary
+if you write for example the browser data.
+
+   
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % Appendix B
 % Appendix B
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2701,15 +2784,10 @@ Although many of the restrictions imposed by the MS-DOS system are removed
 by use of an extender, or use of another operating system, there still are
 by use of an extender, or use of another operating system, there still are
 some limitations to the compiler:
 some limitations to the compiler:
 \begin{enumerate}
 \begin{enumerate}
-\item String constants are limited to 128 characters. All other characters
-are simply dropped from the definition.
-\item The length of generated unit files is limited to 65K for the
-real-mode compiler, and to 1Mb for the 32-bit compiler. This limit can be
-changed by changing the \var{bytearray1} type in \file{cobjects.pas}
 \item Procedure or Function definitions can be nested to a level of 32.
 \item Procedure or Function definitions can be nested to a level of 32.
 \item Maximally 255 units can be used in a program when using the real-mode
 \item Maximally 255 units can be used in a program when using the real-mode
 compiler. When using the 32-bit compiler, the limit is set to 1024. You can
 compiler. When using the 32-bit compiler, the limit is set to 1024. You can
-change this by redefining the \var{maxunits} constant in the
+change this by redefining the \var{maxunits} constant in the 
 \file{files.pas} compiler source file.
 \file{files.pas} compiler source file.
 \end{enumerate}
 \end{enumerate}