Re: Video Mode 13h in windows XP ... impossible?

From: Beth (BethStone21_at_hotmail.NOSPICEDHAM.com)
Date: 02/18/04


Date: Wed, 18 Feb 2004 17:28:10 -0000

da_buddha wrote:
> Hello,

Hi :)

> I'm trying to figure out a way that I can use x86 ASM
> to draw a pixel to the screen. I've been researching for
> a while and have read the faq, but it now seems to me that
> what I'm trying to do *MAY* be impossible on newer operating
> systems

Doesn't sound at all "impossible" to me...

> I'm a teacher trying to come up with a good lesson on
> Machine Language and how graphics work. From what i've seen
> Mode 13h (320x200x256) is the best way to introduce someone
> to the way graphics function (especially and the grade 11 / 12
> high school level)

Yes; Mode 13h is an appropriate introduction because of three useful
attributes:

1. The framebuffer (2D array of pixels that gets drawn on the screen)
is fully contained within 64KB...this is useful because of the
(horrible) 16-bit real-mode addressing scheme in DOS:

2. The organisation of pixel data is very simple: Every pixel is
simply a byte (there are 256 colours and bytes can range between 0-255
:)...

3. Every "VGA compatible" card (which, basically, _all_ cards these
days are...you actually have to go to an effort NOT to find one ;) is
able to display mode 13h without any fuss...

It looks very "blocky" by modern expectations and the standard "colour
palette" (set of colours used at any one time; Though only 256 colours
can be displayed, it's a "paletted" mode where you can select which
256 colours out of a wider palette of 262,144 available colours) is
very "grim"...though, it's quite possible to change that palette to
something more to your tastes (e.g. change the palette to a range of
greens and browns - cutting out colours like bright purple, which
won't be useful for this particular image - then you can render a
forest scene or whatever with more "useful" colours to make it look
better...or, by defining the palette to include the entire range of
greys possible from black to white, you can render a greyscale image
with great accuracy :)...

