Repository navigation
Using Out Port command 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)
- 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]
- 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]
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!
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%
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:
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.
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.
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.
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.
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.
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.
- 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.