Dumb question: Whats the story with video pages. I realize that there are more than one available under most of the INT10h functions in the top of BX but I have been told that using more than one page wasn't used much. How, why?
jon
If we say that the available memory for video in character modes is 64k..
if one page (a full screen) is only 80*25*2 = 4000 bytes, that means you've got space for 16 whole screens - such that, writing to one, wouldn't interfere with the others. Though you can only actually see one at a particular time.
However in practice, it just wasn't used much. Namely it was DOS doing everything on a single screen. Linux consoles use many pages though, although without the aid of bios, but it's the same idea.
Curious, is that how this was developed?
http://video.google.com/videoplay?docid=-5885351342753379583&q=8088
Jon,
Assuming you are asking about the VGA, for the normal alpanumeric display modes the hardware supports 8 display pages. I don't know how detailed of a story you actually want here, so I'll just hit the high spots. In order to maintain compatibility with the CGA, for the VGA alpanumeric display modes the display buffer is mapped into the host address space starting at B8000h and extending to BFFFFh, for a total size of 32KB. Each character code byte is paired with an attribute byte that controls the color of the character, so each character cell requires 2 bytes of storage. With an 80x25 resolution there are 2000 character cells, requiring a total of 4000 bytes of storage. With 4096 bytes actually allotted for each display page, a total of 8 pages will fit within the display buffer. IIRC at higher resolutions, 80x43 or 80x50, only 4 display pages are supported. The VGA BIOS allows you to select the active (visible) page, or write to any page, whether visible or not. The VGA BIOS also maintains a cursor position and state for each of the pages.
AFAIK mainstream applications made little use of multiple display pages. Most applications that had a need to save and restore areas of the screen would use memory buffers. For a text mode user interface that I once developed I used display page switching, and it worked out very well. Page switching is very fast, and because the switch is synchronized with vertical retrace there is no visible tearing.
Ok, I have written directly to vid memory before but I can't see why that video paging ability couldn't be really useful, especially if each page could be in a different mode. Plus thats a bunch of memory area, even if you didn't intend to use the extra pages. Coulnd't that be managed for use as something else, temporary maybe.
jon
Hi guys, I was hoping for an opinion on this last one too..
thanks,
jon
jon
That "extra" memory can certainly be used for anything else. However, even in the old days when total available memory was only 1Mb, you would have been terribly stuck if you really needed that relatively small amount of extra memory.
Raymond
The VGA supports only one mode at a time, so all of the pages must necessarily be the same mode. I have actually used the display buffer to store the code for a memory test app where I wanted to test all of the memory in a single pass, without having to move the test app or not test the memory it occupied. The VGA supported 256KB of memory, but only 64-96 KB of it was directly accessible at any one time.
reading video memory is very slow. I estimate running code in the vga memory with current cpus will slow down execution time by factor 10-100. So this memory usability is really limited.
Gustav,
I think it would depend on whether or not the video memory was cached. I recall doing some crude access time tests where I could detect no difference between the video memory and the main memory.
On the issue of writing directly to video memory, what does this line mean:
mov CS:Screen+100h, 0B800h
.
.
.
Screen dw 0B000h
If Screen was substituted then CS:0B000h, 0B800h so what the heck kind of addressing is that?
Is it something like: mov CS:[Screen+100h], 0B800h ?
mov Byte Ptr CS:[Screen+100h], 0B800h ?
jon
Oh wait,
That snippit sets the CodeSegment effective address to 0B800h. Ah. And I meant Word Ptr not Byte Ptr.
jon
it does not affect the code segment (CS) itself. it just stores a word value (B800) in a variable located in the code segment.
does this mean that MASM doesn't require any type of focus delimiters for the operand that is being read or modified? i am used to something like the following:
mov ax, es:[bx]
dec WORD [bx+100h]
where the brackets show the operand or operand combination that is being read or modified.
jon
The MASM syntax would be:
mov ax, es:[bx]
dec WORD PTR[bx+100h]
For MASM the brackets are the "index" operator (singular), used in this context to specify an indirect memory operand. For indirect memory operands in 16-bit code the operand can specify one base register, or one index register, or one of each.
MASM, unlike NASM, FASM, GoAsm, etc, ignores the brackets for direct memory operands, so for example these two statements are equivalent:
mov bx, var1
mov bx, [var1]
Michael,
Thank you for the clarification. I wrote a little, dskpatch inspired, memroy dump program today. Don't worry, I didn't steal any code. I wrote my own. I have been working on my library of routines for quite some time and writing heavier programs is so much easier now. I used PgUp and PgDn to display 300 and some bytes of memory (hex on left, and ASCII on right - how original) starting with 0000:0000 and incrementing or decrementing on each screen. On the far left I also display the offset for each line of each page of information. I should already know this but Im getting a bit confused on my hex numbering. I can show memory from 0000 to FFFFh and then my program zeros back to 0000. No problem. How do I increment to the next byte after 0000:FFFFh. Do I allow the program to begin incrementing the "segment" value each time I hit FFFFh on the offset value? ex.
0000:FFFFh then next line would be 0001:FFFFh and so on? Im sorry for such a question but examples bring everything together for me.
jon
I think the best method would depend on the purpose of the dump. For dumping real-mode memory I can't really see any good reason to cross segment boundaries, when everything is by necessity split up into segments. The dump would be easier to code and easier to understand if the dump segment were fixed, and only the offset address varied. For protected or big-real mode, assuming a flat address space, I think the memory should be addressed by absolute address.
Ok Michael,
I agree with your opinion on functionality. Remember Im doing these projects as experiments and I guess my question is more like this: If I wanted my program to run past the absolute FFFFh, in Real-Mode, to the next byte then what would be my increment at the "add ax, ??"
xor bx, bx
mov es, bx ; start at 0000:0000
ALoop: mov ah, BYTE [es:bx] ; grab byte
call DisplayAhChar ; update display
inc bx ; inc to next byte
cmp bx, FFFFh ; check for end of seg
jbe ALoop ; < or = loop for next char
SegInc: mov ax, es ; > trans es into ax
add ax, ?? ; inc segment value
cmp ax, FFFFh ; valiid?
jg Rset ; no, reset values
Set: mov es, ax ; yes, assign new value to es
xor bx, bx ; reset offset vaule
jbe ALoop ; loop back for bytes
Rset: xor bx, bx ; reset to 0
mov es, bx ; "
jmp ALoop ; loop back
jon
Assuming you want to progress through the absolute addresses without repeating any address, you should add 1000h to the segment address when you reset the offset to zero. Perhaps I should add that to generate an absolute address the processor (effectively) shifts the segment address left by four bit positions (equivalent to one hex digit) and adds the offset address.
0000:0000 = 00000
...
0000:FFFF = 0FFFF
1000:0000 = 10000
...
1000:FFFF = 1FFFF
2000:0000 = 20000
...