Note, there is NO problem using mode 13h under XP...if you write a DOS
application which switches to mode 13h (with "mov ax, 0013h; int 10h"
:) under XP, the "DOS box" emulation recognises this and switches the
display to "full screen" mode...it automatically switches back after
the program terminates (but, for those _actually_ running DOS - if
there will be any - it's usually good practice to set the video mode
back to 3 ("mov ax, 0003h; int 10h" :) so that it returns to the
standard text mode because, under DOS, if you didn't switch it back
manually, then it _stays_ in that video mode (with really big blocky
text characters ;)...this isn't so much of an issue under XP because
though the same thing is strictly still happening, if you
double-clicked on the icon in Explorer then the instant that program
terminates so does the "DOS box" and you return to the Windows desktop
(so, though you've technically left it in mode 13h when you finished,
you're not running anything else directly after it and the "DOS box"
terminating automatically returns to the Windows desktop at the usual
resolution and video mode that's running at...you'd only notice that
you hadn't cleaned up the video screen if you ran it under real DOS or
even opened up a "command prompt" and then ran your program from there
because, in that case, it would simply return from your program
without restoring the original video mode :)...

Windows has no problem displaying mode 13h DOS programs via its "DOS
box" mechanism...the only issue here is that NT kernels (NT / 2K / XP
:) switch to "full-screen" mode to display mode 13h and makes no
attempt to render it to a window under emulation (if you have your
mode 13h program running and attempt to move away from it with, say,
ALT + TAB to move to another application or pressing ALT + ENTER which
usually toggles between window and full-screen mode...then the
NT-based Windows kernels, like XP, will simply show a taskbar button
for your application at the bottom of the screen - so you can click on
this to return to your application - but it won't attempt to render
the screen to a window...interestingly, though, the Windows 9x kernels
(95 / 98 / ME) actually have emulation for rendering mode 13h into a
window...this, though, is slower to update because Windows is
basically "intercepting" every pixel write and redirecting it to a
windowing routine...this doesn't work particularly well with
animations, usually, because it caches up the graphics and renders it
all in discrete "chunks" - for speed reasons - which makes any fast
animations move jerkily around...note, this stuff, though, _ONLY_
happens if you try to render the program to a window under 9x-based
Windows kernels...NT-based Windows simply doesn't even bother to
attempt to render mode 13h under "emulation" to a window and only
displays it "full-screen" or not at all (just a taskbar button to
return to the application full-screen once more only :)...and if you
run things full-screen under even Windows 9x then there's no problems
as it writes directly without any "emulation" or "interception"...

If you're only using XP exclusively, then you'll simply never
encounter that, anyway...but the difference in implementation is worth
noting if it'll ever be run under Windows 98 or something like that...

> can anyone out there help me come up with a practical example
> of an ASM program that will draw a pixel to the screen?

Well, if you want "practical" (and also "relatively easy" so your
pupils can follow along) then, first, _ditch_ DEBUG...it works and is,
indeed, always available under any Microsoft OS...but it's a nightmare
to use properly...

A dedicated assembler (most of which are completely free and available
on the internet, _including_ even Microsoft's own MASM
assembler...basically, there's no money to be made with assemblers,
generally, that not even the commercial companies charge for their
products anymore ;) will be a hundred times easier to deal with...just
make sure to get the 16-bit versions of the assembler and linker so
that _DOS_ applications are possible...

For the absolute least bother (presuming you're only really going to
be doing just this kind of example, so all the "bells and whistles"
features of some of the dedicated assemblers aren't particularly
useful to you :) then download NASM - the "Netwide assembler" - and
output simple so-called ".com" files using the "flat binary"
mode...this gives you the least amount of "fluff" possible so that you
and your pupils can concentrate on the actual code and none of the
usual assembler "junk"...NASM syntax is designed to be "no red tape"
like this and can directly output these ".com" files with no
additional tools needed plus it's "free software" so there's
absolutely no problems with downloading it and making copies for all
your pupils and so forth (you probably wouldn't be doing anything
wrong with any assembler by making a copy for each pupil...but, with
NASM, this is _certainty_ that it's okay for you to do so...the people
who write and maintain NASM are actually right here, by the way, so
they'll confirm this, I'm sure :)...

http://nasm.sourceforge.net/

It actually _doesn't matter_ if you download a DOS or Windows version
of NASM because either will be able to create these 16-bit DOS ".com"
files, anyway...might, in fact, be best to grab the Windows version
(not that it's likely that you'll be in any danger of breaking DOS's
640KB limit writing simple programs like this but the Windows version
can operate with all of your RAM when assembling programs...so, as it
makes no difference which you download to what you want to do, best to
pick the version that has the least limitations, even if there's no
chance of you ever hitting those limitations with simple programs like
these :)...

As I say, NASM is useful here because it can _directly_ output ".com"
files without a linker (so it's just one program you need to assemble
things, much like DEBUG :) and you'll need absolutely minimum "set-up"
because NASM is a "no red tape" assembler so it cuts out most of the
usual assembler directive "fluff" (your source code can basically
contain just one or two "set-up" lines and then it's all otherwise
_assembly code_...other assemblers have a habit of asking for things
like "segment declarations" and specifying processors and useless
things that would only distract your pupils from understanding what's
going on in the examples :)...

Basically, just grab version 0.98.38 under "Win32 binaries" and, also,
you can grab also version 0.98.38 under "nasm documentation" too
(well, the manual could come in handy, yeah? ;) off the NASM download
page...the reason for there being so many files is simply because NASM
works on lots of different platforms and is continually being upgraded
and developed that all the different versions are available...just
grab the Win32 stuff and the latest versions :)...the Windows versions
of NASM have a "w" added onto the filename just so that it doesn't
conflict with the filenames of other versions...but this isn't
necessary and you can rename it without the "w" to just
"nasm.exe"...this doesn't really matter either way, it's only a
name...just pointing this out so that if I write "nasm" as a
command-line anywhere later on, then it might be "nasmw" to you, if
you haven't renamed NASM to its more "traditional" filename...

