Skip to content

Using Out Port command in QBASIC and Turbo Pascal

RetroNick's Youtube Channel edited this page Aug 20, 2026 · 2 revisions

Using Out\Port command to modify palettes in QBASIC and Turbo Pascal

Raster Master v8.3 and newer support generating Out (for QBASIC) and (Port for Turbo Pascal). This was added to allow Palettes to be created in any of the standard DOS PC modes. The built in palette command is supported in EGA/VGA modes but does not work in the way you would expect in the other PC modes. This is not the fault of the compiler/language. The built in graphics library for these languages assumes that you are working on the expected hardware. So if you set to an EGA mode the graphics library assumes you are using an EGA card. 

With the introduction of the VGA card every mode was super charged with new palette abilities. As long as you are using a VGA card or an emulated environment like dosbox/dosbox-x/jsdos you can use the VGA DAC feature to change the default colors for these modes to anything you like.  As the long as the values fall into VGA's 6bit RGB registers you are perfectly fine to choose any colors you like (6 bit means values from 0 to 63 for RGB values).

To modify the color palette directly using hardware ports in QBasic, you send commands to the VGA DAC (Digital-to-Analog Converter) ports via the OUT statement. This method is faster than the built-in PALETTE statement and works by targeting port &H3C8 for the color index, followed by three sequential OUT calls to port &H3C9 for the red, green, and blue intensities (ranging from 0 to 63). [1, 2, 3]

' Example: Change color index 1 to bright red OUT &H3C8, 1 ' Select color attribute 1 OUT &H3C9, 63 ' Red intensity (max 63) OUT &H3C9, 0 ' Green intensity (0) OUT &H3C9, 0 ' Blue intensity (0)

How to Modify the Palette with OUT

  • Select the index: Send the target color number (0 to 255) to port &H3C8 using OUT &H3C8, colorIndex%.
  • Set Red intensity: Send a value from 0 to 63 to port &H3C9 using OUT &H3C9, red%.
  • Set Green intensity: Send the green value (0 to 63) to port &H3C9 using OUT &H3C9, green%.
  • Set Blue intensity: Send the blue value (0 to 63) to port &H3C9 using OUT &H3C9, blue%. [2, 3]

Important Details

  • Value Range: Standard VGA DAC levels accept values from 0 up to 63 (not 255). If you have standard 0–255 RGB values, divide them by 4 before sending them via OUT. [4, 5, 6, 7]
  • Automatic Increment: After writing the third intensity value (blue), the VGA card automatically increments the internal color index pointer, allowing you to stream multiple sequential colors by repeating triplets of OUT &H3C9 commands. [3]
  • Compatibility: Direct port manipulation using OUT requires real hardware or an environment like DOSBox that permits direct I/O port access. Modern emulators or updated build environments like QB64 emulate these registers or recommend using _PALETTECOLOR instead. [3, 8, 9]

If you attempt to modify the palette for indices 0 through 15 using the standard OUT &H3C8 method in a 16-color mode (like SCREEN 12), only the first 8 colors will change. The remaining 8 colors will seem completely locked. [1, 2]

Why This Happens

In 16-color VGA/EGA modes, the 16 logical color attributes do not map linearly to slots 0–15 in the 256-color DAC hardware table. Because of backward compatibility with old EGA hardware, the internal Attribute Controller routes them to separated slots: [3, 4]

  • Colors 0 to 7 map directly to DAC registers 0 to 7.
  • Colors 8 to 15 map to DAC registers 56 to 63 (&H38 to &H3F).

When you call OUT &H3C8, 8, you are editing DAC slot 8, which the screen isn't even looking at for color 8. The hardware is actually reading slot 56!


Solution 1: Map directly to the true DAC slots

The easiest approach is to adjust your index number right before sending it to port &H3C8. If the index is 8 or greater, offset it to hit the 56–63 range. [5]

SCREEN 12 ' Change all 16 colors to shades of pure red 
FOR i% = 0 TO 15 ' Determine the real VGA DAC slot 
  IF i% < 8 THEN 
    HardwareSlot% = i% 
  ELSE 
    HardwareSlot% = i% + 48 ' Shifts 8..15 to 56..63 
  END IF
' Calculate a gradient value from 0 to 63 
  Intensity% = i% * 4   
  OUT &H3C8, HardwareSlot% 
  OUT &H3C9, Intensity%  ' Red 
  OUT &H3C9, 0           ' Green 
  OUT &H3C9, 0           ' Blue
NEXT i%

Solution 2: Remap the Attribute Controller

Alternatively, you can force the Attribute Controller to map color attributes 0–15 linearly to DAC slots 0–15. This requires talking to the Attribute Controller index/data register at port &H3C0. [3, 4]

SCREEN 12 ' Reset and set Attribute Controller registers 0-15 to point to DAC slots 0-15 FOR i% = 0 TO 15 Dummy% = INP(&H3DA) ' Reset the Attribute Controller flip-flop to Index mode OUT &H3C0, i% ' Select the Attribute register for color i% OUT &H3C0, i% ' Write the new value (map it to DAC slot i%) NEXT i% ' Re-enable screen output on the Attribute Controller Dummy% = INP(&H3DA) OUT &H3C0, &H20 ' Now you can write to DAC slots 0-15 sequentially! OUT &H3C8, 0 FOR i% = 0 TO 15 OUT &H3C9, i% * 4 ' Red OUT &H3C9, 0 ' Green OUT &H3C9, i% * 4 ' Blue (creates purple shades) NEXT i%

Whether you need to make changes depends entirely on the color depth of the screen mode you switch to. Here is how the other QBasic SCREEN modes behave when using direct OUT commands:

1. SCREEN 13 (256-Color Mode) — No Changes Needed

