Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Beginner] Video mode 12h

1,641 views
Skip to first unread message

Thomas L. Christensen

unread,
Mar 4, 2003, 5:13:45 AM3/4/03
to
Hi

I am a beginner, using Peter Abel's book to learn from. I chapter 9 he
has two examples I would like to mix. In the one he is using video
mode 12h and show how to draw pixels using int 10 funcion 0Ch, in the
other he use video mode 03h and draw directly to the video memory (in
his example he use 0B900h).

Int 10 function 0Ch is slow, so I would like to draw pixels directly
to memory in video mode 12h. I have changed the memory area to 0A000h,
set mode 12h and ... well, now I'm stock. I don't really know what to
do from here (see procedure B10DISPLY). Any help is appreciated,
including tutorials on video mode 12h.

The original files from the book is here
http://hjem.get2net.dk/lindblad/temp


.MODEL SMALL
.STACK 64
VIDEO_SEG SEGMENT AT 0A000H
VID_AREA DB 1000H DUP(?)
VIDEO_SEG ENDS
.286 ; --------------------------------------------------
.CODE
A10MAIN PROC FAR
MOV AX,VIDEO_SEG ;Addressability for
MOV ES,AX ; video area
ASSUME ES:VIDEO_SEG
MOV AH,0FH ;Request get
INT 10H ; and save
PUSH AX ; current mode
PUSH BX ; and page
MOV AX,0012H ;Set mode 12h,
INT 10H ; clear screen
MOV AX,0500H ;Set page #0
INT 10H
CALL B10DISPLY ;Process display area
MOV AH,10H ;Wait for keyboard
INT 16H ; response
MOV AH,05H ;Restore
POP BX ; original
MOV AL,BH ; page number
INT 10H
POP AX ;Restore video
MOV AH,00H ; mode (in AL)
INT 10H
MOV AX,4C00H ;End of processing
INT 21H
A10MAIN ENDP
; -----------------------------------------
B10DISPLY PROC NEAR
PUSHA ;Preserve general registers

;How do I define pixel and color?
MOV AX,??? ;Pixel and color
MOV DI,0 ;Start of display area
MOV CX,320 ;Pixels per row (1 row here)

;What do I have to do here?
B30: MOV ES:WORD PTR[DI],AX ;Pixel/color to display

INC DI
LOOP B30 ;Repeat CX times

POPA ;restore registers
RET ; and return
B10DISPLY ENDP
END A10MAIN

--
Thomas L. Christensen - Svendborg, Denmark

JGC

unread,
Mar 4, 2003, 10:17:59 PM3/4/03
to
Being lazy I avoided this mode.
You might try,

http://www.zerosecurity.de/modules.php?op=modload&name=News&file=article&sid
=2663&mode=&order=0&thold=0

Mouse use in mode 12h,

http://www.programmersheaven.com/zone5/cat710/1423.htm

John Casey


"Thomas L. Christensen" <tlcnos...@get2net.dk> wrote in message
news:fa5b02f8.03030...@posting.google.com...

Tim Roberts

unread,
Mar 5, 2003, 2:38:25 AM3/5/03
to
tlcnos...@get2net.dk (Thomas L. Christensen) wrote:
>
>I am a beginner, using Peter Abel's book to learn from. I chapter 9 he
>has two examples I would like to mix. In the one he is using video
>mode 12h and show how to draw pixels using int 10 funcion 0Ch, in the
>other he use video mode 03h and draw directly to the video memory (in
>his example he use 0B900h).
>
>Int 10 function 0Ch is slow, so I would like to draw pixels directly
>to memory in video mode 12h. I have changed the memory area to 0A000h,
>set mode 12h and ... well, now I'm stock. I don't really know what to
>do from here (see procedure B10DISPLY). Any help is appreciated,
>including tutorials on video mode 12h.

You might want to get a book. Mode 12h is a 640x480 planar mode. This
means you don't actually see an entire pixel at once. Each bit represents
one pixel, but the 4 bits that make up each pixel are in separate parts of
memory, and only one plane is visible at any one time.

To write pixels in mode 12h, you need to set VGA registers to indicate
which planes you want to affect, then you write bits into the frame buffer
indicating which pixels you want to touch.
--
- Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Thomas L. Christensen

unread,
Mar 5, 2003, 10:54:58 AM3/5/03
to
On Wed, 5 Mar 2003 14:17:59 +1100, "JGC" <jkc...@bigpond.com> wrote:

>Being lazy I avoided this mode.

Hmm, I hoped it would be not too complicated...

Thanks. It looks like two good links. I am sure I can use it.

Thomas L. Christensen

unread,
Mar 5, 2003, 11:01:49 AM3/5/03
to
On Tue, 04 Mar 2003 23:38:25 -0800, Tim Roberts <ti...@probo.com>
wrote:


>To write pixels in mode 12h, you need to set VGA registers to indicate
>which planes you want to affect, then you write bits into the frame buffer
>indicating which pixels you want to touch.

I will have a look at it.

BTW - is VESA easier to use?

TS

unread,
Mar 5, 2003, 3:46:17 PM3/5/03
to
>BTW - is VESA easier to use?

The linear modes are just as simple as VGa 13h, the banked modes are a
bit more difficult.

JGC

unread,
Mar 5, 2003, 3:39:34 PM3/5/03
to

"Thomas L. Christensen" <t...@get2net.dk> wrote in message
news:g67c6vkd3i6k3l9te...@4ax.com...

> On Wed, 5 Mar 2003 14:17:59 +1100, "JGC" <jkc...@bigpond.com> wrote:
>
> >Being lazy I avoided this mode.
>
> Hmm, I hoped it would be not too complicated...

Someone sent me the code below which I used as
it gave me high res with 256 colors instead of just 16.

..model small
..stack
..data
coords dw 480 dup (0)
window db 480 dup (0)
task db 10
vinfo db 255 dup (0)
..code
main proc
mov ax,@data
mov ds,ax
call define_coords
call define_window
call initvesa
mov al,14
mov bx,300
mov dx,300
call putpixel
mov ah,07h
int 21h
mov ax,0003h
int 10h
mov ax,4c00h
int 21h
main endp

initvesa proc
;***************************************
push ds
pop es
lea di,vinfo
mov cx,0101h
mov ax,4f01h
int 10h
;***************************************
mov ax,4f02h
mov bx,101h
int 10h
mov ax,0a000h
mov es,ax
ret
initvesa endp

define_coords proc
xor cx,cx
xor si,si
again_def_c: mov ax,640
xor dx,dx
mul cx
mov coords[si],ax
inc si
inc si
inc cx
cmp cx,480
jb again_def_c
ret
define_coords endp

define_window proc
xor si,si
xor ax,ax
def_w1: mov window[si],al
inc si
cmp si,102
jbe def_w1
mov al,1
def_w2: mov window[si],al
inc si
cmp si,204
jbe def_w2
mov al,2
def_w3: mov window[si],al
inc si
cmp si,307
jbe def_w3
mov al,3
def_w4: mov window[si],al
inc si
cmp si,409
jbe def_w4
mov al,4
def_w5: mov window[si],al
inc si
cmp si,480
jb def_w5
fine: ret
define_window endp

putpixel proc
;bx=x dx=y al=col
mov si,dx
mov dl,window[si]
add si,si
mov di,coords[si]
add di,bx
; cmp di,coords[si]
; jae avanti1
; inc dl
adc dl,0
avanti1: cmp dl,task
je avanti2
mov task,dl
push ax
xor bx,bx
;***************************************************
; mov ax,4f05h
; int 10h
call dword ptr [vinfo+0ch]
;****************************************************
pop ax
avanti2: mov es:[di],al
ret
putpixel endp

end main

JGC

unread,
Mar 5, 2003, 6:15:17 PM3/5/03
to

"TS" <nomai...@deinmeister.de> wrote in message
news:3e665b80....@News.CIS.DFN.DE...

> >BTW - is VESA easier to use?
>
> The linear modes are just as simple as VGa 13h, the banked modes are a
> bit more difficult.

The hard part was trying to find out _exactly_ what
steps to take to enter the desired linear mode. I was
never able to get the _complete_ set of steps to achieve
this result. I could never find complete examples or
routines that I could call to put the computer graphics
in the desired 24 bit _linear_ mode.

John


Beth

unread,
Mar 12, 2003, 12:55:43 AM3/12/03
to
[ Cross-posted because someone else was asking about video programming
in news:alt.lang.asm recently and I avoided explaining video mode 12
(because, as I rightly guessed, it would require an entire lengthy
post all to itself to explain...that post being this post you're
reading now and just look at the size of it! ;)...so, I can kill two
birds with one Stone by dealing with mode 12h here because Thomas is
asking specifically about it...and I've also included some source code
at the end which turns all the "theory" of both posts into something
you can actually see...which - knowing Frank - he'll have hours of fun
converting to NASM and making it draw funny shapes...hehehe ;) ]

Thomas L. Christensen wrote:
> Hi

Hi :)

> I am a beginner, using Peter Abel's book to learn from. I chapter 9
> he has two examples I would like to mix. In the one he is using
video
> mode 12h and show how to draw pixels using int 10 funcion 0Ch, in
> the other he use video mode 03h and draw directly to the video
memory
> (in his example he use 0B900h).
>
> Int 10 function 0Ch is slow, so I would like to draw pixels directly
> to memory in video mode 12h. I have changed the memory area to
> 0A000h, set mode 12h and ... well, now I'm stock. I don't really
know what
> to do from here (see procedure B10DISPLY). Any help is appreciated,
> including tutorials on video mode 12h.