NASM's strength is kind of in its very simplicity (plus, being "free
software", there's no "legal" worries about making a personal copy of
it as many times as you need for each of your pupils on each machine,
which is another consideration that a teacher has to look out for, I
know ;)...so, your pupils should easily get to grips with things and
can concentrate on writing the code rather than working out how the
assembler works...

You need to create a "source file" but it's just a plain ASCII text
file so just using "Notepad" for this (like DEBUG, comes with every
copy of Windows automatically :) is just perfect...unlike DEBUG, this
is the more traditional way - much like would be done with a
high-level language compiler - and makes editing your source code very
easy using the traditional editing facilities everyone'll be used
to...much nicer for your pupils to follow than trying to get to grips
with DEBUG (note that you can _still_ run DEBUG on the file NASM
generates (just put the ".com" file's name after "DEBUG" on the
command line and it'll start up DEBUG with the program loaded into
RAM, ready for DEBUG to manipulate in the usual way :), if you also
intended, perhaps, to use DEBUG for "illustrative
purposes"...although, one _big_ problem with using DEBUG to "single
step" through the code and show what's happening inside the machine -
a great idea to make clear what the machine is actually doing when it
runs the code - is that DEBUG itself uses the screen too so its output
would conflict with the program's output...but, otherwise, if you can
tolerate this, then DEBUG could be used to step instruction by
instruction through the program and print out the register contents
for everyone to actually _see_ the machine "MOV" one value to another
register or whatever, as it is running :)...it doesn't matter, of
course, what you call the source file you say but it's "tradition" to
give it a ".asm" file extension to show that it's an assembly language
source file (most tools don't care about this at all, mind you...it's
more for the user's benefit to immediately see that it's an assembly
language source file...this is basically roughly why we all tend to
abbreviate assembly language to just saying "ASM" around here and in
the newsgroup title, by the way...it's the traditional "mnemonic" for
the name of assembly language itself...well, once you start using
mnemonics for everything, why stop? ;)...

Anyway, using NASM, it's really easy to create a working ".com"
program (perfectly useful for this kind of example and as free as
possible from distracting "junk" as you can get :)...basically, you
only include a single "org 100h" directive at the start of the file
before the code...this simply starts the program at offset 100h which
is needed for a ".com" file (basically, ".com" files are _literally_
loaded from the file "as is" into memory at offset 100h and then
executed...absolutely no fuss other than the "org 100h" directive,
which just makes sure that the code's offsets are correctly set-up
because DOS loads it at offset 100h into RAM when it loads it because
there's a 256 byte "header" in front of the program, simply for DOS's
own internal "management" purposes to record information about the
program for DOS's own internal purposes...actually, the command-line
can also be read out of this "header" - a byte count of characters at
offset 80h and from 81h unless the end is the actual command line -
but, well, you probably have no need for processing command-lines at
all in such simple examples...nice to know it's there and relatively
easy to access, though :)...

Better yet, NASM defaults to "flat binary" mode and 16-bits that other
than "org 100h", there is no other piece of "administrative" stuff you
need at all...this makes it easy for your pupils to simply type: "NASM
filename.asm -o filename.com", substituting "filename" for the
filename of the source file, obviously...the "-o" option simply
specifies the output filename, nothing more (NASM defaults to NOT
putting the ".com" extension, which is NOT what we want, actually,
because DOS expects to see that...so, the "-o" option is just to make
sure it has the needed ".com" file extension at the end of the output
filename...otherwise, the "filename" can be anything at all that you
want, NASM is not in the least bit fussy about that ;)...to execute
the program, simply type the name (with or without ".com" at the end
:) at the command-prompt...or, of course, you can equally double-click
on the icon that'll appear in Explorer, if you prefer being to "point
and click" at things...it won't make any difference here...the
command-line might be preferable only because you've already had to
use it to assemble things with NASM so, as you're already there, this
is usually the least hassle ;)...

