Vintage PC pages
Home -> Vintage PCs -> PGC Notes

Professional Graphics Controller: Notes


This document describes the behaviour of IBM's Professional Graphics Controller (part number 6181765, I believe).

The PGC was, at the time of its release, the most advanced graphics card for the IBM XT, costing several thousand dollars. It was designed for 2D and 3D vector graphic operations, such as CAD. It supports 640x480x256 graphics; the 256 colours are chosen from a palette of 4096.

It has two modes of operation - CGA and native. The CGA emulation can optionally be disabled, so that the PGC can be fitted in a system with a real CGA (or EGA, or VGA).

The PGC used a specialised monitor. I have tested one with a VGA monitor (a Samsung SyncMaster 500s Plus) which appears to work correctly in all modes. To connect it, I used a standard 9-pin to 15-pin converter, probably designed to connect an Archimedes 300 series computer to a VGA.

There is a paper in the IBM Systems Journal which gives an overview of how the PGC works, and lists most of the commands it accepts. However, it doesn't list the expected parameters; I had to find these out for myself.

Since I originally wrote this page, the PGC section of the IBM Options and Adapters manual has been scanned: you can find it near the bottom of this page.

Hardware requirements

The PGC is rather more than just a graphics card - it's a full computer, with its own CPU, 68k of ROM and 320k of RAM. It's composed of two full-length ISA cards plus a third, smaller, card that sits between them. The whole affair is firmly bolted together.

This isn't a particularly good picture, but it's the best one I've got showing the PGC split into three cards:

[Picture of PGC]

Because the PGC fits in two adjacent slots, it won't work in an original (5150) PC - the expansion slots are too far apart. To use it with a 5150, you need a 5161 expansion unit, which has 8 slots at the correct spacing.

The PGC uses the following hardware resources:

The PGC is rather picky about the ISA bus it finds itself in. I've successfully used one on an XT and an XT/286, but it didn't work when put in a 486; memory reads and writes were unreliable, and the display went blank at the slightest provocation. It may be that the 486 was running its ISA bus too fast for the PGC to keep up.

The hardware

The rear board of the PGC contains a dedicated 8088 processor, 64K of ROM, a 4-bit DAC, various support chips, and 2k of RAM shared with the PC. Half of this contains buffers for communication; the other half has the 8088 stack and various variables. The middle (half-size) board is the CGA emulator, containing the CGA character ROM (soldered rather than socketed), and support circuitry. The front board contains the PGC's 320k of video RAM (300k for the framebuffer, 20k for other purposes) and a clock crystal. Both the full-size boards have a connection to the ISA bus; all three boards are connected using an internal bus.

A jumper on the back board (J1) controls whether the CGA emulator is enabled or disabled.

The video out connector is DE-9, with the following pinout:

Pin 1: Red Video
Pin 2: Green Video
Pin 3: Blue Video
Pin 4: Composite Sync
Pin 5: According to various sources, either 'No connection' or switch 
      between 400-line and 480-line modes.
Pin 6: Red Return
Pin 7: Green Return
Pin 8: Blue Return
Pin 9: Ground

One other point about the physical card - it can put out a lot of heat, so be sure the PC has good internal ventilation.


The PGC came with three diskettes:

The only other software I know of which supports the PGC is CompuShow; but early versions of AutoCAD are also said to be able to use it.

Memory Map

The PGC appears to its host as 2k of memory at 0C6000h. This is laid out as follows:

C6000-C60FF: Host-to-PGC ring buffer.
C6100-C61FF: PGC-to-host results ring buffer.
C6200-C62FF: PGC-to-host errors ring buffer.
C6300-C63FF: Other data, including:

C6300:       Write pointer in buffer at C6000.
C6301:       Read pointer in buffer at C6000.
C6302:       Write pointer in buffer at C6100.
C6303:       Read pointer in buffer at C6100.
C6304:       Write pointer in buffer at C6200.
C6305:       Read pointer in buffer at C6200.
C6306:       Cold start flag.
C6307:       Warm start flag.
C6308:       Set to nonzero to report errors.
C6309:       Set at the same time as the warm start flag; not changed 
C630A:       Not used by the PGC. The diagnostic utility loads itself into
             PGC RAM and uses this byte to store its result.