Video mode 12h, as others have mentioned, is a "planar" mode which
makes things a bit complicated...perhaps, first, you should try video
mode 13h (there is tons of stuff about this on the 'net...as it's got
to be the easiest (and most wasteful but that's another story ;)
graphics video mode ever constructed...horrible resolution, mind
you...it's 320x200 in 256 colours :)...that should give you grounding
in the things you generally need to do for graphics modes (as opposed
to the text modes that the book has already shown :)...then, once
mastered, you can move to video mode 12h which has the added problem
of "bitplanes" for you to learn about too...

[ Cautionary word of warning: Video mode 12h is one of the most
awkward
graphics modes to use on the PC...only ModeX modes would be worse than
mode 12h and there's no way you're going to understand ModeX modes
until you learn all about "planar" modes like mode 12h (ModeX modes
are very "advanced" because they aren't standard BIOS video modes
at all and the way "bitplanes" work in them is, quite frankly,
a little bit insane... ]

By coincidence, I've just written a "mini-tutorial" about video mode
13h in the thread "Doing graphics + hardware I/O + misc" over in
news:alt.lang.asm ...coupled with Peter Abel's book then you should
have no great difficulties getting video mode 13h mastered...

As for video mode 12h, it's a bit of an exception because it's a
"planar" mode...you'll also note that the memory window for the video
framebuffer at A000h is only 64KB in size...but if you do the maths,
video mode 12h requires a minimum of 640x480 with 4 bits per colour =
150KB...it's too big!! It won't fit into the A000h segment...but not
to
worry because this is where "bitplanes" come into the picture...for
mode 12h, there are 4 bitplanes (the amount of bitplanes _should_
equal
the amount of bits required for the colour value...with ModeX modes,
this isn't true and is what makes them slightly insane...but,
generally,
if a mode is "planar" then the number of colours should tell you how
many
bitplanes there are...2 to the power of the bitplanes should tell you
the
colour depth...or, of course, the other way around too :)...each
"bitplane"
is a bit like a sheet of acetate with a monochrome picture on it...if
you take four of these "bitplane" acetate sheets and then overlay them
on top of each other on one of those overhead wall projector machines,
then the light shining through each acetate will "merge" together to
form one picture on the wall...that's roughly how bitplanes in
"planar" modes work too...

[ ASCII graphics follows...set font to a fixed font like courier to
see properly :) ]

+---------------+ Bitplane #0
| O |
| +-----\---------+ Bitplane #1
| | O |
| | +-----\---------+ Bitplane #2
| | | O |
| | | +-----\---------+ Bitplane #3
| | | | O |
| | | | |

Each bitplane is actually perfectly aligned on top of each other but,
for the purposes of making the diagram readable, I've offset them to
show each one individually (each "sheet" of acetate would be exactly
the same size and their corners would meet up exactly...but you just
can't show that with ASCII graphics :)...the "O" symbols all are the
same pixel (same x and y co-ordinates :) but on different
bitplanes...each bitplane itself is ONLY a monochrome bitmap so the
pixel in each bitplane is either off or on (zero or one :)...

The VGA card, though, will compose each of the bitplanes together -
just like the actetate sheets "merge" when we put them together on the
overhead wall projector - when it renders the framebuffer...as mode
12h is a 16 colour mode, we only need 4 bits to select any one of the
colours...and, simply, those four bits of the colour value are the
four different bits in each of the bitplanes...we're reading it
"laterally", if you like...bitplane #0 has a monochrome image of every
bit #0 in the colour value on the screen...bitplane #1 is bit #1 of
the colour...bitplane #2 is bit #2 of the colour...bitplane #3 is bit
#3 of the colour...the diagonal line in the ASCII graphics shows the
line along which we read the colour value for the pixel...

So, to plot colour 15 (white), we plot a single bit in each of the
bitplanes at the same screen location...to plot colour 1, we'd plot
the single bit in bitplane #0 but would "unplot" those same bits in
the other bitplanes...the binary value of the colour is 4 bits and,
simply, each bit of that value tells you whether to plot or "unplot"
the bit in the bitplane (unplotting - setting the pixel bit to zero -
is as important as plotting - setting the pixel bit to one - because
it is the _combined_ values of each bitplane that specifies the colour
:)...

Okay, now that you've Hopefully got the rough idea about bitplane
modes, we can actually get to video mode 12h's implementation of
it...as mentioned earlier, the memory window at A000h is only 64KBs in
size so there's not enough room to access the entire screen in one
go...but there _is_ enough room (640x480/8 bits = 37.5 KB :) for one
monochrome bitplane image...so, once you've set up video mode 12h then
the video memory at A000h is essentially a 1 bit per pixel monochrome
image of the screen...with 80 bytes (80 x 8 = 640 pixels :) for each
scanline, repeated 480 times down the screen...

And to control which bitplane we're currently writing to, there's a
separate VGA register (accessed using port I/O commands :) which lets
us set which bitplanes to write to...it is possible with this register
to specify more than one bitplane as "active"...all this means is that
any of your writes to video memory will go to _more than one_ bitplane
at the same time...for reading a pixel value back, there's another
_different_ VGA register which specifies which bitplane you want to
read from...in the case of reading, it's only possible to specify
_one_ bitplane at a time (so to read the full colour information of a
pixel requires four reads(!) and four changes to the read bitplane
register :)...

To get at the write bitplane register, you have to send 02h to port
03C4h to specify you want to set the write bitplane register and then
you send a value from 0-15 to port 03C5h to set which bitplanes are
"active" (alternatively, as I do in my program, you can use a 16-bit
port write command to set both at the same time...but, if you do this,
be careful about the order...02h goes into AL and your value goes into
AH...the 16-bit writes are "byte-reversed" because Intel chips are
little-endian...I mention this because it's a really easy mistake to
put them the wrong way round...yes, so simple that I did it when I was
writing my code example...hehehe :)...

The read bitplane register is set by writing 04h to port 03CEh and
then which bitplane you want to read from is sent to port 03CFh (you
can also do this with one 16-bit port write too :)...my example code
below doesn't actually do any reading, though...the thing to note
about setting the read bitplane register is that, though you can set
multiple _write_ bitplanes in one go, you can only set _one_ read
bitplane at a time...and, therefore, the value you send to port 03CFh
is in the range 0-3 (0 = bitplane #0, 1 = bitplane #1, etc. :)...BUT,
when you set the write bitplane the range is 0-15 (bit #0 = bitplane
#0, bit #1 = bitplane #1, etc. :)...again, I'm stressing the
difference between the two here because the values are interpreted
differently for the read and write bitplane registers and it's easy to
forget or get mixed up or something...just stressing it to save you
all from horrible debugging sessions where you just can't work out
what's gone wrong...hehehe :)

The palette can also be changed to any 16 colours from the usual
24-bit range, just like I've already explained in my other post about
video mode 13h over in news:alt.lang.asm ...the standard palette
you're given actually neatly corresponds that bitplane #0 is blue,
bitplane #1 is green, bitplane #2 is red and bitplane #3 is
"intensity" (bright colours :)...but there's nothing sacred about the
standard palette at all and you can set any colour to anything you
like...in fact, you can get some groovy-looking "planar" special
effects by setting up special palettes (set most of the colours to
black or something and then set a few to different colours and then
the graphics only show up when certain combinations of bitplanes
align...this can give an interesting "cut out" effect where one
graphic is masked out by another...I was going to add this to my
example, actually, but it got big enough without the extra code for
that, that I thought I'd better stop before I get carried away with
all the pretty graphics and make it too complicated to follow...hehehe
:)...

As I've said, though, video mode 12h can be a very awkward mode to use
because of the bitplane stuff...a general routine that just plots a
single pixel needs to set the read bitplane register four times - one
for each bitplane - and read in four bytes from video memory (and
reading video memory is slower than writing)...then it needs to change
just one bit in the byte it read for each bitplane, switching it on or
off according to the colour we want to plot...then it has to write
each of the four bytes back to video memory, changing the write
bitplane register four times...

As you can guess, general pixel plotting routines for video mode 12h
are slow because of all this reading and writing and playing with
individual bits...which is why - if you want speed - you don't really
wanting to be plotting things pixel by pixel to draw lines and
circles...I made a point before in another post that the BIOS
"PutPixel" routine is not the routine to use if you want speed (and
was forced to prove it with an example which does both and the
difference is VERY noticable indeed :)...this still applies but is
much, much worse in video mode 12h because the video memory is just
not laid out in a way that suits plotting complex graphics pixel by
pixel...so, all in all, I'm not at all surprised that the BIOS routine
you're calling is too slow for you...they are NOT routines for doing
things fast, they are routines that make things "easy" (now you know
about all this bitplane nonsense, you can see that the BIOS really
does make life easier by hiding all that complexity...BUT there's a
trade off...you get absolutely dire performance from the BIOS routines
:)...

At one time, "planar" modes were the standard and, with other machines
(especially the older machines :), that's what you'd have to play
with...amazingly, video mode 13h is "linear" and not "planar" because
of a problem with "backwards compatibility" (they'd set up the EGA to
only use 4 bitplanes...a 256 colour mode needs 8 bitplanes...they
needed the VGA to be compatible with the EGA and, thus, couldn't
change what they'd set in stone with the EGA...so, they added some
very weird circuitry to the VGA to deal with trying to draw 8 bitplane
graphics using only 4 of them...this circuitry does make things
simpler but - would you believe? - it actually means that video mode
13h wastes 3/4(!) of video memory to provide that simplicity...and
that is, in fact, where "Mode X" fits into the picture...if you switch
off the "chain" bit of the VGA, it switches off the circuitry that
hides all the "8 bitplane display controlled with only 4 bitplane"
stuff and exposes the _true horror_ of what video mode 13h actually
looks like "under the hood"...it's not a pretty sight...although, in
doing this, you get the full 256KB that every VGA has to play with
(and can therefore have more than one "page" with a 320x200x256 screen
:))...this, though, turned out to be a "happy accident" because mode
13h became really easy to program for (one byte per pixel laid out
"flat" :)...

And then, of course, that a minor revolution appeared - DOOM - which
made all game graphics go 3D forever more...and, simply, bitplanes
would be a complete nightmare to use for that...well, once you got the
idea of what I've just explained about video mode 12h, you can see the
difficulty that trying to draw 3D texture mapping with it would
cause...just drawing pixels is complicated (and slow)
enough...although, as my example demonstrates, there were some nifty
"special effects" that planar modes could do that have been mostly
"lost" thanks to linear modes becoming the "norm" (though, I would, of
course, much, much prefer a linear mode and then the hassle of ORing
things together to "fake" these bitplane effects than to have to
bitplanes come back as the convention again :)...

It's a funny old world, isn't it? :)

[ In fact, I'm sure that the reason why Windows uses bitmaps for so
much (icons, cursors, etc. :) when some other OSes use vector graphics
instead (which scale and rotate and that sort of thing much better
than bitmaps do :) is probably all down to all these "planar" modes
and, specifically, video mode 12h (which, to this day, is still the
video mode that "safe mode" uses because every VGA can do it and
programming it is "standard" across all video cards :)...in terms of
design, it probably would have made more sense to use vector graphics
(especially when there's all the different icon sizes and Windows lets
you change the sizes around :)...but in terms of programming, bitmaps
made things soooo much simpler for mode 12h (and other "planar" modes
:)...and like so many things in Windows, once they made the decision,
it's not easy to go back on it and still provide that all-important
"backwards compatibility" guarantee that they hold so dear...but their
bitmap "rescaler" thing does a reasonable job these days...although,
it does make things look "fuzzy" and "blurry" that you think your eyes
are starting to go short-sighted or something...hehehe :) ]

Anyway, there should be enough detail here in this post and the other
one, for you to do all the graphics you might want to do in video
modes 12h and 13h...which are the best VGA modes that are "standard"
and sure to work on any VGA compatible card (which basically means
more or less any video card that you're likely to meet on a PC :)...if
you want to ask about VESA's VBE and for me to write some example code
then, please, give me a week or two rest first, as VBE is even more of
a nightmare to fully explain...hehehe...just kidding, just kidding
;)...

Beth :)

-----

Example code:

[ Some lines might be wrapped around on your newsreader (and, knowing
Outlook, it'll totally ruin all the neat identing I use...well, trust
me, it looked just perfect before I hit "send", anyway...hehehe
:)...they, obviously, should be stitched back together before handing
to the assembler...also, I've tried to add useful comments, which I
Hope you can understand enough to follow how the program works...plus,
I make no apologises about it not being the most optimal code in the
world but I want it to be readable first and foremost...anyway, you'd
need to find a _really_ old and slow machine for it not to run at a
reasonable speed :)

But, otherwise, assemble it and then kick back to enjoy the "hippy
vibe"...hehehe :) ]

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

; Video12.asm
;
; Demonstrates using video mode 12h to create a cool
; psychadelic special effect (don't stare too long
; or you'll probably get a headache ;)...
;
; Created by Beth :)
;
; Released to the public domain...
;
; [ Compile as .COM file...I've used TASM myself but have
; delibrately kept it simple enough (not used fancy
; macros :) that MASM should run it okay "as is" and,
; for other assemblers, it shouldn't be too difficult
; to make the necessary conversions... ]
;
.386
.model tiny

; Graphics data
;
; There are three 64x64 monochrome bitmaps hidden in
; all those numbers below...if you squint at the data,
; then you can just see the shape of the graphic (sort
; of)...the label names also give a big clue ;)...
;
; As I have to post this code, I've converted it all
; to hex and squashed things into DWORDs (takes up the
; least space :) and squeezed two bitmap rows per source
; line...though this is unfortunately not the best
; format to see how the graphics are stored, it's
; a format that takes up the least source lines...
;
; If you feel like editing the graphics (hard work
; but sort of fun ;) then convert the data into binary...
; Intel chips are little-endian, so you'll find that each
; DWORD is byte-reversed but each byte itself is the right
; way around...this is odd but that's how Intel make their
; chips and I had to store them as DWORDs or the program
; source just becomes too large...reverse it back around
; and lay the rows out properly...and, magically, you
; should be able to see the image in 0s and 1s...feel
; free to play with the bitmaps and make some of your
; own...but, word of warning, it takes ages to hand edit
; these (I cheated - using a resource compiler to change
; what I'd drawn in a paint package into a list of
; numbers and just sorted it out by hand - and _that_
; took long enough to do ;)...
;
; Also, pardon any bad drawing...but, well, I'm a
; programmer, which means it's a minor miracle I can
; even draw as badly as I do...that's why I stuck with
; simple shapes...hehehe :)
;
.data