This is the easiest mode to work with. There are no hardware mapping tricks, offsets, or remappings required.

  • How it works: Color attributes 0 through 255 map exactly and linearly to hardware DAC slots 0 through 255.
  • Usage: You can safely use the basic OUT &H3C8, colorIndex followed by the three OUT &H3C9 commands for any color.

2. SCREEN 7, 8, and 9 (16-Color EGA/VGA Modes) — Same 16-Color Rules Apply

These modes share the exact same heritage as SCREEN 12.

  • How it works: They use the same EGA-compatible Attribute Controller mapping.
  • Usage: You must use either the offset math (shifting indices 8–15 to slots 56–63) or the register remapping code detailed previously.

3. SCREEN 1 and 2 (4-Color and 2-Color CGA Modes) — Special Palette Handling

These modes emulate old CGA hardware. While you can use OUT statements to change their colors on a VGA card, the default hardware mappings are highly unusual due to how the VGA card emulates CGA palettes.

  • SCREEN 1 (4 colors): The 4 attributes (0, 1, 2, 3) do not map to DAC slots 0, 1, 2, 3. Instead, they typically map to scattered DAC slots (often slots 0, 2, 4, 6 or depending on the active CGA palette color selection, slots like 0, 11, 13, 15).
  • SCREEN 2 (2 colors): The background (0) maps to DAC slot 0, but the foreground (1) maps to DAC slot 7 (or 15 depending on the configuration).
  • Fix: If you plan to use OUT in these modes, the easiest method is to apply the Attribute Controller Remapping routine (Solution 2 from the previous response) right after setting the screen mode. This forces attributes 0–3 to line up nicely with DAC slots 0–3.

Summary Checklist for QBasic Port Graphics


SCREEN Mode | Max Colors | Native Palette State | Code Modification Required? -- | -- | -- | -- SCREEN 13 | 256 | Linear (0 to 255) | None. Standard sequential OUT works perfectly. SCREEN 7, 8, 9, 12 | 16 | Split (0–7 and 56–63) | Yes. Must use index offset math or remap port &H3C0. SCREEN 1, 2 | 2 or 4 | Emulated CGA Slots | Yes. Best to remap port &H3C0 to make them linear. SCREEN 0 | Text | Dependent on text color width | Yes. Uses standard 16-color split rules for foreground/background attributes.

If you are thinking about moving your project to a different mode, let me know:

  • Which specific mode you are considering
  • If you need the exact DAC slot numbers for SCREEN 1 or SCREEN 2 without remapping registers

The exact same hardware mapping rules apply to Turbo Pascal because these limitations are built into the VGA graphics card, not the programming language. The only difference is how you talk to the hardware ports. Instead of QBasic's OUT command, Turbo Pascal uses the built-in Port array.

1. The 16-Color Mode Fix in Turbo Pascal (Using Offset Math)

If you are using Turbo Pascal's Graph unit (e.g., SetGraphMode with VGAHi for 640x480 16-colors), colors 8 to 15 still map to hardware DAC slots 56 to 63. Here is how you handle the index offset in Turbo Pascal:

program Set16ColorPalette;
 uses Graph; var gd, gm, i, hardwareSlot, intensity: Integer; 
begin 
  gd := VGA; gm := VGAHi; { 640x480, 16 colors } 
  InitGraph(gd, gm, '');
  for i := 0 to 15 do 
  begin { Direct hardware slot mapping logic } 
    if i < 8 then 
      hardwareSlot := i 
    else hardwareSlot := i + 48; { Shift 8..15 to 56..63 }
    intensity := i * 4; { Red intensity gradient 0 to 63  Turbo Pascal Port array acts exactly like QBasic OUT } 
    Port[$3C8] := hardwareSlot; { Select color slot } 
    Port[$3C9] := intensity;    { Red } 
    Port[$3C9] := 0;            { Green } 
    Port[$3C9] := 0;            { Blue }
 end;
 Readln; 
 CloseGraph; 
end.

2. The Attribute Controller Remapping Fix in Turbo Pascal

If you prefer to reprogram the Attribute Controller so that colors 0–15 map directly to DAC slots 0–15, you use Turbo Pascal's Port array to handle the flip-flop reset and index selection.

program RemapAndSetPalette; uses Graph; var gd, gm, i: Integer; dummy: Byte; begin gd := VGA; gm := VGAHi; InitGraph(gd, gm, '');

{ 1. Force the Attribute Controller to map attributes 0-15 to DAC slots 0-15 } for i := 0 to 15 do begin dummy := Port[$3DA]; { Reset the Attribute Controller flip-flop (Inp) } Port[$3C0] := i; { Select Attribute register for color i (Out) } Port[$3C0] := i; { Set it to point to DAC slot i (Out) } end;

{ 2. Re-enable the screen display on the Attribute Controller } dummy := Port[$3DA]; Port[$3C0] := $20; { Hex $20 is 32 in decimal }

{ 3. Now write to DAC slots 0-15 completely sequentially } Port[$3C8] := 0; { Start at slot 0 } for i := 0 to 15 do begin Port[$3C9] := i * 4; { Red } Port[$3C9] := 0; { Green } Port[$3C9] := i * 4; { Blue } end;

Readln; CloseGraph; end.

Key Differences to Keep in Mind

  • Hexadecimal Notation: QBasic uses &H (e.g., &H3C8), while Turbo Pascal uses a dollar sign $ (e.g., $3C8).
  • Reading Ports: Reading port $3DA to reset the video flip-flop is done by assigning it to a dummy variable (dummy := Port[$3DA]), which replaces QBasic's Dummy% = INP(&H3DA).
  • Standard Graph Unit Interference: If you use Turbo Pascal's built-in SetPalette routine later in the code, it expects the default hardware mapping and might temporarily break your custom remapping until you re-run your port loop.