Luke Rossie
Luke Rossie

Reputation: 61

Writing to video memory in VGA mode 13h

I'm using NASM to learn x86 assembly, running my code in qemu on linux. I am trying to draw a pixel on the screen.

Why is it that

mov     bx,0xA000 
mov byte [bx],0x0A

doesn't seem to do anything, but

mov     bx,0xA000 
mov     es,bx 
mov byte [es:di],0x0A

is able to draw a pixel?

A second question: Why do I have to use [es:di] rather than just [es]?

Upvotes: 6

Views: 2936

Answers (1)

Brendan
Brendan

Reputation: 37232

In real mode, an address used for reads and writes consists of a segment and an offset, and the actual address read from or written to is calculated as segment * 16 + offset.

Note: In documentation, etc; the segment and offset are typically as written 2 numbers joined by a colon (like 0x1234:0x5678, where 0x1234 is the segment and 0x5678 is the offset).

For 0x0000:0xA000 the actual address is 0x0000A000. This address typically corresponds to RAM.

For 0xA000:0x0000 the actual address is 0x000A0000. This is where the legacy VGA display memory area is (which is used when video cards emulate ancient VGA's 320 * 200 video mode).

All reads and writes use a segment register, and if you don't specify one explicitly (e.g. mov [es:di],ax) then the CPU uses a default/implied segment register, which is normally DS (unless SP or BP is being used for the offset part of the address which makes SS the default/implied segment, or its instruction fetch which always uses CS). This means that mov [di],ax does the same as mov [ds:di],ax.

The offset part is always explicit and the CPU doesn't support (e.g.) "offset is assumed to be 0x0000 as default". This means you can't do mov [es],ax because there is no offset (and no way to encode the instruction) and you'd have to do something like mov [es:0x0000],ax instead.

Upvotes: 8

Related Questions