PeaceCND dd 000000000h, 000000000h, 000000000h, 000000000h
dd 07F000000h, 0000000FEh, 0FF070000h, 00000E0FFh
dd 0FF1F0000h, 00000F8FFh, 0FF7F0000h, 00000FEFFh
dd 0FFFF0100h, 00080FFFFh, 0FFFF0300h, 000C0FFFFh
dd 0FFFF0F00h, 000F0FFFFh, 0BFFF1F00h, 000F8FFFDh
dd 01FF83F00h, 000FC1FF8h, 01FE07F00h, 000FE03F8h
dd 01F80FF00h, 000FF01F8h, 01F00FE00h, 0007F00F8h
dd 01F00FC01h, 0803F00F8h, 01F00F803h, 0C01F00F8h
dd 01F00F803h, 0C01F00F8h, 01F00F007h, 0E00F00F8h
dd 01F00F007h, 0E00F00F8h, 01F00E00Fh, 0F00700F8h
dd 01F00E00Fh, 0F00700F8h, 01F00C01Fh, 0F80300F8h
dd 01F00C01Fh, 0F80300F8h, 01F00C01Fh, 0F80300F8h
dd 01F00C01Fh, 0F80300F8h, 01F00803Fh, 0FC0100F8h
dd 01F00803Fh, 0FC0100F8h, 01F00803Fh, 0FC0100F8h
dd 01F00803Fh, 0FC0100F8h, 03F00803Fh, 0FC0100FCh
dd 07F00803Fh, 0FC0100FEh, 0FF00803Fh, 0FC0100FFh
dd 0FF01803Fh, 0FC0180FFh, 0FF03803Fh, 0FC01C0FFh
dd 0FF07803Fh, 0FC01E0FFh, 0FF0F803Fh, 0FC01F0FFh
dd 0FF1F803Fh, 0FC01F8FFh, 0FF3F803Fh, 0FC01FCFFh
dd 0FF7F803Fh, 0FC01FEFFh, 0FFFFC01Fh, 0F803FFFFh
dd 09FFFC11Fh, 0F883FFF9h, 01FFFC31Fh, 0F8C3FFF8h
dd 01FFEC71Fh, 0F8E37FF8h, 01FFCEF0Fh, 0F0F73FF8h
dd 01FF8FF0Fh, 0F0FF1FF8h, 01FF0FF07h, 0E0FF0FF8h
dd 01FE0FF07h, 0E0FF07F8h, 01FC0FF03h, 0C0FF03F8h
dd 01F80FF03h, 0C0FF01F8h, 01F00FF01h, 080FF00F8h
dd 01F00FF00h, 000FF00F8h, 01F80FF00h, 000FF01F8h
dd 01FE07F00h, 000FE07F8h, 01FF83F00h, 000FC1FF8h
dd 0BFFF1F00h, 000F8FFFDh, 0FFFF0F00h, 000F0FFFFh
dd 0FFFF0300h, 000C0FFFFh, 0FFFF0100h, 00080FFFFh
dd 0FF7F0000h, 00000FEFFh, 0FF1F0000h, 00000F8FFh
dd 0FF070000h, 00000E0FFh, 07F000000h, 0000000FEh
dd 000000000h, 000000000h, 000000000h, 000000000h

LoveHeart dd 000000000h, 000000000h, 000FE0000h, 000C03F00h
dd 080FF0300h, 000F0FF00h, 0E0FF0F00h, 000FCFF03h
dd 0F0FF1F00h, 000FEFF07h, 0F8FF3F00h, 000FFFF0Fh
dd 0FCFF7F00h, 080FFFF1Fh, 0FEFFFF00h, 080FFFF3Fh
dd 0FFFFFF01h, 0C0FFFF7Fh, 0FFFFFF01h, 0C0FFFFFFh
dd 0FFFFFF03h, 0E0FFFFFFh, 0FFFFFF03h, 0E0FFFFFFh
dd 0FFFFFF03h, 0E0FFFFFFh, 0FFFFFF07h, 0F0FFFFFFh
dd 0FFFFFF07h, 0F0FFFFFFh, 0FFFFFF07h, 0F0FFFFFFh
dd 0FFFFFF07h, 0F0FFFFFFh, 0FFFFFF07h, 0F0FFFFFFh
dd 0FFFFFF07h, 0F0FFFFFFh, 0FFFFFF07h, 0F0FFFFFFh
dd 0FFFFFF07h, 0F0FFFFFFh, 0FFFFFF07h, 0F0FFFFFFh
dd 0FFFFFF03h, 0E0FFFFFFh, 0FFFFFF03h, 0E0FFFFFFh
dd 0FFFFFF03h, 0E0FFFFFFh, 0FFFFFF01h, 0C0FFFFFFh
dd 0FFFFFF01h, 0C0FFFFFFh, 0FFFFFF00h, 080FFFFFFh
dd 0FFFFFF00h, 080FFFFFFh, 0FFFF7F00h, 000FFFFFFh
dd 0FFFF3F00h, 000FEFFFFh, 0FFFF1F00h, 000FCFFFFh
dd 0FFFF0F00h, 000F8FFFFh, 0FFFF0700h, 000F0FFFFh
dd 0FFFF0300h, 000E0FFFFh, 0FFFF0000h, 00080FFFFh
dd 0FF7F0000h, 00000FFFFh, 0FF3F0000h, 00000FEFFh
dd 0FF1F0000h, 00000FCFFh, 0FF0F0000h, 00000F8FFh
dd 0FF070000h, 00000F0FFh, 0FF030000h, 00000E0FFh
dd 0FF010000h, 00000C0FFh, 0FF010000h, 00000C0FFh
dd 0FF000000h, 0000080FFh, 0FF000000h, 0000080FFh
dd 07F000000h, 0000000FFh, 07F000000h, 0000000FFh
dd 03F000000h, 0000000FEh, 03F000000h, 0000000FEh
dd 01F000000h, 0000000FCh, 01F000000h, 0000000FCh
dd 00F000000h, 0000000F8h, 00F000000h, 0000000F8h
dd 007000000h, 0000000F0h, 007000000h, 0000000F0h
dd 003000000h, 0000000E0h, 003000000h, 0000000E0h
dd 001000000h, 0000000C0h, 001000000h, 0000000C0h
dd 000000000h, 000000080h, 000000000h, 000000080h
dd 000000000h, 000000000h, 000000000h, 000000000h

