Home » Assembler » Graphics with Direct Memory Access

Graphics with Direct Memory Access

Drawing pictures on the screen using the bios interrupts is all very easy, but when push comes to shove, its also very, very slow as the bios routines are built to cope with every graphics mode. A faster way of plotting pixels is to directly place the bits in video memory, using, for example, a move instruction. This is very, very fast. but it does limit you to the resolution for which the routine was written.

The simplest video modes for demostrating this principle, is that of mode 19, (13h) which has 320 x 200 pixels and uses 256 colours. 256 is 2^8, meaning that the colour value takes up exactly one byte per pixel. This makes the actual setting of pixels very easy, move the colour value into the appropriate memory byte. The video memory for this mode begins at memory address A000h, and the pixels are then linearly in memory row by row. The memory location to write to for pixel (x,y) is A000h + (y * 320) + x.

Unfortunately, this involves a previously unencountered complication. With the programs we have written so far, the data and program have all been placed in the one segment. However, the graphics memory is not within that segment, so we need a segment offset. This offset is the start of video memory. To access an address we now use two parts, the segment (stored in the es register) and the offset (stored in the di register). The whole address is referenced es:[di].

Drawing horizontal and vertical lines in this mode is easy: to draw a horizontal line, simply fill all memory addresses from the starting point to the end point; to draw a vertical line, add 320 to the current pixel position and this gives the next point. Below is a sample program demostrating this.

jmp start
;  Draws a horiz and vert line
  startaddr	dw	0a000h	;start of video memory
  colour	db	1
   mov ah,00
   mov al,19
   int 10h			;switch to 320x200 mode
   mov es, startaddr		;put segment address in es
   mov di, 32000		;row 101 (320 * 100)
   add di, 75			;column 76
   mov al,colour		;cannot do mem-mem copy so use reg
   mov cx, 160			;loop counter
    mov es:[di],al		;set pixel to colour
    inc di			;move to next pixel
  loop hplot
   mov di, 16000		;row 51 (320 * 50)
   add di, 160			;column 161
   mov cx, 100			;loop counter
    mov es:[di],al
    add di, 320			;mov down a pixel
  loop vplot
   mov ah,00
   int 16h			;await keypress
   mov ah,00
   mov al,03
   int 10h
   mov ah,4ch
   mov al,00			;terminate program
   int 21h

That, basically is all there is to it. Note how for switching to and from graphics mode we still use the int calls. This is because the change only occurs generally once per program and so, unlike pixel plotting is not a bottle-neck.

The primary use of assembler for graphics is frequently to embed the code in a higher level language. Given below, then is an implementation of a few basic graphics primatives created in assembler but embedded withing pascal functions (these will work with Borland/Inprise’s Turbo Pascal Compilers or can be easily converted to equivalent C/C++ functions).

  vga : word = $A000;

  oldmode : byte;

Procedure setMCGA; assembler;
{Sets the graphics mode, including saving
the previous graphics mode}
  mov ax,0F00h
  int 10h
  mov oldmode,al
  mov ax,0013h
  int 10h

Procedure settext; assembler;
{Returns the program to the graphics
mode it was previous in}
  mov ah,00h
  mov al,oldmode
  int 10h

procedure putpixel( x,y : word; colour : byte);
{sets the pixel at (x,y) to the
colour given by colour.
Calculations are done using shifts
and additions not multiplications}
  if (x>319) or (y>199) then exit;
    push ds	{save these two registers...}
    push di	{...by putting values on stack}

    mov ax,y
    shl ax,1	{ax=y*2}
    mov bx,ax	{bx=y*2}
    shl ax,2	{ax=y*8}
    add ax,bx	{ax=(y*8)+(y*2)=y*10}
    shl ax,5	{ax=(y*10)*2^5=y*320}

    mov bx,x	{ax has y offset, bx has x}
    add ax,bx	{add the offsets}

    mov di,ax	{di now has currect offset}
    mov ah,colour
    mov ds,vga	{es now has segment}
    mov ds:[di],ah	{plot the pixel}

    pop di	{restore reg values}
    pop ds

Leave a Reply

Your email address will not be published. Required fields are marked *

Name *
Email *

February 2020
« Aug    


Recent Comments