C630B:       Nonzero if CGA mode can be selected.
C630C:       Display request. Set this to 1 (CGA mode) or 0 (normal mode) and
	     the PGC will change to that mode and set the "Display acknowledge"
             flag to the requested value. This is an alternative to sending
	     DI commands to the PGC.
C630D:       Display acknowledge.
C630E:       CGA framebuffer request. 
C630F:       CGA framebuffer acknowledge.
C6310-C6321: Register values - these get set if the PGC processor jumps to
	     a breakpoint at 0FFF:0008h. Registers are AX,BX,CX,DX,BP,SI,DI,
             DS and ES.
C6322:       CGA vertical total
C6323:       CGA vertical displayed
C6324:       CGA vertical adjust
C6325:       CGA vertical sync
C6326:       Unused
C6327-C6328: CGA cursor size
C6329-C632A: CGA cursor address
C632B-C632C: CGA screen start address
C63D8:       Last value written to port 03D8h.
C63D9:       Last value written to port 03D9h.
C63DB:       "Presence test byte"
C63E0-C63F3  Last values written to the emulated CGA CRTC.
C63F8-C63F9  PGC firmware version.
C63FB:       0A5h if PGC processor has passed tests.
C63FC:       0FFh if PGC ROM (low 32k) has failed; else 5Ah.
C63FD:       0FFh if PGC ROM (high 32k) has failed; else 55h.
C63FE:       0FFh if PGC RAM has failed; else AAh.
C63FF:       To reboot the PGC, write 50h into this byte, wait a bit 
             (IBM's diagnostic program waits 2 system clock ticks) 
	     and then write 0A0h. While at the 50h stage, the PGC's processor
	     is in a tight loop; you can access the remainder of the 
	     transfer RAM without upsetting it (or it upsetting you).

C6400-C67FF  Reserved. The top part of this contains the PGC's stack; the rest
	    contains PGC state. Whether this area appears in memory or not
            appears to be up to the discretion of the host PC; it showed up
            on an XT, but not an XT/286.


[ZIP] PGCBMP.ZIP contains a couple of example utilities for people experimenting with the PGC - a BMP file viewer, and a program to send typed commands to the PGC and print the results.

Emulated CGA mode

When the card is emulating a CGA, it looks and acts pretty much like a real CGA, with these exceptions:

  1. The text mode has 400 pixel rows, not 200.
  2. The font used for text mode is the EGA 14-pixel font, not a stretched version of the CGA 8-pixel one.
  3. Nonstandard modes (such as the undocumented 160x100 mode) don't work.
  4. On a real CGA, if bit 2 of port 03D8h and bit 5 of port 03D9h are both set, the palette used in graphics modes is red/cyan/white. On a PGC, it's magenta/cyan/white. You still get red/cyan/white if bit 5 of port 03D9h is not set. This is a firmware issue rather than hardware.

Native mode

In native mode, the host PC sends commands to the PGC, which then executes them asynchronously. Commands are sent by writing them into the ring buffer at 0C6000h, and incrementing the write pointer at 0C6300h. As the PGC takes bytes from this buffer, it will increment the read pointer at 0C6301h.

By default, PGC coordinates are based on an origin at the centre of the 640x480 screen.

Hex and ASCII commands

Commands can be sent either as human-readable ASCII text, or a compressed Hex representation. To find the Hex version of an ASCII command, write it to a command list (CLBEG 0 command CLEND) and then read it back (CLRD 0); you will get the command in Hex form.

The following table lists all the PGC commands I know of. Short forms are given in brackets after the long forms. Data types are:

0-255. In Hex mode, 1 byte.
-32768 to +32767. In Hex mode, 2 bytes (least significant first).
-32768.9999 to +32767.9999. In Hex mode, 4 bytes - the first two hold the integer part, and the second two hold the fractional part (in 65536ths).

Angles are measured anticlockwise from the X axis, in degrees.

Command (ASCII mode) Command byte (HEX mode) Parameters Behaviour
ARC (AR)3C radius,angle1,angle2 (1 coord, 2 words) Draws an arc, centred on the current drawing position, starting at the first angle from and continuing to the second. If radius is negative angles are measured from the negative X-axis.
AREA (A)C0 none Flood fill, starting at the current drawing position, in the current colour.
AREABC (AB)C1 colour (1 byte) As AREA, but only stops when it reaches a pixel of the specified colour.
AREAPT (AP)E7 word,word... (16 words) Set the fill pattern (defaults to solid colour). The first word gives the bottom row of a 16x16 bitmap, the second gives the next, and so on. Within each word, bit 0 is the leftmost pixel and bit 15 the rightmost.
BUFFER (BU)4F p, q (2 bytes) Not mentioned in the IBM article. The two bytes are each 0-3, and affect the internal display flags.
CAD2 (or 43 41)none Switch to ASCII mode. All commands are human-readable.
CIRCLE (CI)38 radius (1 coord) Draws a circle centred on the current drawing position.
CLBEG (CB)70id (1 byte) Store a command list for later execution. Commands up to the next CLEND will be stored in the named list rather than executed.
CLDEL (CD)74 id (1 byte) Delete the specified command list.
CLEARS (CLS) 0Fcolour (1 byte) Clear the screen to the specified colour.
CLEND (CE)71none End of command list.
CLIPH (CH)AAmode (1 byte) Set 'Hither' clip mode. Mode is 0 (disable) or 1 (enable).
CLIPY (CY)ABmode (1 byte) Set 'Yon' clip mode. Mode is 0 (disable) or 1 (enable).
CLOOP (CL)73id, repeats (1 byte, 1 word) Execute the specified command list a number of times.
CLRD (CRD)75id (1 byte) Read back the specified command list. Returns the list as hex bytes, preceded by a word giving the length of the list.
CLRUN (CR)72id (1 byte) Execute the specified command list.
COLOR (C)06colour (1 byte) Select the current drawing colour, 0 to 255.
CONVRT (CV)AFnone Maps the current 3D drawing position to 2D, and sets the current 2D drawing position to the result.
CXD1 (or 43 58)none Switch to Hex mode. All commands are one byte long. Note that the ASCII CA/CX still work in this mode, so you can select a mode without knowing what the current one is.
DISPLA (DI)D0mode (1 byte) Select display mode - 0 for 640x480, 1 for emulated CGA.
DISTAN (DS)B1 distance (1 coord) Set the 3D viewing distance. This is the distance from the eye to the viewing reference point.
DISTH (DH)A8 distance (1 coord) Set the distance from the viewing reference point to the "hither" clip plane. Any points further away from the viewer than the hither clip plane aren't displayed.
DISTY (DY)A9 distance (1 coord) Set the "yon" clip distance. Any points closer to the viewer than the yon clip plane aren't displayed.
DRAW (D)28 x,y (2 coords) Draw from the current position to the specified position.
DRAWR (DR)29 dx,dy (2 coords) Draw a line relative to the current position.
DRAW3 (D3)2A x,y,z (3 coords) Draw from the current 3D position to the specified 3D position.
DRAWR3 (DR3)2B dx,dy,dz (3 coords) Draw a line relative to the current 3D position.
ELIPSE (EL)39Width,Height (2 coords) Draws an ellipse centred on the current drawing position.
FILMSK (FM)EFmask (1 byte) Set the fill mask. This is similar to the draw mask set by MASK, but is only used in area fills.
FLAGRD (FRD)51Flag no. (1 byte) Read a PGC flag (flag numbers are 1-26). See below for what the values mean.
FLOOD (F)7colour (1 byte) As CLEARS, but only in the area covered by the viewport.
IMAGER (IR)D8 row,col1,col2 (3 words) Read some or all of a line of pixels. Returns an IMAGEW command that can be used to redraw this pixel line.
IMAGEW (IW)D9 row,col1,col2, data (3 words, then data as bytes) Plot some or all of a row of pixels between the specified columns. The row is 0-479, with 0 at the bottom and 479 at the top; the columns are 0-639. In Hex mode, the bytes are run-length compressed.
The sequence [nn][xx] (where nn < 80h) means '[nn+1] repetitions of [xx]'.
The sequence [nn][xx][xx][xx]... (where nn >= 80h) means 'sequence of uncompressed bytes, [nn-7Fh] bytes long'.
LINFUN (LF)EB mode (1 byte) Select drawing mode. Mode 0 (the default) sets pixels to the currently selected colour. Mode 1 inverts pixels.
LINPAT (LP)EA pattern (1 word) Select line pattern (for dotted or dashed lines). The parameter word is treated as a bitmap pattern.
LUT (L)EE ink, r, g, b (4 bytes) Set the palette for colour c. (0 to 255). R/G/B values are 0-15.
LUTINT (LI)EC palette (1 byte) Select a standard palette (0-5 or 255). See below for the list of palettes.
LUTRD (LRD)50 ink (1 byte) Read the palette values for colour c (0 to 255). Returns the Red/Green/Blue values in the output buffer.
LUTSAV (LS)ED none Save current palette. It can be restored with LUTINT 255.
MASK (MK)E8 mask (1 byte) Set drawing mask. All pixels written will be affect only the bits set in this mask. See pages 3 and 4 of the IBM paper for why you would do this.
MATXRD (MRD)52 id (1 byte) Read 3D model matrix. id can be 1 (Model matrix) or 2 (Viewing matrix). Returns 16 bytes, giving a 4x4 matrix.
MDIDEN (MDI)90none Reset 3D model matrix to the identity.
MDMATX (MDM)9716 coords. Set 3D model matrix: a 4x4 array of coordinates.
MDORG (MDO)91x,y,z (3 coords). Set origin of 3D model matrix.
MDROTX (MDX)93angle (1 word) Rotate 3D model about the X axis.
MDROTY (MDY)94angle (1 word) Rotate 3D model about the Y axis.
MDROTZ (MDZ)95angle (1 word) Rotate 3D model about the Z axis.
MDSCAL (MDS)92xscale, yscale, zscale (3 coords) Scale 3D model.
MDTRAN (MDT)92dx, dy, dz (3 coords) Translate 3D model.
MOVE (M)10 x,y (2 coords) Set the current drawing position.
MOVER (MR)11 dx,dy (2 coords) Add the supplied values to the current drawing position.
MOVE3 (M3)12 x,y,z (3 coords) Set the current 3D drawing position.
MOVER3 (MR3)13 dx,dy,dz (3 coords) Add the supplied values to the current 3D drawing position.
POINT (PT)8none Put a dot, of the current colour, at the current drawing position.
POINT3 (PT3)9none Put a dot, of the current colour, at the current 3D drawing position.
POLY (P)30 count, x1,y1,x2,y2,... (1 byte, followed by 2*count coords) The first parameter is the number of points. The second and subsequent parameters are their coordinates.
POLYR (PR)31 count, x1,y1,x2,y2,... (1 byte, followed by 2*count coords) As POLY, but coordinates are relative to the current drawing position.
POLY3 (P3)32 count, x1,y1,z1,... (1 byte, followed by 3*count coords) As POLY, but each point is drawn in 3D space and has x,y,z coordinates.
POLYR3 (PR3)33 count, x1,y1,z1,... (1 byte, followed by 3*count coords) As POLY3, but coordinates are relevant to the current 3D drawing position.
PRMFIL (PF)E9fill (1 byte) Set polygon fill mode (0-2). If 0, polygons are drawn as outlines; if 1, they are drawn filled with the current fill pattern. If it is 2, performance is improved by not checking for degenerate polygons.
PROJCT (PRO)B0angle (1 word) Set the type of projection used in 3D to 2D transformations. 0 selects orthographic projection; 1 to 179 select perspective projection with the specified viewing angle.
RECT (R)34 x,y (2 coords) Draw a rectangle, one corner at the current drawing position and the opposite corner at the specified coordinates.
RECTR (RR)35 dx,dy (2 coords) As RECT, but coordinates are relative to the current drawing position.
RESETF (RF)4 none Reset the PGC to default settings.
SCAN5F search (1 byte) This command (not mentioned in the article) returns 1 if the specified byte is found (in the framebuffer?), 0 if it is not.
SECTOR (S)3D radius,angle1,angle2 (1 coord, 2 words) As ARC, but joins the centre point to the ends.
TANGLE (TA)82 angle (1 word) Set the angle of the baseline used to draw text. This does not change the angle at which the letters themselves are drawn.
TDEFIN (TD)84 char_id, width, height, bits... (bytes) Define a custom character shape.
TEXT (T)80 "txt" or 'txt' Draw the specified text, with its bottom left corner at the current position.
TEXTP (TP)83 "txt" or 'txt' Draw the specified text using the characters defined by TDEFIN.
TJUST (TJ)85 (2 bytes) Set text positioning relative to the current point. The first byte specifies horizontal alignment (1=left 2=centre 3=right) and the second specifies vertical alignment (1=bottom 2=centre 3=top).
TSIZE (TS)81 size (1 coord) Set the horizontal spacing of characters.
VWIDEN (VWI)A0 none Reset 3D view matrix to the identity.
VWMATX (VWM)A716 coords. Set 3D view matrix.
VWPORT (VWP)B2 x1, x2, y1, y2 (words) Define the viewport area.
VWRPT (VWR)A1x,y,z (3 coords). Set 3D view reference point: the point that the viewer is looking at.
VWROTX (VWX)A3angle (1 word) Rotate 3D view (X).
VWROTY (VWY)A4angle (1 word) Rotate 3D view (Y).
VWROTZ (VWZ)A5angle (1 word) Rotate 3D view (Z).
WAIT (W)5delay (1 word) Wait for the specified number of frames.
WINDOW (WI)B34 words x1, x2, y1, y2 (words) Define the coordinates of the viewing window.
5B 71 8Csegment, offset, checksum (3 words) This undocumented command is only available in Hex mode. If segment + offset + checksum = 0, the PGC's processor will do a far jump to the specified address - presumably in the transfer buffer, which from the PGC's point of view is from 28000h to 283FFh. To return control to the normal firmware, the IBM diagnostic program jumps to FFFF:0008h; INT 3 may also work.


The standard palettes are:

Default 256-colour palette. Low 4 bits of ink give intensity, high 4 bits give colour (0=Grey, 1=Red, 2=Red/Magenta, 3=Magenta, 4=Violet, 5=Blue, 6=Blue/Cyan, 7=Cyan, 8=Cyan/Green, 9=Green, 10=Green/Yellow, 11=Yellow, 12=Orange, 13=Red, 14=Green, 15=Blue)
16-colour palette (for making the PGC behave as two 16-colour planes). If high 4 bits of ink are 0, low 4 bits give colour; otherwise, high 4 bits give colour. Colours are 0=Cyan, 1=Black, 2=Dark Brown, 3=Light Brown, 4=Red/Brown, 5=Red, 6=Orange, 7=Yellow, 8=Yellow/Green, 9=Green, 10=Dark Green, 11=Dark Cyan, 12=Blue, 13=Salmon, 14=Grey, 15=White.
2-3-3 truecolour palette. Bits 0-2 of ink give blue; bits 3-5 give green; bits 6,7 give red.
3-2-3 truecolour palette. Bits 0-2 of ink give blue; bits 3-4 give green; bits 5-7 give red.
3-3-2 truecolour palette. Bits 0,1 of ink give blue; bits 2-4 give green; bits 5-7 give red.
6x6x6 colour cube.
Restore palette previously saved with the LUTSAV command.


The following flags can be read by the FLAGRD command:

  1. The fill pattern (set by AREAPT). Returns 16 words.
  2. The "Hither" clip flag (set by CLIPH). Returns 1 byte.
  3. The "Yon" clip flag (set by CLIPY). Returns 1 byte.
  4. The current pen colour (set by COLOR). Returns 1 byte.
  5. The current display mode (set by DISPLAY). Returns 1 byte.
  6. The viewing distance (set by DISTAN). Returns 1 coord.
  7. The "Hither" clip value (set by DISTH). Returns 1 coord.
  8. The "Yon" clip value (set by DISTY). Returns 1 coord.
  9. The fill mask (set by FILMSK). Returns 1 byte.
  10. The value set by LINFUN. Returns 1 byte.
  11. The value set by LINPAT. Returns 1 word.
  12. The plane mask (set by MASK). Returns 1 byte.
  13. The model matrix origin (set by MDORG). Returns 3 coords.
  14. Return current 2D drawing position. Returns 2 coords.
  15. Return current 3D drawing position. Returns 3 coords.
  16. Return polygon fill mode (set by PRMFIL). Returns 1 byte.
  17. The current projection angle (set by PROJCT). Returns 1 byte.
  18. The text angle (set by TANGLE). Returns 1 word.
  19. The text justification settings (set by TJUST). Returns 2 bytes.
  20. The text size (set by TSIZE). Returns 1 coord.
  21. Viewport parameters. Returns 4 words.
  22. Viewport reference point (set by VWRPT). Returns 3 coords.
  23. Window parameters (set by WINDOW). Returns 4 coords.
  24. Transformed 3D current point. Returns 3 coords.
  25. Free memory. Returns 1 word.

PGC Clones

John Elliott 11 August 2010