HappyFace dd 000000000h, 000000000h, 000000000h, 000000000h
dd 03F000000h, 0000000FCh, 0FF030000h, 00000C0FFh
dd 0FF1F0000h, 00000F8FFh, 0FF7F0000h, 00000FEFFh
dd 0FFFF0100h, 00080FFFFh, 0FFFF0300h, 000C0FFFFh
dd 0FFFF0700h, 000E0FFFFh, 03FFE1F00h, 000F87FFCh
dd 0DFFD3F00h, 000FCBFFBh, 0EFFB7F00h, 000FEDFF7h
dd 0EFFB7F00h, 000FEDFF7h, 0F7F7FF00h, 000FFEFEFh
dd 0F7F7FF01h, 080FFEFEFh, 0F7F7FF03h, 0C0FFEFEFh
dd 0F7F7FF03h, 0C0FFEFEFh, 0FBEFFF07h, 0E0FFF7DFh
dd 0FBEFFF07h, 0E0FFF7DFh, 03BECFF0Fh, 0F0FF37DCh
dd 00BF0FF0Fh, 0F0FF0FD0h, 007E0FF0Fh, 0F0FF07E0h
dd 007E0FF1Fh, 0F8FF07E0h, 003E0FF1Fh, 0F8FF07C0h
dd 003E0FF1Fh, 0F8FF07C0h, 003E0FF1Fh, 0F8FF07C0h
dd 003E0FF3Fh, 0FCFF04C0h, 003E0FF3Fh, 0FCFF07C0h
dd 003E0FF3Fh, 0FCFF07C0h, 003E0FF3Fh, 0FCFF07C0h
dd 0C3E0FF3Fh, 0FCFF07C3h, 067F1FF3Fh, 0FCFF8FE5h
dd 0E7F1FF3Fh, 0FCFF8FE7h, 0E7F1FF3Fh, 0FCFF8FE7h
dd 0C7F0FF3Fh, 0FCFF0FE3h, 00FF8FF3Fh, 0FCFF1FF0h
dd 00FF8FB3Fh, 0FCDF1FF0h, 01FFCFB3Fh, 0FCDF3FF8h
dd 03FFE771Fh, 0F8EE7FFCh, 0FFFF8F1Fh, 0F8F1FFFFh
dd 0FFFFEF1Fh, 0F8F7FFFFh, 0FFFFEF1Fh, 0F8F7FFFFh
dd 0FFFFF70Fh, 0F0EFFFFFh, 0FFFFF30Fh, 0F0CFFFFFh
dd 0FFFFF90Fh, 0F09FFFFFh, 0FFFFF807h, 0E01FFFFFh
dd 0FF3FFC07h, 0E03FFCFFh, 0FF0FFE03h, 0C07FF0FFh
dd 0FF03FF03h, 0C0FFC0FFh, 07F80FF01h, 080FF01FEh
dd 000C0FF00h, 000FF0300h, 000F07F00h, 000FE0F00h
dd 000F87F00h, 000FE1F00h, 000FF3F00h, 000FCFF00h
dd 0E0FF1F00h, 000F8FF07h, 0FFFF0700h, 000E0FFFFh
dd 0FFFF0300h, 000C0FFFFh, 0FFFF0100h, 00080FFFFh
dd 0FF7F0000h, 00000FEFFh, 0FF1F0000h, 00000F8FFh
dd 0FF030000h, 00000C0FFh, 03F000000h, 0000000FCh
dd 000000000h, 000000000h, 000000000h, 000000000h

.data?

Frames dw ? ; Frame counter

Workspace dd 256 dup (?) ; Workspace for scrolling bitmaps in

; Each pointer points to one of the bitmaps in the data...
; one for each bitplane...I did it like this so that I
; could swap the bitmaps around to add some variety...
;
Pointer1 dw ?
Pointer2 dw ?
Pointer3 dw ?
Pointer4 dw ?

; Scrolling counters (one per bitplane)...
;
Scroll1 dw ?
Scroll2 dw ?
Scroll3 dw ?
Scroll4 dw ?

.code

org 100h

; Set video mode 12h (640x480 bitplane mode in 16 colours
:)
;
_start: mov ax, 0012h
int 10h

; Set ES to the start of the video memory
;
mov ax, 0A000h
mov es, ax

; Set up intial values for variables
;
mov Frames, 0000h
mov Pointer1, offset HappyFace
mov Pointer2, offset PeaceCND
mov Pointer3, offset LoveHeart
mov Pointer4, offset LoveHeart

; Bitplane #0:
;
NextFrame: mov bx, Scroll1
inc bx ; Increment scroll counter...
and bx, 003Fh ; Keep it in the 0-63 range...
mov Scroll1, bx

; Copy bitmap at Pointer1 to workspace...
; (bx - set above - specifies amount of scroll)
;
mov si, Pointer1
call CopyBitmap

; Set write bitplane to bitplane #0
; then tile workspace to cover screen...
;
mov dx, 03C4h
mov ax, 0102h
out dx, ax
call TileBitmap

; Bitplane #1:
;
mov bx, Scroll2
add bx, 3 ; Increment scroll counter by 3...
and bx, 003Fh ; Keep it in the 0-63 range...
mov Scroll2, bx

; Copy bitmap at Pointer2 to workspace...
; (bx - set above - specifies amount of scroll)
;
mov si, Pointer2
call CopyBitmap

; Set write bitplane to bitplane #1
; then tile workspace to cover screen...
;
mov dx, 03C4h
mov ax, 0202h
out dx, ax
call TileBitmap

; Bitplane #2:
;
mov bx, Scroll3
add bx, 2 ; Increment scroll counter by 2...
and bx, 003Fh ; Keep it in the 0-63 range...
mov Scroll3, bx

; Copy bitmap at Pointer3 to workspace...
; (bx - set above - specifies amount of scroll)
;
mov si, Pointer3
call CopyBitmap

; Set write bitplane to bitplane #2
; then tile workspace to cover screen...
;
mov dx, 03C4h
mov ax, 0402h
out dx, ax
call TileBitmap

; Bitplane #3:
;
mov bx, Scroll4
dec bx ; Decrement scroll counter...
and bx, 003Fh ; Keep it in the 0-63 range...
mov Scroll4, bx

; Copy bitmap at Pointer4 to workspace...
; (bx - set above - specifies amount of scroll)
;
mov si, Pointer4
call CopyBitmap

; Set write bitplane to bitplane #3
; then tile workspace to cover screen...
;
mov dx, 03C4h
mov ax, 0802h
out dx, ax
call TileBitmap

; Synchronise with the vertical blank
; (avoids "tear" and slows program down to
; run smoothly at the monitor's refresh
; rate :)...
;
mov dx, 03DAh
Wait4NotVB: in al, dx
test al, 8
je Wait4NotVB

Wait4VBlnk: in al, dx
test al, 8
jne Wait4VBlnk

; Frame completed, add one to counter...
;
inc Frames

; Have we drawn 256 (0100h) frames yet?
;
cmp Frames, 0100h
jne CarryOn

; Yes, we have...time to swap the bitmaps
; around to add some variety to the
; animation and stop it getting boring :)...
;
mov Frames, 0
mov ax, Pointer1
mov bx, Pointer2
mov cx, Pointer3
mov dx, Pointer4
mov Pointer1, bx
mov Pointer2, cx
mov Pointer3, dx
mov Pointer4, ax

; Check for key press (exits program :)
;
CarryOn: mov ah, 01h
int 16h
jz NextFrame

; Restore display by changing to video mode 3...
; (cheap and nasty way but it works :)
;
mov ax, 0003h
int 10h

; Terminate program...
;
mov ah, 4Ch
int 21h

; *** Subroutines ***

; CopyBitmap:
;
; Copies bitmap into workspace, scrolled by
; displacement in bx...wrapping the bitmap around
; the workspace so that it tiles properly...
;
; si = offset to 64x64 monochrome bitmap
; bx = scroll displacement (0-63)
;
CopyBitmap proc

; Set di to start of workspace area
;
mov di, offset Workspace

and bx, 003Fh ; make sure it's in range 0-63
shl bx, 3 ; multiple by 8 to get offset into
workspace
and bx, 01FFh ; wrap around to top if we go off
the bottom

mov cx, 256 ; count of DWORDs to copy
NextDWord: mov eax, [si + bx] ; Grab DWORD from bitmap data
mov [di], eax ; Put into workspace

; Increment data pointers (making sure to wrap around
; the workspace pointer if we go off the bottom)...
;
add bx, 4
and bx, 01FFh
add di, 4

; Finished copying whole bitmap?
; If not, loop back to NextDWord...
;
dec cx
cmp cx, 0
jne NextDWord

ret
CopyBitmap endp

; TileBitmap:
;
; Simply tiles the workspace bitmap to
; cover the screen...it doesn't touch
; the write bitplane register so it'll
; write to whatever plane is active
; when the proc is called :)
;
TileBitmap proc

mov dx, 7 ; Number of rows (7 * 64 = 448
pixels)
xor di, di ; Set DI to start of video segment

NextRow: mov cx, 64 ; Each bitmap is 64 pixels high
mov si, offset Workspace

NextLine: mov eax, [si] ; Grab DWORD from workspace (left
side)

; Write the DWORD (left-side) across the screen...
;
mov es:[di], eax
mov es:[di+8], eax
mov es:[di+16], eax
mov es:[di+24], eax
mov es:[di+32], eax
mov es:[di+40], eax
mov es:[di+48], eax
mov es:[di+56], eax
mov es:[di+64], eax
mov es:[di+72], eax

; Increment both pointers...
;
add si, 4
add di, 4

mov eax, [si] ; Grab DWORD from workspace (right
side)

; Write the DWORD (right-side) across the screen...
;
mov es:[di], eax
mov es:[di+8], eax
mov es:[di+16], eax
mov es:[di+24], eax
mov es:[di+32], eax
mov es:[di+40], eax
mov es:[di+48], eax
mov es:[di+56], eax
mov es:[di+64], eax
mov es:[di+72], eax

; Increment pointers...
;
; (76 bytes gets DI onto the next row of the screen, as
there's
; 80 bytes per scanline...640 / 8 = 80 :)
;
add si, 4
add di, 76

; Finished every line of bitmap?
; If not, loop back to NextLine...
;
dec cx
cmp cx, 0
jne NextLine

