12

For those of you retro developers out there, I am having a hard time figuring out how exactly to select the "darker" color palette in 320x200 CGA mode. Here's what I have so far:

setup_cga_graphics:
    mov     ah, 0           ; int 10,0
    mov     al, 4           ; mode 4 (cga 320x200 4 color)
    int     10h             ; bios int

    mov     ah, 0Bh         ; interrupt 10B
    mov     bh, 1           ; 1 = 4 pallette mode
    mov     bl, 0           ; 0 = warm colors (r,g,b) 1 = cool (c,m,w)
    int     10h             ; bios int

I assemble this with NASM and fire it up. It brings up a C:\ prompt in bright yellow. This tells me that somehow the "intensity bit" is set high and thus the brighter color scheme is selected by default. I realize this is somewhat arcane/esoteric and absolutely obsolescent. I guess I'm hoping that a few of you oldschool x86 coders are still out there.

I tried looking at other interrupts to set the intensity bit like service 10H, however it appears to only support EGA. Any pointers would be great.

EDIT: To avoid confusion i've attached two images, one from Defender of the Crown using the lower intensity that I am aiming for:

What I'm not looking for is this:

migrated from stackoverflow.com Jan 3 at 23:22

This question came from our site for professional and enthusiast programmers.

  • 3
    I realize this is somewhat arcane/esoteric and absolutely obsolescent - I think you'll fit in just fine! – manassehkatz-Reinstate Monica Jan 4 at 3:38
  • Have you checked that Defender of the Crown (or something else) correctly displays brown on your test machine? – Tommy Jan 4 at 21:41
10

Your code is correct; a yellow prompt means that you’re using the red/green/brown palette. However, to get the low intensity variant, you also need to call interrupt 10h service 0Bh with BX set to 0 (black background, low intensity; strictly speaking, you can have any background — the bottom four bits, 3–0 — and the fifth bit, bit 4, controls the intensity; this maps to register 03D9h, the colour control register). You can draw the various colours and flip palettes to see the difference:

    org 100h

    section .text

start:
    mov ax, 4           ; set CGA 320x200
    int 10h

    mov ah, 0Bh         ; set the cool palette
    mov bx, 0101h       ; (cyan, magenta, white)
    int 10h

    xor bx, bx          ; low intensity, black background
    int 10h

    mov ax, 0B800h      ; draw some pixels in each colour
    mov es, ax
    mov di, 0
    mov bx, 320
    xor ax, ax
    mov cx, bx
    rep stosw
    inc ax
    mov cx, bx
    rep stosw
    inc ax
    mov cx, bx
    rep stosw
    inc ax
    mov cx, bx
    rep stosw

    mov ah, 1           ; wait for a character
    int 21h

    mov ah, 0Bh
    mov bx, 0010h       ; high intensity
    int 10h

    mov ah, 1           ; wait for a character
    int 21h

    mov ah, 0Bh         ; set the warm palette
    mov bx, 0100h       ; (red, green, brown)
    int 10h

    mov ah, 1           ; wait for a character
    int 21h

    mov ah, 0Bh
    xor bx, bx          ; low intensity
    int 10h

    mov ah, 1           ; wait for a character
    int 21h

    mov ax, 4C00h       ; exit
    int 21h
  • perhaps I wasn't 100% clear on my original question, but what I'm getting at is the darker set of colors. Your example works just fine, but its with red, green and yellow (not brown). – JohnnyStarr Jan 4 at 20:04
4

On the original IBM PC BIOS and true compatibles, the foreground intensity can be set using INT 10h with AH = 0Bh and BH = 00h. The low four bits of BL give the background colour, and bit 4 gives the foreground intensity. This is documented in (for example) the PC XT technical reference, page A-53.

So after selecting your palette, this should switch to low intensity (brown rather than yellow text):

mov ah, 10h
mov bh, 0   ; Set background / intensity
mov bl, 0   ; Black background, low intensity 
int 10h

Alternatively, you can avoid possible BIOS compatibility issues by writing directly to the CGA colour select register at 03D9h. This won't work on non-CGA hardware:

mov ax,40h
mov es,ax       ; ES -> BIOS data segment
mov al,es:[66h] ; Last value written to 03D9h
mov dx,03D9h
and al,0EFh     ; Reset intensity bit
mov es:[66h],al ; Update last value written
out dx,al       ; And write to the CGA
  • But that doesn’t change the palette, which is what the question is about (switching between the red/green/blue and cyan/magenta/white palettes). – Stephen Kitt Jan 4 at 13:44
  • My reading of "I tried looking at other interrupts to set the intensity bit" is that the the questioner wants to know how to control the foreground intensity (bit 4 of the colour select register) rather than select the palette (bit 5). – john_e Jan 4 at 19:49
  • I have combined both @john_e and Stephen Kitt's source code and I am still only getting red, green and yellow. I was comfortable switching palettes just fine, but what I can't figure it is how to switch intensity. – JohnnyStarr Jan 4 at 20:06
  • Please see my edit at the top, I've included some images to clarify what I meant to originally ask. – JohnnyStarr Jan 4 at 20:15
  • 1
    It works for me in PCEM on an emulated IBM XT with CGA, but this behaviour may not be implemented by clone BIOSes or EGA/VGA cards. – john_e Jan 4 at 20:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.