As you can see, I'm recommending using NASM here because there's the
absolute minimum "red tape" nonsense involved to get up and running
that it should be easy to explain and you can let your pupils do
everything themselves (nothing beats the satisfaction or learning
experience of them being able to do be left alone to try things out
themselves...NASM makes this simple enough that the usual chaos that
ensues giving children a task to do alone - yeah, I know what kids can
be like...telling them just to "sit down" can be a challenge enough as
it is ;) - shouldn't be too problematic or need teacher to step in too
often to "save the day" ;)...

The most basic example would look something like this:

--------------- >8 ----------------

; Pixel.asm
;
; Assemble with:
; NASM pixel.asm -o pixel.com
;

        org 100h

        ; co-ordinates for pixel (there is no
        ; actual "middle pixel" because 320 and
        ; 200 are even numbers but this is close
        ; enough to that ;)...
        ;
      X equ 159
      Y equ 99

        ; Set up graphic mode 13h
        ; (320 x 200 in 256 colours)
        ;
        mov ax, 0013h
        int 10h

        ; Set ES to point to the segment
        ; of video memory (address
        ; 0A000:0000h is the start of
        ; video memory :)...
        ;
        mov di, 0A000h
        mov es, di

        ; Calculate offset in memory
        ;
        mov di, (320 * Y) + X

        ; Write the value 15 (white) to
        ; this offset in the video (ES)
        ; segment of memory...
        ;
        mov byte [es:di], 15

        ; Wait for keypress before continuing
        ; (Gives a chance to actually look at
        ; what we've drawn on the screen :)
        ;
        mov ah, 00h
        int 16h

        ; Restore text mode
        ;
        mov ax, 0003h
        int 10h

        ; RETurn to DOS
        ;
        ret

--------------- 8< ----------------

...and "X" and "Y" can be altered to move the single white pixel
around the screen...the address is actually calculated at
assembly-time by NASM itself here - you'd want to go further to show
how to work it out with machine instructions - but this is a good
starting point just to illustrate the "basics"...note the use of "mov
ah, 00h; int 16h" to pause the program (very easy to forget something
simple like this and then wonder why you can't see anything:
computers, of course, run so fast that it can complete the program
before you've even had a change to look at the output...so, waiting
for a key press gives the user the chance to say when the program
should finish and is a convenient way to "pause" the program to look
at the graphics output :)...also, I've used "ret" at the end to get
back to DOS (DOS is set up so that a procedure "ret" actually jumps to
a "int 20h" instruction, anyway..."ret" as in "RETurn to DOS" would
just seem a whole lot easier to comprehend than "int 20h", at first
:)...

Note, as I think it was Frank who mentioned this in his reply, that "x
* 320" can also be achieved by "(x * 256) + (x * 64)" and multiplying
by a power of two can be done easily by just shifting the bits left in
the register, so that's "(x << 8) + (x << 6)"...one idea here is to
show the usual "x * 320" code using "mul" first...and then show how
it's the equivalent of shifting bits and adding them together because
256 + 64 = 320 with a little diagram of the bits in the register being
shifted around or whatever...so, when one of the pupils decides to
start moaning: "Why are we learning this assembly nonsense? What use
is learning this?", you can _directly answer_ that question by showing
how you can approach a problem in a lower-level way like this...it
gives a small glimpse of "assembly thinking" and how by tackling the
problem at a lower-level - thinking of the actual bits sitting in the
registers - you can come up with alternative methods which might be a
whole lot faster or easier or whatever...then, yes, you can note that
it's perfectly possible to also use "(x << 8) + (x << 6)" in something
like C (this is actually written in C syntax, in fact ;) but that,
well, unless you know how the machine works at a lower-level and learn
at least some basic assembly language, then you won't _realise_ that
there exists other better alternatives...when using C, you're _taken
away_ from the machine so realising these alternatives isn't at all
easy or natural unless you've done some assembly language programming
which makes you realise what the machine is and isn't good at doing...

Was this the kind of thing you were thinking about?

Beth :)