; Finished drawing every row of bitmaps?
; If not, loop back to NextRow...
;
dec dx
cmp dx, 0
jne NextRow

ret
TileBitmap endp

end _start


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

Thomas L. Christensen

unread,
Mar 13, 2003, 2:23:38 PM3/13/03
to
On Wed, 12 Mar 2003 05:55:43 -0000, "Beth"
<BethS...@hotmail.NOSPICEDHAM.com> wrote:

[snip]

>Video mode 12h, as others have mentioned, is a "planar" mode which
>makes things a bit complicated...

Thank you very much for your answer. I am still here, but I don't
have time to play with programming before the weekend. I expect to
look at your example then, but maybe I will drop mode 12h until I am a
bit more experienced. I am only a hobby programmer, and I was just
currious to see if I could make a quick hack to the examples in the
book. I have played with mode 13h in C, and I hate it because the
pixels are big as tennis balls, but it's maybe the best place to
start, Just learning assembly is difficult enough, so I don't really
need to make things more complicated. I have printed out your "mode
13h tutorial" and will also look at that in the weekend.

Thank you again for your answer, and also to all the other who have
helped. I'll be back... ;-)

laura fairhead

unread,
Mar 13, 2003, 5:16:58 PM3/13/03
to
On Wed, 12 Mar 2003 05:55:43 -0000, "Beth" <BethS...@hotmail.NOSPICEDHAM.com>
wrote:

>


>----------- 8< -----------
>
>; Video12.asm
>;
>; Demonstrates using video mode 12h to create a cool
>; psychadelic special effect (don't stare too long
>; or you'll probably get a headache ;)...
>;
>; Created by Beth :)
>;
>; Released to the public domain...
>;
>; [ Compile as .COM file...I've used TASM myself but have
>; delibrately kept it simple enough (not used fancy
>; macros :) that MASM should run it okay "as is" and,
>; for other assemblers, it shouldn't be too difficult
>; to make the necessary conversions... ]
>;

[]

Beautiful :-))

Great work Beth !


bestwishes
laura


--
alt.fan.madonna |news, interviews, discussion, writings
|chat, exchange merchandise, meet fans....
|Get into the groove baby you've got to... check us out!

Frank Kotler

unread,
Mar 13, 2003, 10:31:41 PM3/13/03
to
Beth wrote:
> ...which - knowing Frank - he'll have hours of fun
> converting to NASM and making it draw funny shapes...hehehe ;) ]

Only a few minutes to convert to Nasm - changing "es:[..." to "[es:..."
and putting "[]"s around the memory references, mostly. You write nice
"bare-to-the-wire" code that's easy to "translate". Hours watching it.
That's a really nice effect. A friend of mine just walked by and said,
"Hey, that'd be good with a bottle of cough syrup."

Ummm, later,
Frank

Beth

unread,
Mar 14, 2003, 4:26:35 AM3/14/03
to
Thomas L. Christensen wrote:
> Thank you very much for your answer.

You're welcome...it was quite fun to write, actually...I haven't
programmed for mode 12h in a while so didn't hurt to refresh my memory
making the example...

> I am still here, but I don't
> have time to play with programming before the weekend.

Oh, well...no hurry at all...I'm not running a stopwatch on you or
anything...hehehe ;)

> I expect to look at your example then, but maybe I will drop mode
> 12h until I am a bit more experienced.

Hmmm...mode 12h isn't a walk in the park, it's true...but that could
be seen as an advantage or a disadvantage, depending on your
inclination...the complexity is more, really, about the graphics side
of things than the technical programming side of things (changing the
bitplane is but one 16-bit port I/O write :)...it's easy enough to
select a bitplane and just write some bytes into memory (only that
port I/O write extra code from using mode 13h :)...the difficulty
comes wrapping your head around writing efficient algorithms, if you
want them to be as speedy as possible...

So, you could either look on it as "too complicated and it's an
obselete video mode and no-one uses planar modes anymore" or you could
look at it as "well, if I can master this video mode and be able to
write optimal routines for it, then there's nothing that any other
video mode (ModeX excluded, perhaps ;) can throw at me that'll be
anywhere near this awkward"...how serious you are about your hobby and
whether you think bothering to learn it would actually come in handy
is what'll tell you when and how much effort to devote to any in-depth
study of it :)...

> I am only a hobby programmer, and I was just
> currious to see if I could make a quick hack to the examples in the
> book.

It might be possible to do a "relatively quick hack", perhaps, but it
really depends on what the algorithm is...for instance, if the example
in the book doesn't use any colour (simple monochrome graphics :) then
you could just set it to write to all the bitplanes and write a simple
"PutPixel" which you call instead of the BIOS...and you don't mind
that it's not perhaps totally optimal (to be optimal, you'd try not to
plot each pixel individually and would "combine" together any pixel
writes that happen to land inside the same byte so that you only have
to write that byte once...this, though, isn't so bad if it's not
totally perfect because the worst case would be 8 writes instead of
one and you're going to save sooo much time doing direct writes rather
than the BIOS call, it'll still be pretty speedy...after all, my
example program re-writes a 640x448 area completely every frame and it
would take a very old and slow machine for it not to happily manage
that at the typical 60Hz refresh rate...the slowness of the BIOS call
is mostly all wrapped up in all the overhead of making an interrupt
call...coupled with the fact that the whole video BIOS can only be
32KB in size - which has to fit in fonts, tables and _all_ those BIOS
routines - so BIOSes tend to prefer to use small, generalised but
probably slow routines so that they can actually fit everything into
that 32KB, rather than have specialised and optimised "PutPixel"
routines specifically for each video mode :)...that would be
relatively easy to "hack" (heavily stress on "relatively" ;)...but if
colours are used then we have to include things to deal with switching
bitplanes and, yes, then it'll start to move beyond just being a
simple "quick hack" to get it to work (but it might still be an
interesting thing to try...is there somewhere I could get a look at
the source code for these examples easily, as I don't have the book
myself?)...

> I have played with mode 13h in C, and I hate it because the
> pixels are big as tennis balls, but it's maybe the best place to
> start,

Hehehe...yes, I agree...pixels as big as tennis balls...although, of
course, that's the reason why it's actually quite simple...bigger
pixels means smaller resolution means it can all fit happily into the
64KB "window" at A000...having 256 colours can compensate a little bit
(anti-aliasing...if you convert a photographic image down to
320x200x256 and then show it in mode 13h, it's actually not so
bad...smooth gradients of colour can partially "hide" those
tennis-ball-sized pixels a little bit because it's harder to see where
one pixel stops and the next one starts ;)...

Against the grain, perhaps, when SVGA first showed up offering better
resolutions than VGA, I was actually more interested in a video mode
with plenty of colours rather than plenty of pixels...more pixels just
slows things down for smooth animations, but more colours gives a
better ability to effectively "hide" the resolution, especially if the
graphics are fully anti-aliased...the point now, though, is completely
moot because modern SVGA cards do both a lot of colours _and_ a lot of
pixels on machines that are at least a hundred times faster...

So it's now a case of "who cares?"...but, at first, they tended to,
argueably, be going in the "wrong" direction...anyone who's looked at
the difference in quality between a high-resolution Commodore 64
screenshot, an Atari ST screenshot and then an Amiga screenshot will
be staggered to find out that the usual resolution used for games and
demos for those machines were all the same (320x200...pixels as big as
tennis balls ;)...it was the number of colours you could display at
that resolution that made the great difference between them...the
emphasis towards greater resolution did show through too because there
were many games that were struggling to make low rates like
12fps...which, in my opinion, is a big mistake...for graphics that
animate (i.e. games :), the speed is the top priority then the colours
then the resolution...smooth animation can (partially) make up for bad
graphics...more colours can (partially) make up for bad
resolution...hence why I would say that these are the
priorities...but, thankfully, this stuff is really now mostly a thing
of the past because modern machines can handle high resolutions in 16
or 24 bit colour at 60fps...so the old compromises tend not to be
needed anymore...you can now have your cake and eat it...yummy! ;)

> Just learning assembly is difficult enough, so I don't really
> need to make things more complicated.

Yes; It's best if you try to tackle one thing at a time...although, of
course, there's a limit to how easily you can do this sometimes
because everything is inter-related (especially at the ASM level
:)...so, for example, you can't really learn about ASM without having
to learn at least a little bit about making DOS / Windows API calls
and that sort of thing...so I do appreciate that it's easier said than
done to suggest "learn one thing at a time"...that's why I suggested
mode 13h first, actually...no other reason than it makes the
programming side very easy that you can concentrate a little more on
graphics algorithms and the ASM needed...if you can get comfortable at
that, then it's easier to approach mode 12h because then the "new
thing" to learn is just the weird "bitplane" layout stuff...

> I have printed out your "mode
> 13h tutorial" and will also look at that in the weekend.

Cool; Hope it's actually useful to you...

> Thank you again for your answer, and also to all the other who have
> helped. I'll be back... ;-)

Oh dear...when Arnie said "I'll be back" in his films, it usually
wasn't a good sign...it normally meant he'd come back with a big
machine gun to shoot everyone...hehehe ;)

Beth :)


Beth

unread,
Mar 14, 2003, 4:30:57 AM3/14/03
to
laura fairhead wrote:
> Beautiful :-))
>
> Great work Beth !

Actually, I've just spotted a "bug" of sorts...the "happy face" has a
pixel missing slightly to the right of his eyes...that wasn't
intentional or in the original image, so I must have hit the wrong key
while editing the data into a more compact form...oops! ;)

Beth :)


Beth

unread,
Mar 14, 2003, 11:56:09 AM3/14/03
to
Frank Kotler wrote:
> Beth wrote:
> > ...which - knowing Frank - he'll have hours of fun
> > converting to NASM and making it draw funny shapes...hehehe ;) ]
>
> Only a few minutes to convert to Nasm - changing "es:[..." to
"[es:..."
> and putting "[]"s around the memory references, mostly. You write
nice
> "bare-to-the-wire" code that's easy to "translate".

Well, I write that sort of code when I'm going to post it up
here...because there's such a variety of assemblers and everyone's got
a different one that there's no real choice but to write it that way
or I may lose half the "target audience"...other times, I'm actually a
"struc" and macro freak of the first order...luckily, though, I began
programming life as an out and out "hacker" and then learnt the merits
of more structured programming as I went on...which means that I'm
pretty comfortable doing either, as necessary...

