19

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:

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

3 Answers 3

15

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

This will produce the following output:

  • low intensity, cyan/magenta/white

    rows of dots, top third in cyan, middle third magenta, bottom third white

  • high intensity, cyan/magenta/white

    rows of dots, top third in cyan, middle third magenta, bottom third white, brighter than the previous screenshot

  • high intensity, red/green/yellow

    rows of dots, top third bright green, middle third bright red, bottom third yellow

  • low intensity, red/green/brown

    rows of dots, top third green, middle third red, bottom third brown

(Also tested on actual hardware.)

1
  • 3
    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). Jan 4, 2019 at 20:04
8

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
8
  • 1
    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). Jan 4, 2019 at 13:44
  • 1
    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, 2019 at 19:49
  • 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, 2019 at 20:51
  • 1
    @john_e I'm using DOSBox on Windows 10. The weird thing is I've tried out Defender of the Crown in CGA mode with the same DOSBox configuration and sure enough, the colors work perfectly. I've tried both your BIOS and direct color select register examples and i'm still getting the light colors. I'm assembling with NASM to make a COM file with these flags: nasm -f bin -o test.o test.asm Jan 4, 2019 at 22:05
  • 1
    @JohnnyStarr I don't know what you're doing differently. You can find my test code at seasip.info/Misc/brown.asm - it works for me under dosbox -machine cga
    – john_e
    Jan 4, 2019 at 23:54
2

for those like me who read this 5 times and still didn't get it. the explanation is here:

https://www.chibialiens.com/8086/platform.php?noui=1

; 1 set video mode

mov ah, 0           ; video command
mov al, 4           ; cga mode, 320x200, 4 colors
int 10h 

; 2. set up palette

mov ah, 0bh         ; palette command
mov bh, 1           ; bh is subcommand, 1 = choose which palette
mov bl, 0           ; this sets the palette to red green yellow black
int 10h

; 3. set up palette brightness

mov ah, 0bh         ; palette command
mov bh, 0           ; bh is subcommand, 0 = control brightness
mov bl, 0           ; low intensity. this makes yellow into brown
int 10h

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .