p-Code
P-Code ist der Befehlssatz einer Pseudo-Maschine (oder P-Maschine), also einer virtuellen CPU, die P-Code als Maschinensprache ausführt. Der P-Code war ein Computer- bzw. CPU-unabhängiger Code und war Teil der Entwicklungsumgebung UCSD Pascal. Die Umsetzung in die Maschinensprache der CPU erfolgt durch den Interpreter der P-Maschine. Man kann den P-Code und das Konzept der virtuellen Maschine als geistigen Vorläufer der heutigen Java Virtual Machine betrachten.
Plattformen
    
Durch die Unabhängigkeit von bestimmten Rechnerarchitekturen konnte das P-System auf verschiedenste Plattformen portiert werden:
- 6502 (Apple II, CBM-8000-Serie)
- DEC LSI-11
- DEC PDP-11
- Zilog Z80 (CP/M-Systeme)
- Motorola 68000
- Intel 8086 (IBM PC)
- Texas Instruments TMS9900 (TI99)
Funktionsumfang der P-Maschine
    
- Adressierung von Variablen, Strings, Byte-Arrays
- Logische Verknüpfungen und Vergleiche
- Arithmetik mit Konstanten und Variablen der Typen Integer, Real, Set, Array, String
- Verzweigungen, Sprünge
- Prozedur- und Funktionsaufrufe
- Overlay-Prozeduren
- Systemfunktionen und -prozeduren
Register des Emulators
    
Die P-Maschine ist eine 16-Bit-Maschine; der Adressraum ist damit auf 64 KiB beschränkt. Sie ist aber in der Lage, mehrere Adressräume zu verwalten, beispielsweise 128 KiB in Version IV. Zur Emulation des P-Codes dienen folgende Register (Pointer):
| SP: | Stack-Pointer | Zeiger auf das oberste Wort im Stack. Dient der Parameterübergabe und als Operandenquelle für den Interpreter. | 
| IPC: | Interpreter Program Counter | Adresse der nächsten P-Code-Instruktion im Codesegment der aktuellen Prozedur | 
| SEG: | Segment Pointer | Zeiger auf das Prozedurverzeichnis des aktuellen Segments | 
| JTAB: | Jump Table Pointer | Zeiger auf die Sprungtabelle des aktuellen Segments | 
| KP: | Program Stack Pointer | Zeiger auf das Ende des Programm-Stacks | 
| MP: | Markstack Pointer | Zeiger auf den Aktivierungs-Record der aktuellen Prozedur zum Zugriff auf die lokalen Variablen | 
| NP: | New Pointer | Zeiger auf das Ende des dynamischen Heaps | 
| BASE: | Base Procedure | Zeiger auf den Aktivierungs-Record der Basis-Prozedur zum Zugriff auf die globalen Variablen | 
P-Code (Befehlssatz der P-Maschine)
    
Der Befehlscode der Pseudo-Maschine ist ein oder zwei Byte lang und wird von bis zu vier Operanden gefolgt. Es gibt folgende Befehlsklassen:
- 1-Wort-Transportbefehle
- Mehr-Wort-Transportbefehle
- Byte-Array-Behandlung
- String-Behandlung
- Record und Array-Behandlung
- Dynamische Speicherallokation
- Arithmetik-Befehle
- Sprungbefehle
- Prozedur- und Funktionsaufrufe
- Unterstützungs-Routinen
Verbindung zwischen P-Maschine und Betriebssystem
    
Das UCSD-Pascal-Betriebssystem und die virtuelle P-Maschine tauschen Informationen über die Systemvariable SYSCOM aus. Diese befindet sich im äußeren Block des Betriebssystems. Dieser Speicherbereich ist der P-Maschine „bekannt“.
P-Code-Beispiel
    
Auszug aus einem Disassembler-Listing:
Attribute Table
-------------------------
Procedure No.:   37
Lex Level:        0
EnterIC:         54
Exit IC:          7
Parameter Size:   0 words
Data Size:        2 words
-------------------------
Block No:|58
Block Offset:|132
Offset P-Code             Hex-Code
     0 CBP     36         C224
     2 LOD      1     1   B60101
     5 SRO      1         AB01
     7 SLDO1              E4
     8 INC     31         A21F
    10 SRO      2         AB02
    12 SLDC3              03
    13 CSP   UNITCLEA     9E26
    15 SLDO2              E9
    16 INC 1              A201
    18 SLDC8              08
    19 SLDC0              00
    20 LDP                BA
    21 SLDC0              00
    22 NEQI               CB
    23 FJP     36         A10B
    25 SLDC3              03
    26 SLDO2              E9
    27 INC      1         A201
    29 SLDC8              08
    30 SLDC0              00
    31 LDP                BA
    32 CBP     52         C234
    34 UJP     45         B909
    36 SLDC6              06
    37 SLDD02             E9
    38 INC      4         A204
    40 SLDC8              08
    41 SLDC8              08
    42 LDP                BA
    43 CBP     52         C234
    45 RBP      0         C100
In UCSD-Pascal sieht die Prozedur so aus:
PROCEDURE CLEARSCREEN;                (*Bemerkung*)
  BEGIN HOMECURSOR;                   (*Offset  0*)
    WITH SYSCOM^,CRTCTRL DO           (*Offset 10*)
      BEGIN
        UNITCLEAR(3);                 (*Offset 13*)
        IF ERASEEOS <> CHR(0) THEN    (*Offset 23*)
          PUTPREFIXED(3,ERASEEOS)     (*Offset 32*)
        ELSE                          (*Offset 34*)
          PUTPREFIXED(6,CLEARSCREEN)  (*Offset 43*)
      END
END (*CLEARSCREEN*) ;                 (*Offset 45*)