By the way, has anyone tried compiling it with MASM? I named the entry
point "_start" because that's the name MASM seems to prefer and (I
think)didn't use anything MASM doesn't like...but I never actually
tested whether MASM will swallow it "as is" without complaints (making
sure it uses the 16-bit linker rather than the 32-bit linker just for
a one-off test - when anything else I normally assemble with MASM
would be 32-bit - just seemed too much hassle at the time :)...

> Hours watching it.
> That's a really nice effect. A friend of mine just walked by and
said,
> "Hey, that'd be good with a bottle of cough syrup."

Of course, the effect is meant purely for educational purposes, as it
makes it possible to actually _see_ the "bitplanes" in action...and
demonstrates a bit more clearly what I meant by "sheets of actate on
top of each other"...the fact that it's quite a psychedelic effect
which looks rather cool and might go down well with a "bottle of cough
syrup" is merely a "bonus" to its "educational" purposes...hehehe :)

Beth :)


Ross Simpson

unread,
Mar 14, 2003, 1:26:15 AM3/14/03
to
"Frank Kotler" <fbko...@attbi.com> wrote in message...

Frank,

Would you be so good as to posting that. I've tried rewriting it based on
those comments & 'am still getting lots of errors in NASM! :-(

If not then perhaps Beth can rewrite it so that TASM 1.0 supports it. Well,
not so that it has to be 8086/8088/80286 based, but just so it's compilable!
:-)

Ross.

Aaron.O.D...@spamgourmet.com

unread,
Mar 14, 2003, 2:08:19 PM3/14/03
to
In article <EWnca.349$KB1.1...@newsfep1-win.server.ntli.net>
BethS...@hotmail.com "Beth" writes:
[..]

> By the way, has anyone tried compiling it with MASM? I named the entry
> point "_start" because that's the name MASM seems to prefer and (I
> think)didn't use anything MASM doesn't like...but I never actually
> tested whether MASM will swallow it "as is" without complaints (making
> sure it uses the 16-bit linker rather than the 32-bit linker just for
> a one-off test - when anything else I normally assemble with MASM
> would be 32-bit - just seemed too much hassle at the time :)...

I had a small issue compiling it with tasm and using a 16-bit
linker -- compiled and linked fine, but didn't run :( Solved by
swapping the order of the .model and .386 lines around making the
default segments 16-bit.

Nice one :)

Pete
--
"We have not inherited the earth from our ancestors,
we have borrowed it from our descendants."

Thomas L. Christensen

unread,
Mar 15, 2003, 12:05:44 AM3/15/03
to
[snip]

>simple "quick hack" to get it to work (but it might still be an
>interesting thing to try...is there somewhere I could get a look at
>the source code for these examples easily, as I don't have the book
>myself?)...

In my original message -
(fa5b02f8.03030...@posting.google.com)
- I link to the two examples from the book I tried to 'mix'. You can
find them here: http://hjem.get2net.dk/lindblad/temp, But, if you look
at the code in the original message, you will see I hoped it was *very
simple*, basically like mode 13h. I don't think it is worth to play
further with the examples from the book.


[...]


>> Thank you again for your answer, and also to all the other who have
>> helped. I'll be back... ;-)
>
>Oh dear...when Arnie said "I'll be back" in his films, it usually
>wasn't a good sign...it normally meant he'd come back with a big
>machine gun to shoot everyone...hehehe ;)

I promise I won't. I'm a lover, not a fighter... *LOL*

Frank Buss

unread,
Mar 15, 2003, 10:27:46 PM3/15/03
to
"Beth" <BethS...@hotmail.NOSPICEDHAM.com> wrote:

> and I've also included some source code
> at the end which turns all the "theory" of both posts into something
> you can actually see...

You've done a nice effect, but I think it would be difficult for the OP
to use it for writing a simple SetPixel function, so I've written
Conway's well known Game Of Life with an interesting pattern.

The VGA register setup is something special: The enable-set-reset is
setup in a way, that all latches should be combined with the set/reset
register. And with the function select-register I specify the replace
mode. For a sequence of SetPixels then I need only one SetColor call,
which fills the set/reset register. Now a pixel is set by first setting
the bit-mask-register with (128 >> (x & 7)) to select the bit-position of
every bank. Then I do an increment on the address, which first loads the
VGA latches, combines (which is replace) it with the set/reset register
and then writes it back, without incrementing it :-)

But it would be nice to have some larger cellular automaton space. I
tried to use ECX, EDI etc., but I can't access more than 64 kB. Some
years ago I've programmed a little bit in assembler in DOS and there was
DOS4GW for protected mode applications and the like. It's not useful,
because a Win32 application and DirectX would be better, but is there
anything like DOS4GW for Windows XP *.com-programs, if I want to use the
VGA mode?

BTW: My pages and Java applets about cellular automata:
http://www.frank-buss.de/automaton/
The "Virtual" automaton is like programming in assembler :-)

The rabbits source (you can download the compiled rabbits.com at
http://www.frank-buss.de/automaton/rabbits.zip, could be optimized,
because for a CA not every pixel position need to be calculated by its
own and I'm no assembler professional, so feel free to comment my code):

; rabbits.asm
;
; The rabbits pattern
; (http://www.ericweisstein.com/encyclopedias/life/Rabbits.html)
; in Conway's Game Of Life with video mode 0x12.
;
; Created by Frank Bu_ (f...@frank-buss.de)
;
; It's public domain, use it for whatever you want.
;
; Compile it with nasm (or nasmw) like this:
; nasmw -f bin -o rabbits.com rabbits.asm
;


%define SCREEN_WIDTH 200
%define SCREEN_HEIGHT 150


section .data

PALETTE db 0x00, 0x00, 0x00
db 0xff, 0xff, 0xff


section .bss

OldVideoMode resw 1
CurrentCA resd 1
NextCA resd 1
CA resb SCREEN_WIDTH * SCREEN_HEIGHT
CA2 resb SCREEN_WIDTH * SCREEN_HEIGHT


section .text
org 100h

; switch to 640x480x16
;
call SetVideoMode
mov [OldVideoMode], ax

; set palette
;
mov cx, 6 ; number of colors * 3
mov dx, 0x3C8 ; DAC write register
mov al, 0
out dx, al
inc dx
mov si, PALETTE
cld
rep outsb ; write all colors

mov dword [CurrentCA], CA
mov dword [NextCA], CA2

; clear CA
;
mov ecx, SCREEN_WIDTH * SCREEN_HEIGHT
mov edi, CA
xor al, al
rep stosb

; init CA with rabbit pattern
;
mov esi, CA + SCREEN_HEIGHT / 2 * SCREEN_WIDTH \
+ SCREEN_WIDTH / 2;
mov byte [esi - 3], 1
mov byte [esi + 1], 1
mov byte [esi + 2], 1
mov byte [esi + 3], 1
mov byte [esi - 3 + SCREEN_WIDTH], 1
mov byte [esi - 2 + SCREEN_WIDTH], 1
mov byte [esi - 1 + SCREEN_WIDTH], 1
mov byte [esi + SCREEN_WIDTH + 2], 1
mov byte [esi + 2 * SCREEN_WIDTH - 2], 1

; loop until key pressed
;
NextFrame: call WaitVSync
mov esi, [CurrentCA]
mov edi, [NextCA]
add esi, SCREEN_WIDTH + 1
add edi, SCREEN_WIDTH + 1
mov dx, 1
NextLine: mov cx, 1
NextPixel: lodsb
call SetColor
call SetPixel

; update CA
;
xor bl, bl ; neighbour counter
add bl, [esi - SCREEN_WIDTH - 2]
add bl, [esi - SCREEN_WIDTH - 1]
add bl, [esi - SCREEN_WIDTH]
add bl, [esi - 2]
add bl, [esi]
add bl, [esi + SCREEN_WIDTH - 2]
add bl, [esi + SCREEN_WIDTH - 1]
add bl, [esi + SCREEN_WIDTH]
cmp bl, 3
jne Check2
mov al, 1
jmp CheckEnd
Check2: cmp bl, 2
je CheckEnd
xor al, al
CheckEnd: mov [edi], al
inc di

; check for next pixel
;
inc cx
cmp cx, SCREEN_WIDTH - 1
jne NextPixel

; check for next line
;
add esi, 2
add edi, 2
inc dx
cmp dx, SCREEN_HEIGHT - 1
jne NextLine

; exchange CurrentCA and NextCA for the next generation
;
mov eax, [CurrentCA]
xchg eax, [NextCA]
mov [CurrentCA], eax

; check for key press (exits program)
;
mov ah, 1
int 0x16
jz NextFrame
; eat the key
mov ah, 0
int 0x16

; restore video mode
;
mov ax, [OldVideoMode]
int 0x10

; Terminate program...
;
mov ah, 0x4c
int 0x21


; graphics subroutines ----------------------

; wait for horizontal sync
; in: -
; out: -
;
WaitVSync: push ax
push dx
mov dx, 0x3da
WaitVSync_l1: in al, dx
test al, 8
jnz WaitVSync_l1
WaitVSync_l2: in al, dx
test al, 8
jz WaitVSync_l2
pop dx
pop ax
ret

; set video mode to 640x480, return old mode in ax
; in: -
; out: ax
;
SetVideoMode: push bx
push cx
push dx

; get old video mode
;
mov ah, 0xf
int 0x10
xor ah, ah
push ax

; set new mode
;
mov ax, 0x12
int 0x10

; set special write mode
;
mov dx, 0x3ce ; graphics controller
mov ax, 0xf01 ; enable-set-reset register:
out dx, ax ; combine all 4 latches with VGA reg. 0
mov al, 3 ; function select-register: replace bits
out dx, al
mov al, 5 ; mode-Register: read mode 0, write mode 0
out dx, al
pop ax ; return value in ax: old video mode
pop dx
pop cx
pop bx
ret

; set color for subsequent set pixel calls
; in: ax: color
; out: -
;
SetColor: push eax
push edx
mov dx, 0x3ce ; graphics controller
mov ah, al ; color to ah
mov al, 0 ; set/reset register
out dx, ax
pop edx
pop eax
ret

; set pixel with current color
; in: cx: x coord, dx: y coord
; out: -
;
SetPixel: pusha

; calculate offset x / 8 + y * 80
;
lea edi, [4 * edx + edx]
lea edi, [8 * edi]
xor ebx, ebx
mov bx, cx
shr bx, 3
lea bx, [2 * edi + ebx]

; set the VGA GC bit mask-register to 128 >> (x & 7)
;
mov dx, 0x3ce ; graphics controller
and cl, 7
mov ah, 128
shr ah, cl ; calulate pixel position
mov al, 8 ; bit mask-register
out dx, ax

; load latches, combine with VGA register
; and write it back
;
mov ax, 0xa000
mov es, ax ; init graphic segment
inc byte [es:bx] ; no increment, CPU registers ignored
popa
ret


--
Frank Bu_, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Frank Kotler

unread,
Mar 16, 2003, 2:24:51 PM3/16/03
to
Frank Buss wrote:

> ; It's public domain, use it for whatever you want.

Thanks! If you don't mind, I'll use it to investigate weird phenomena
involving Nasm :)

I assembled this using a djgpp build of Nasm, ran it, and got a "illegal
operation and will be terminated with extreme predjudice" message. To
make a long story short, it seems that running any djgpp version of Nasm
- even just a "usage" message - screws up the "runtime environment" for
your program. According to "details", it seems to be this line:

CheckEnd: mov [edi], al

I can't see why this should be a problem - you've initialized edi
properly (not "assumed" that the high part was clear, or anything). The
executable - made with *any* version of Nasm - is fine (some flicker -
erratic - that I can't explain), *unless* a djgpp build of Nasm is run
first! I'll be spending some time figuring *that* out, I think!

But I wanted to point out a couple "version related" things, for the
benefit of those still using antique versions of Nasm :)

> mov esi, CA + SCREEN_HEIGHT / 2 * SCREEN_WIDTH \
> + SCREEN_WIDTH / 2;

We have here a "line continuation character" (the first feedback I've
seen that anyone is actually using it - thank you!). Not available in
0.97 or 0.98 - just unwrap the line.

jz NextFrame

And this is going to have to be "jz near NextFrame" (*just* like Beth's
program).

add esi, 2
add edi, 2

And to get the same size as new versions of Nasm will produce (414 vs
422), these will have to be "add es(d)i, byte 2". Again, 0.98.36 is
doing this by default! Not Right, although it makes sense. This is going
to break Brian Raiter's "true.asm", if no other existing program in the
known universe :)

