123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- { example for :
- Selectors and descriptors
- DOS memory access
- allocate_ldt_descriptors()
- free_ldt_descriptors()
- get_segment_base_address()
- set_segment_base_address()
- get_segment_limit()
- set_segment_limit()
- seg_move()
- seg_fillword()
- }
- { This example demonstrates the usage of descriptors and the effects of
- changing its limit and base address.
- In more detail, the program fills the region described by an allocated
- descriptor in text screen memory with various characters.
- Before doing this it saves the entire screen contents to the heap and
- restores it afterwards.
- Some additional background:
- The text screen of a VGA card has it's address space at $B800:0; screen
- memory is organized in a linear fashion, e.g. the second line comes
- directly after the first, where each cell occupies 2 bytes of memory
- (1 byte character data, 1 byte attributes). It is 32 kb in size.
- Hence the offset of a single memory cell from its origin is:
- Y * columns * 2 + X * 2
- where X and Y mark the point and columns is the number of character cells
- per line
- }
- uses crt, { color constants, clreol(), gotoxy(), wherex(), wherey() }
- go32;
- const maxx = 80; { screen x and y dimensions }
- maxy = 25;
- bytespercell = 2; { bytes used for every character cell }
- screensize = maxx * maxy * bytespercell; { screen size in bytes }
- linB8000 = $B800 * 16; { the linear address of $B800:0 }
- type string80 = string[80];
- var
- text_save : array[0..screensize-1] of byte; { holds the old screen contents }
- text_oldx, text_oldy : Word; { old cursor x and y coordinates }
- text_sel : Word; { selector to the text mode screen }
- { prints a status message on the first line of the screen and then waits for
- a keypress }
- procedure status(s : string80);
- begin
- gotoxy(1, 1); clreol; write(s); readkey;
- end;
- { writes some descriptor info on the last 2 lines }
- procedure selinfo(sel : Word);
- begin
- gotoxy(1, 24);
- clreol; writeln('Descriptor base address : $', hexstr(get_segment_base_address(sel), 8));
- clreol; write('Descriptor limit : ', get_segment_limit(sel));
- end;
- { returns a 2 byte character cell, which includes character data and its
- color attributes }
- function makechar(ch : char; color : byte) : Word;
- begin
- result := byte(ch) or (color shl 8);
- end;
- begin
- { save original screen contents to variable, this time by using seg_move()
- and the dosmemselector variable }
- seg_move(dosmemselector, linB8000, get_ds, longint(@text_save), screensize);
- { additionally we have to save the old screen cursor coordinates }
- text_oldx := wherex; text_oldy := wherey;
- { clear the whole screen }
- seg_fillword(dosmemselector, linB8000, screensize div 2, makechar(' ', Black or (Black shl 4)));
- { output message }
- status('Creating selector ''text_sel'' to a part of text screen memory');
- { allocate descriptor }
- text_sel := allocate_ldt_descriptors(1);
- { set its base address to the linear address of the text screen + the
- byte size of one line (=maxx * bytespercell * 1) }
- set_segment_base_address(text_sel, linB8000 + bytespercell * maxx * 1);
- { the limit is set to the screensize reduced by one (a must be) and the
- number of lines we don't want to have touched (first line + lower 2 lines) }
- set_segment_limit(text_sel, screensize - 1 - bytespercell * maxx * 3);
- { write descriptor info }
- selinfo(text_sel);
- status('and clearing entire memory selected by ''text_sel'' descriptor');
- { fill the entire selected memory with single characters }
- seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2, makechar(' ', LightBlue shl 4));
- status('Notice that only the memory described by the descriptor changed, nothing else');
- status('Now reducing it''s limit and base and setting it''s described memory');
- { set the base address of the descriptor (increase it by the byte size of one line) }
- set_segment_base_address(text_sel, get_segment_base_address(text_sel) + bytespercell * maxx);
- { decrease the limit by byte size of 2 lines (1 line because base address changed,
- one line on the lower end) }
- set_segment_limit(text_sel, get_segment_limit(text_sel) - bytespercell * maxx * 2);
- { write descriptor info }
- selinfo(text_sel);
- status('Notice that the base addr increased by one line but the limit decreased by 2 lines');
- status('This should give you the hint that the limit is relative to the base');
- { fill the descriptor area }
- seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2, makechar(#176, LightMagenta or Brown shl 4));
- status('Now let''s get crazy and copy 10 lines of data from the previously saved screen');
- { copy memory from the data segment to screen }
- seg_move(get_ds, longint(@text_save), text_sel, maxx * bytespercell * 2, maxx * bytespercell * 10);
- status('At last freeing the descriptor and restoring the old screen contents..');
- status('I hope this little program may give you some hints on working with descriptors');
- { free the descriptor so that it can be used for things }
- free_ldt_descriptor(text_sel);
- { restore old state }
- seg_move(get_ds, longint(@text_save), dosmemselector, linB8000, screensize);
- gotoxy(text_oldx, text_oldy);
- end.
|