With those changes, you get the same thing with 0.97 as with a (free,
you know) new version.

You didn't know what you started here, Beth!

Best,
Frank

Frank Buss

unread,
Mar 16, 2003, 4:00:58 PM3/16/03
to
Frank Kotler <fbko...@attbi.com> wrote:

> CheckEnd: mov [edi], al
>
> I can't see why this should be a problem - you've initialized edi
> properly (not "assumed" that the high part was clear, or anything). The
> executable - made with *any* version of Nasm - is fine

I don't have djgpp installed, but it should be easy for you to find the
bug by disassembling both files and comparing it (perhaps the COM-
headers, too).

> (some flicker - erratic - that I can't explain)

Perhaps that's because of my WaitVSync function. I've just copied it from
an older source code (only cleaning formatting) I've written many years
ago (http://groups.google.de/groups?selm=4ossao%24ffa%40esb.mbis.de), and
it flickers on my display, too. Perhaps because I have a flat-panel with
digital input.

Beth wrote it the other way around: first waiting for retrace start and
then waiting until retrace end. I've a bit experience with old C64
programming, so I wait first for retrace end (if currently in retrace)
and then for retrace start, because on C64 it was usual to change
graphics while retracing to avoid displaying something half moved. But
both ways produces flickering on my display. I think the drawing routine
is too slow to complete within retrace.

>> mov esi, CA + SCREEN_HEIGHT / 2 * SCREEN_WIDTH \
>> + SCREEN_WIDTH / 2;
>
> We have here a "line continuation character" (the first feedback I've
> seen that anyone is actually using it - thank you!). Not available in
> 0.97 or 0.98 - just unwrap the line.

It is available in version 0.98.36. I'm programming mostly in Java and
C++, so I didn't think about it, that it couldn't work :-)

--
Frank Buß, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Frank Kotler

unread,
Mar 16, 2003, 11:36:17 PM3/16/03
to
Frank Buss wrote:

> I don't have djgpp installed, but it should be easy for you to find the
> bug by disassembling both files and comparing it (perhaps the COM-
> headers, too).

I don't have much luck learning anything from a disassembly of Nasm. I
think it's something I'd have to look at sourcecode for the djgpp
runtime setup, and cwsdpmi. Running just cwsdpmi causes the same effect
- it seems not to be nasm-specific. Something in the "environment" is
different, and it brings out what seems to be a SOE (Segment Overrun
Exception - caused by something like [edi] if edi exceeds "limit" fot
the segreg involved - normally 0FFFFh) in your program. I'm going to put
it down to "unexplained weirdness", I think.

>>(some flicker - erratic - that I can't explain)

The "flicker" I referred to is just a few pixels around the border of
the screen. I can get rid of it by clearing the uninitialized buffers CA
and CA2.

In the course of my fiddling, I of course tried it in "real dos" to
eliminate whatever effects Windows might be having (after running Nasm,
your program locks up, rather than just crash the dos box - entering
Flat Real Mode in between fixes it, which is what leads me to think it's
a segment overrun exception). In real dos, it really looks like crap -
the whole screen flickers badly, and those uninitialized buffers are
full of garbage. I don't think the WaitVSync is the problem. My "diddle"
of your code leaves that alone, and it looks better in "real dos", as
well as not being affected by whatever "mess" djgpp/nasm is leaving
behind. See how it looks on your display...

>>> mov esi, CA + SCREEN_HEIGHT / 2 * SCREEN_WIDTH \
>>> + SCREEN_WIDTH / 2;
>>
>>We have here a "line continuation character" (the first feedback I've
>>seen that anyone is actually using it - thank you!). Not available in
>>0.97 or 0.98 - just unwrap the line.
>
> It is available in version 0.98.36. I'm programming mostly in Java and
> C++, so I didn't think about it, that it couldn't work :-)

Well, prior to Nasm 0.98.25, it wouldn't have worked. But it can be
useful, I guess! I'm going to use it in this "diddle" of your code that
otherwise should assemble as-is with "antique" Nasm versions - what the
hell, you'd have to unwrap it anyway!

Mostly what I did was to eliminate edi and esi, except where they were
needed to be a valid effective address (that's an interesting way to
multiply by 80!). If we use them for actual addressing, they can't
exceed 0FFFFh anyway (except in Flat Real Mode, which would allow the
thing to be extended to full screen, as well!). That got rid of the
"after-Nasm Indigestion" - and made the program smaller. With the
exception of the line continuation character, it'll assemble with 0.97,
if you like :)

Thanks for posting that, Frank - I suspect extending it to a Flat Real
Mode, full-screen version will provide still *more* entertainment! :)

Best,
Frank

;Re: [Beginner] Video mode 12h
;Frank Buss <f...@frank-buss.de>
;Sun, 16 Mar 2003 03:27:46 +0000 (UTC)
;alt.lang.asm,comp.lang.asm.x86

; BTW: My pages and Java applets about cellular automata:
; http://www.frank-buss.de/automaton/

; rabbits.asm


;
; The rabbits pattern
; (http://www.ericweisstein.com/encyclopedias/life/Rabbits.html)
; in Conway's Game Of Life with video mode 0x12.
;
; Created by Frank Bu_ (f...@frank-buss.de)
;

; "diddled" - fbk
;


; It's public domain, use it for whatever you want.

;
; Compile it with nasm (or nasmw) like this:
; nasmw -f bin -o rabbits.com rabbits.asm

%define SCREEN_WIDTH 200
%define SCREEN_HEIGHT 150


section .data

PALETTE db 0x00, 0x00, 0x00
db 0xff, 0xff, 0xff


section .bss

OldVideoMode resw 1
CurrentCA resd 1
NextCA resd 1
CA resb SCREEN_WIDTH * SCREEN_HEIGHT
CA2 resb SCREEN_WIDTH * SCREEN_HEIGHT

zzz:

section .text
org 100h

;
; clear our buffers
;
mov di, CA
mov cx, zzz
sub cx, CA
shr cx, 2
xor eax, eax
rep stosd


; switch to 640x480x16
;
call SetVideoMode
mov [OldVideoMode], ax

; set palette
;
mov cx, 6 ; number of colors * 3
mov dx, 0x3C8 ; DAC write register
mov al, 0
out dx, al
inc dx
mov si, PALETTE
cld
rep outsb ; write all colors

mov dword [CurrentCA], CA
mov dword [NextCA], CA2

; clear CA
;
mov ecx, SCREEN_WIDTH * SCREEN_HEIGHT

mov di, CA


xor al, al
rep stosb

; init CA with rabbit pattern
;

; Pre Nasm 0.98.25 users - unwrap this line and
; remove the backslash!
mov si, CA + SCREEN_HEIGHT / 2 *\


SCREEN_WIDTH + SCREEN_WIDTH / 2;

mov byte [si - 3], 1
mov byte [si + 1], 1
mov byte [si + 2], 1
mov byte [si + 3], 1
mov byte [si - 3 + SCREEN_WIDTH], 1
mov byte [si - 2 + SCREEN_WIDTH], 1
mov byte [si - 1 + SCREEN_WIDTH], 1
mov byte [si + SCREEN_WIDTH + 2], 1
mov byte [si + 2 * SCREEN_WIDTH - 2], 1

; loop until key pressed
;
NextFrame: call WaitVSync

mov si, [CurrentCA]
mov di, [NextCA]
add si, SCREEN_WIDTH + 1
add di, SCREEN_WIDTH + 1


mov dx, 1
NextLine: mov cx, 1
NextPixel: lodsb
call SetColor
call SetPixel

; update CA
;
xor bl, bl ; neighbour counter

add bl, [si - SCREEN_WIDTH - 2]
add bl, [si - SCREEN_WIDTH - 1]
add bl, [si - SCREEN_WIDTH]
add bl, [si - 2]
add bl, [si]
add bl, [si + SCREEN_WIDTH - 2]
add bl, [si + SCREEN_WIDTH - 1]
add bl, [si + SCREEN_WIDTH]


cmp bl, 3
jne Check2
mov al, 1

jmp short CheckEnd


Check2: cmp bl, 2
je CheckEnd
xor al, al

CheckEnd: mov [di], al
inc di

; check for next pixel
;
inc cx
cmp cx, SCREEN_WIDTH - 1
jne NextPixel

; check for next line
;
add si, byte 2
add di, byte 2


inc dx
cmp dx, SCREEN_HEIGHT - 1
jne NextLine

; exchange CurrentCA and NextCA for the next generation
;
mov eax, [CurrentCA]
xchg eax, [NextCA]
mov [CurrentCA], eax

; check for key press (exits program)
;
mov ah, 1
int 0x16

jz near NextFrame


; graphics subroutines ----------------------

;-------------------

Frank Buss

unread,
Mar 17, 2003, 5:37:18 PM3/17/03
to
Frank Kotler <fbko...@attbi.com> wrote:

> Frank Buss wrote:
>
>> I don't have djgpp installed, but it should be easy for you to find
>> the bug by disassembling both files and comparing it (perhaps the
>> COM- headers, too).
>
> I don't have much luck learning anything from a disassembly of Nasm. I
> think it's something I'd have to look at sourcecode for the djgpp
> runtime setup, and cwsdpmi. Running just cwsdpmi causes the same
> effect - it seems not to be nasm-specific.

Ok, I've misunderstood you, that the building result of my program was
different. Now I can see what your mean.

> The "flicker" I referred to is just a few pixels around the border of
> the screen. I can get rid of it by clearing the uninitialized buffers
> CA and CA2.

You're right. I forgot to delete the second buffer, too. I left it
untouched first, because I thought it was the target in the first pass,
but in the second pass the 1-pixel border with garbage was used for the
next CA generation.

> ;
> ; clear our buffers
> ;
> mov di, CA
> mov cx, zzz
> sub cx, CA
> shr cx, 2

I think you could do it at compile-time: mov cx, (zzz-CA)/2

But the 640x480 mode is to complicated and 16 colors are not much. So
I've written another program for 320x200. It uses 128 kB after the first
64 kB, because I've read somewhere for COM programs the rest of the
memory is reserved. I hope it runs everywhere. You can get the
precompiled program at http://www.frank-buss.de/automaton/arabeske.zip
It's 181 bytes, but zip-packed for no transfer problems, 303 bytes :-)

; arabeske.asm
;
; A Generations pattern
; (see MCell at http://www.mirwoj.opus.chelm.pl/ca/ for more patterns)
;
; Created by Frank Buss (f...@frank-buss.de)


;
; It's public domain, use it for whatever you want.
;

; Compile it with NASM (or nasmw) like this:
; nasmw -f bin -o arabeske.com arabeske.asm
;


%define SCREEN_WIDTH 320
%define SCREEN_HEIGHT 200

%define CA_WIDTH (SCREEN_WIDTH + 2)
%define CA_HEIGHT (SCREEN_HEIGHT + 2)

; try changing this, every value a slightly different effect
%define NUMBER_OF_STATES 65


section .text
org 100h



; get old video mode
;
mov ah, 0xf
int 0x10

push ax

; switch to 320x200x256, default palette is fine
;
mov ax, 0x13
int 0x10

; clear first CA
;
mov ax, ds
add ax, 0x1000
mov bx, ax
mov es, ax ; first CA starting at ds + 0x1000
push es ; save for later use
mov cx, CA_WIDTH * CA_HEIGHT / 2
xor di, di
xor ax, ax
cld
rep stosw

; clear second CA
add bx, 0x1000 ; second CA starting at ds + 0x2000
mov es, bx
mov cx, CA_WIDTH * CA_HEIGHT / 2
xor di, di
xor ax, ax
rep stosw

; init first CA with one cell in the center
;
pop ds ; get segment to first CA
inc byte [CA_HEIGHT / 2 * CA_WIDTH + CA_WIDTH / 2]

; loop until key pressed
;
mov ax, 0xa000
mov gs, ax ; g-segment for graphics area
std

; wait for horizontal sync
;
NextFrame: mov dx, 0x3da


WaitVSync_l1: in al, dx
test al, 8
jnz WaitVSync_l1
WaitVSync_l2: in al, dx
test al, 8
jz WaitVSync_l2

; show and update CA
;
mov si, CA_WIDTH * (CA_HEIGHT - 1) - 2 ; CurrentCA index
mov di, si ; NextCA index
mov bx, SCREEN_WIDTH * SCREEN_HEIGHT - 1 ; graphics index

NextLine: mov cx, SCREEN_WIDTH ; current column
NextPixel: lodsb
mov [gs:bx], al

; update CA
;
or al, al ; if 0, check if it has to birth
jz Check
inc al ; if not 0, next cell generation
jmp CheckEnd
Check: xor dl, dl ; count neighbours
add dl, [si - CA_WIDTH]
add dl, [si - CA_WIDTH + 1]
add dl, [si - CA_WIDTH + 2]
add dl, [si]
add dl, [si + 2]
add dl, [si + CA_WIDTH]
add dl, [si + CA_WIDTH + 1]
add dl, [si + CA_WIDTH + 2]
cmp dl, 1
jne CheckEnd
mov al, 1 ; birth, if exactly one new cell is around

CheckEnd: cmp al, NUMBER_OF_STATES ; test maximum age
jl SetNext
mov al, 0 ; die
SetNext: mov [es:di], al ; set new state

dec bx ; graphics index
dec di ; NextCA index

; check for next pixel
;
loop NextPixel

; check for next line
;
sub si, 2 ; previous line for CurrentCA
sub di, 2 ; previous line for NextCA

cmp bx, 0xffff
jne NextLine

; exchange first CA and next CA for the next CA generation
;
push ds
push es
pop ds
pop es

; check for key press (exits program)
;
mov ah, 1
int 0x16

jz NextFrame

; eat the key
;
mov ah, 0
int 0x16

; restore video mode
;
pop ax
xor ah, ah
int 0x10

; back to DOS


;
mov ah, 0x4c
int 0x21


--
Frank Bu_, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Frank Kotler

unread,
Mar 17, 2003, 8:52:33 PM3/17/03
to
Frank Buss wrote:

> Ok, I've misunderstood you, that the building result of my program was
> different. Now I can see what your mean.

Right - the executable is the same, but running the djgpp build of Nasm
leaves... I now suspect... the upper part of edx non-zero. I just threw
an "xor edx, edx" at the top of your file, and it seems to have fixed it.

>> ;
>> ; clear our buffers
>> ;
>> mov di, CA
>> mov cx, zzz
>> sub cx, CA
>> shr cx, 2
>
> I think you could do it at compile-time: mov cx, (zzz-CA)/2

Right you are! Duh! I *knew* as I was writing that, that it was "dumb"
but just blindly plodded along with "what do I have to do next". (the
first version was "stosb"...) Before I posted, I looked at it again,
thinking "I know I can improve that", but just didn't "see" it. Of
*course* that should be done at compile-time! The size of those buffers,
expressed as SCREEN_HEIGHT and SCREEN_WIDTH was staring me right in the
face, too. Well, that's the advantage of posting this stuff - someone
can help me find my bugs. (not really a "bug", I guess, just really
klutzy code)

> But the 640x480 mode is to complicated and 16 colors are not much.

Agreed. Pity that 640 x 480 x 256 isn't more "standardized". Even banked
mode is easier than mode 12h, I think. A Linear Frame Buffer in Flat
real mode (or unprotected 32-bit mode would be nice) is about as
sraightforward as you can get, once it's set up. Your code, with all the
extended registers, looks like it's headed in that direction.

> ; arabeske.asm

Got it! It isn't true, as Beth claims, that I've downloaded and played
with every bit of code that's ever been posted here. There are several
I've missed :)

Best,
Frank

Beth

unread,
Mar 18, 2003, 4:52:30 AM3/18/03
to
Frank Kotler wrote:
> It isn't true, as Beth claims, that I've downloaded and played
> with every bit of code that's ever been posted here. There are
several
> I've missed :)

Yes...but only because the group had been running for a while before
you subscribed to it...hehehe...just kidding, just kidding :)

No, I actually think it's good that you do that and I should probably
do it more often myself...because, in the end, you only get good at
this stuff but doing it over and over and over again...it's why I
still question your "I'm no expert" claim because you're able to
attack anyone's code posted here no matter how weirdly it's coded and
almost always point out great improvements :)

Beth :)


Frank Buss

unread,
Mar 18, 2003, 11:46:04 AM3/18/03
to
Frank Kotler <fbko...@attbi.com> wrote:

>> ; arabeske.asm
>
> Got it! It isn't true, as Beth claims, that I've downloaded and played
> with every bit of code that's ever been posted here. There are several
> I've missed :)

For everyone, who won't play with it or don't have a x86, I've set up a web
page with a screenshot:

http://www.frank-buss.de/automaton/arabeske.html

It was difficult, to make the screenshot, because Windows XP don't want to
start it in window-mode and in fullscreen mode it looks like Windows is
ignoring print-screen key, so I made the screenshot from a VMware session.
Any ideas, how to make screenshots in Windows XP DOS-mode fullscreens?

Jerry Coffin

unread,
Apr 1, 2003, 10:01:51 AM4/1/03
to
In article <b57igc$5ob$2...@newsreader2.netcologne.de>, f...@frank-buss.de
says...

[ ... ]

> It was difficult, to make the screenshot, because Windows XP don't want to
> start it in window-mode and in fullscreen mode it looks like Windows is
> ignoring print-screen key, so I made the screenshot from a VMware session.
> Any ideas, how to make screenshots in Windows XP DOS-mode fullscreens?

Let it run in full screen mode, then when it's drawn what you want to
take a shot of, press Alt-Enter. That will switch it back to a window
and freeze it. From there, you can use print-screen just like with
other windows.

This doesn't work with _everything_, but it's usually pretty usable.

--
Later,
Jerry.

The universe is a figment of its own imagination.

0 new messages