Kalashnikoff.ru - Ассемблер? Это просто!.. (Выпуск № 030) (XMS-память) Ассемблер? Это просто! Учимся программировать

______________________________________

Выпуск N 030 (XMS-память)

Здравствуйте, уважаемые подписчики!

Сегодня в номере:

Информация для новых подписчиков

Тусоffка

Отпуск

Предложения

XMS-память

Наши партнеры

Информация для новых подписчиков Благодарю Вас, что подписались на рассылку "Ассемблер? Это просто! Учимся программировать". Надеюсь, что Вы не останетесь равнодушны к ней и почерпнете море полезной информации, а также повысите свой уровень в "общении" с IBM-совместимыми компьютерами.

Прежде, чем приступать к изучению материала в данном выпуске, Вам необходимо внимательно ознакомиться с предыдущими. Я уверен, что Вы очень быстро и без труда догоните остальных подписчиков, не смотря на то, что у нас уже 30 выпуск.

Все, что нужно для изучения Ассемблера (предыдущие выпуски, необходимые программы, документацию, форму для подачи вопроса экспертам, а также многое другое), можно найти на сайте http://www.Kalashnikoff.ru. Рекомендую Вам сперва ознакомиться с разделом "Для новых подписчиков".

Для тех, кто не имеет выхода в Интернет.

К огромному сожалению, я пока не имею постоянного доступа к Интернету и почте. Поэтому высылка архива по e-mail временно приостановлена... Извините за доставленные неудобства...

Тусоffка Вот, уважаемые читатели, и прошла первая тусоffка, посвященную программированию на Ассемблере.

Что можно сказать? Если честно, то я планировал, что все это произойдет совсем по-другому. Но то, что получилось, это тоже не плохо. Я очень надеюсь, что следующая тусоffка пройдет более массово и более слажено.

Тем не менее, я благодарю всех, кто пришел! Огромное вам всем спасибо!

Т.к. я потерял все, имеющиеся у меня, электронные адреса и номера ICQ подписчиков, то хотел бы попросить написать мне тех, кто присутствовал на тусоffке. Мне нужно выслать вам кое-что... Как только я получу доступ к почте, сразу вам отвечу.

Отпуск Уважаемые читатели! В настоящий момент я нахожусь в отпуске и не имею постоянного выхода в Интернет, поэтому не могу отвечать на ваши письма. Но как только я вернусь к своим делам, то сразу сообщу об этом на сайте.

Этот выпуск я отправляю из интернет-кафе. Поэтому просьба: не пишите пока мне письма, т.к. я все равно не смогу отвечать...

________

Недавно удалось посмотреть объем своего почтового ящика и был безмерно удивлен тем, что его размер порядка 120 Мб!!! Это ж сколько писем-то пришло за месяц!!!

________

Обратите также внимание, что я не закачал на сайт файлы-приложения в архиве. К сожалению, не было возможности. Поэтому вам придется сохранить файл старым добрым способом, а именно: скопировать в буфер обмена, а затем вставить в какую-нибудь оболочку.

________

Находясь в отпуске вдалеке от Интернета, у меня появилось много свободного времени, которое я посвящаю написанию книги. За неделю дела продвинулись очень далеко. И это хорошо! Скоро будет готово!

В книге будут также приведены некоторые интересные письма подписчиков, ответы экспертов из рассылки FAQ, а также многое другое (если технический редактор не вырежет это). Если кто-либо из вас не согласен с тем, чтобы опубликовать вашу информацию в книге, то напишите мне.

________

Хотелось бы поблагодарить всех экспертов, отвечающих на вопросы подписчиков в рассылке "Ассемблер? Это просто! Учимся программировать (FAQ)". Даже не знаю, чтобы я делал без вас...

Выражаю отдельную благодарность эксперту Dron за оказанную помощь.

Предложения В прошлом выпуске я опубликовал письмо одного подписчика, который предложил попробовать написать свою собственную операционную систему. Я даже не ожидал, что эту идею поддержат такое количество читателей (порядка 48 человек)!

В настоящий момент открыта рассылка, которую ведет эксперт Dron. Уже вышло несколько номеров. Подписаться можно в приведенной ниже форме.

Рассылки Subscribe.Ru Операционная система "с нуля" на Ассемблере и С

Ассемблер? Это просто! Учимся программировать (FAQ) HTML SMS PALM windows КОИ-8 Надеюсь, что рассылка будет интересна вам!

XMS-память  

1. XMSmem.asm

; XMSMEM.ASM - программа к рассылке № 030 ; Определяем объем памяти XMS ; (С) Авторские права на файлы-приложения принадлежат подписчикам рассылки ; "Ассемблер? Это просто! Учимся программировать" ; Автор рассылки: ; Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru) ; http://www.Kalashnikoff.ru ; --- Ассемблирование (получение *.com файла) --- ;При использовании MASM 6.11 - 6.13: ;ML.EXE XMSMEM.asm /AT ;При использовании TASM: ;TASM.EXE XMSMEM.asm ;TLINK.EXE XMSMEM.obj /t/x .386 .8087 CSEG segment use16 assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG org 100h Start: mov ah,9 mov dx,offset Mess_about int 21h ;Проверим на наличие Himem.sys в памяти... mov ax,4300h int 2Fh cmp al,80h je Himem_loaded ;Если AL = 80h, то Himem.sys загружен. ;Иначе выводим сообщение о том, что Himem в памяти не обнаружен... mov ah,9 mov dx,offset Mess_nohimem int 21h ret Himem_loaded: ;Готовим XMS-память (отводим блок в XMS-памяти) call Prepare_XMS ret ;=== Готовим XMS-память === Prepare_XMS proc mov ax,4310h int 2Fh mov word ptr XMS_Addr,bx mov word ptr XMS_Addr+2,es ;Сохраним обработчик XMS-функций mov ah,88h ;Получить кол-во Кб XMS-памяти (всего) call dword ptr XMS_Addr mov dword ptr Number_dec,edx ;Сохраним кол-во Кб XMS-памяти mov dx,offset Mess_TotalMemory mov ah,9 int 21h mov ah,3 mov bh,0 int 10h ;Читаем текущую позицию курсора add dx,8 mov ah,2 int 10h ;Установим курсор на 8 позиций правее, после выведенного сообщения call Out_dec ;Выводим кол-во килобайт XMS в текущую позицию курсора mov dx,offset Mess_cursor mov ah,9 int 21h ret Prepare_XMS endp ;=== Вывод десятичного числа на экран с использованием сопроцессора === ;Здесь без комментариев... См. предыдущие выпуски... Out_dec proc finit fstcw Dat or Dat,0C00h fldcw Dat fldz fild Divider fild Number_dec fst st(7) Next_sym: fprem fistp Dat call Out_sym fld st(6) fdiv st,st(1) frndint fst st(7) fcom st(2) fstsw ax and ax,4500h cmp ax,4000h jnz Next_sym Finish_dec: ret Number_dec dq 0 Divider dw 10 Dat dw ? Out_dec endp ;=== Вывод одного символа на экран в текущую позицию курсора === Out_sym proc push dx mov ah,2 mov dl,byte ptr Dat add dl,'0' int 21h pop dx dec dx mov ah,2 mov bh,0 int 10h ret Out_sym endp Mess_about db 0Ah, 0Dh, 'XMSMEM - определяем объем XMS-памяти.',0Ah, 0Dh db 'Рассылка "Ассемблер? Это просто! Учимся программировать", Выпуск № 030',0Ah,0Dh db 'http://www.Kalashnikoff.ru. E-mail: Assembler@Kalashnikoff.ru',0Ah,0Dh,0Ah db '(C) Авторские права на файлы-приложения принадлежат всем подписчикам рассылки.',0Ah, 0Dh, 0Ah db 9,9,'=== Россия, Москва, 2001 год ===',0Ah,0Dh,'$' Mess_nohimem db 'Драйвер Himem.sys не загружен! Невозможно использовать XMS-память!!!' Mess_cursor db 0Ah, 0Dh,'$' Mess_TotalMemory db 0Ah,0Ah,0Dh,'Всего XMS-памяти (Килобайт):$' XMS_Addr dw ? CSEG ends end Start 2. XMSblock.asm

; XMSBLOCK.ASM - программа к рассылке № 030 ; (С) Авторские права на файлы-приложения принадлежат подписчикам рассылки ; "Ассемблер? Это просто! Учимся программировать" ; Автор рассылки: ; Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru) ; http://www.Kalashnikoff.ru ; --- Ассемблирование (получение *.com файла) --- ;При использовании MASM 6.11 - 6.13: ;ML.EXE XMSBLOCK.asm /AT ;При использовании TASM: ;TASM.EXE XMSBLOCK.asm ;TLINK.EXE XMSBLOCK.obj /t/x .386 .8087 CSEG segment use16 assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG org 100h Start: mov ah,9 mov dx,offset Mess_about int 21h ;Перенесем стек в PSP, т.к. будем ужимать сегмент... mov sp,0FEh ;Проверим на наличие Himem.sys в памяти... mov ax,4300h int 2Fh cmp al,80h je Himem_loaded ;Иначе выводим сообщение о том, что Himem в памяти не обнаружен... mov ah,9 mov dx,offset Mess_nohimem int 21h ret Himem_loaded: ;Готовим основную память (ужимаем и отводим два блока по 64Кб) call Prepare_memory ;Готовим XMS-память (отводим блок в XMS-памяти) call Prepare_XMS ;Читаем файл в ОСНОВНУЮ память call Open_file call Read_file call Close_file ;Выводим: ;"Прочитали файл в основную память... ;Выводим то, что находится в ОСНОВНОЙ памяти:" mov ah,9 mov dx,offset Mess_first int 21h xor ah,ah int 16h ;Выводим то, что прочитали в ОСНОВНУЮ память (в Buffer1) mov ax,Buffer1 call Out_file ;Выводим: ;"---------------------------" mov ah,9 mov dx,offset Mess_second int 21h xor ah,ah int 16h ;Переносим прочитанные байты из основной памяти в расширенную, а ;а затем обратно в основную. call Move_toXMS ;Выводим то, что пересылалось (основная --> XMS --> основная, но в другой ;сегмент (Buffer2)) mov ax,Buffer2 call Out_file ;Выводим: ;"Оба сообщения должны совпадать!!! Иначе и быть не может!!!" mov ah,9 mov dx,offset Mess_third int 21h ;Возврат из программы ret ;=== Готовим XMS-память === Prepare_XMS proc mov ax,4310h int 2Fh mov word ptr XMS_Addr,bx mov word ptr XMS_Addr+2,es ;Сохраним обработчик XMS-функций mov ah,88h ;Получить кол-во Кб XMS-памяти (всего) call dword ptr XMS_Addr mov dword ptr Number_dec,edx ;Сохраним кол-во Кб XMS-памяти mov ah,9 mov dx,1024 ;Отводим 1024Кб XMS-памяти call dword ptr XMS_Addr or ax,ax jnz XMS_OK mov ah,9 mov dx,offset XMS_Error int 21h int 20h XMS_OK: mov XMS_id,dx ;Сохраним ID отведенного блока ret Prepare_XMS endp ; --- Открываем файл --- Open_file proc mov ax,3D00h mov dx,offset File_name int 21h jnc Next_stp mov ah,9 mov dx,offset Mess_errfile int 21h int 20h Next_stp: mov Handle,ax mov bx,ax ret Open_file endp ; --- Читаем файл в основную память --- Read_file proc mov ah,3Fh mov cx,0FFFFh xor dx,dx mov ds,Buffer1 int 21h push cs pop ds mov Bytes,ax ;Сохраним кол-во прочитанных байт ret Read_file endp ; --- Закрываем файл --- Close_file proc mov bx,Handle mov ah,3Eh int 21h ret Close_file endp ; --- Выводим прочитанный файл --- Out_file proc mov cx,Bytes ;Кол-во прочитанных байт mov ds,ax ;Сегмент - в DS xor bx,bx mov ah,2 Next_byte: mov dl,[bx] int 21h inc bx loop Next_byte push cs pop ds ret Out_file endp ; === Готовим основную память === Prepare_memory proc mov bx,offset Finish shr bx,4 inc bx mov ah,4Ah int 21h ;Ужимаем размер отведенной памяти до метки Finish ; -- Отводим память mov ah,48h mov bx,4096 ; 4096 * 16 = 65536 байт int 21h jc Error_main mov Buffer1,ax ;Сохраним сегмент первого отведенного блока mov ah,48h mov bx,4096 ; 4096 * 16 = 65536 байт int 21h jc Error_main mov Buffer2,ax ;Сохраним сегмент второго отведенного блока ret Error_main: ;Ошибка? mov ah,9 mov dx,offset Error_alloc int 21h int 20h Buffer1 dw ? Buffer2 dw ? Prepare_memory endp ; === Пересылаем прочитанные данные в XMS память и обратно в основную === Move_toXMS proc ;<<< Сперва из основной в РАСШИРЕННУЮ >>> mov ax,Bytes mov word ptr XMS_str,ax ;Кол-во пересылаемых байт mov word ptr XMS_offsrc,0 ;Смещение в основной памяти mov ax,Buffer1 mov word ptr XMS_offsrc+2,ax ;Сегмент в основной памяти mov ax,XMS_id ;Идентификатор приемника (т.е. XMS-памяти) mov XMS_rec,ax mov ah,0Bh mov si,offset XMS_str call dword ptr XMS_Addr ;<<< Теперь из расширенной в ОСНОВНУЮ >>> mov ax,Bytes mov word ptr XMS_str,ax ;Кол-во пересылаемых байт mov ax,XMS_id mov XMS_src,ax mov dword ptr XMS_offsrc,0 mov XMS_rec,0 mov ax,Buffer2 mov word ptr XMS_offrec,0 mov word ptr XMS_offrec+2,ax mov ah,0Bh mov si,offset XMS_str call dword ptr XMS_Addr ret XMS_str dd 0 ;Кол-во байт для пересылки XMS_src dw 0 ;Источник XMS_offsrc dd 0 ;Смещение в блоке-источнике или адрес в основной памяти XMS_rec dw 0 ;Идентификатор приемника XMS_offrec dd 0 ;Смещение в блоке-приемнике или адрес в основной памяти Move_toXMS endp Mess_about db 0Ah, 0Dh, 'XMSBLOCK - читаем файл в XMS-память.',0Ah, 0Dh db 'Рассылка "Ассемблер? Это просто! Учимся программировать", Выпуск № 030',0Ah,0Dh db 'http://www.Kalashnikoff.ru. E-mail: Assembler@Kalashnikoff.ru',0Ah,0Dh,0Ah db '(C) Авторские права на файлы-приложения принадлежат всем подписчикам рассылки.',0Ah, 0Dh, 0Ah db 9,9,'=== Россия, Москва, 2001 год ===',0Ah,0Dh,'$' Mess_errfile db 'Ошибка: указанный в переменной File_name файл не удалось открыть!',0Ah,0Ah,0Dh,'$' Mess_nohimem db 'Драйвер Himem.sys не загружен! Невозможно использовать XMS-память!!!' Mess_cursor db 0Ah, 0Dh,'$' XMS_error db 'Ошибка распределения XMS-памяти!',0Ah, 0Dh,'$' Error_alloc db 'Ошибка распределения основной памяти!',0Ah, 0Dh,'$' XMS_Addr dd ? XMS_id dw ? Mess_first db 0Ah,0Ah,0Dh,'Прочитали файл в основную память...',0Ah,0Dh,'Выводим то, что находится в ОСНОВНОЙ памяти:',0Ah,0Ah,0Dh,'$' Mess_second db 0Ah,0Ah,0Dh,'-------------------------------------------',0Ah,0Ah,0Dh,'Теперь выводим то, что переслано из ОСНОВНОЙ в РАСШИРЕННУЮ (XMS),',0Ah,0Dh,'а затем обратно в ОСНОВНУЮ память:',0Ah,0Ah,0Dh,'$' Mess_third db 0Ah,0Ah,0Dh,'Оба сообщения должны совпадать!!! Иначе и быть не может!!!',0Ah,0Dh,0Dh,'$' Handle dw ? File_name db 'c:\autoexec.bat',0 Bytes dw 0 Number_dec dw 0 Finish equ $ CSEG ends end Start

3. XMScopy.asm

; XMSCOPY.ASM - программа к рассылке № 030 ; Копируем файл с использованием XMS ; (С) Авторские права на файлы-приложения принадлежат подписчикам рассылки ; "Ассемблер? Это просто! Учимся программировать" ; Автор рассылки: ; Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru) ; http://www.Kalashnikoff.ru ; --- Ассемблирование (получение *.com файла) --- ;При использовании MASM 6.11 - 6.13: ;ML.EXE XMSCOPY.asm /AT ;При использовании TASM: ;TASM.EXE XMSCOPY.asm ;TLINK.EXE XMSCOPY.obj /t/x .386 .8087 CSEG segment use16 assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG org 100h Start: mov ah,9 mov dx,offset Mess_about int 21h mov sp,0FEh ;Проверим на наличие Himem.sys в памяти... mov ax,4300h int 2Fh cmp al,80h je Himem_loaded mov ah,9 mov dx,offset Mess_nohimem int 21h ret Himem_loaded: call Prepare_memory call Prepare_XMS ;Копируем файл... call Copy_file ret ;=== Готовим XMS-память === Prepare_XMS proc mov ax,4310h int 2Fh mov word ptr XMS_Addr,bx mov word ptr XMS_Addr+2,es ;Сохраним обработчик XMS-функций mov ah,88h ;Получить кол-во Кб XMS-памяти (всего) call dword ptr XMS_Addr mov dword ptr Number_dec,edx ;Сохраним кол-во Кб XMS-памяти cmp edx,0FFFFh jbe Ok_XMS mov edx,0FFFFh Ok_XMS: mov ah,9 call dword ptr XMS_Addr mov XMS_id,dx ;Сохраним ID отведенного блока ret Prepare_XMS endp ; === Готовим основную память === Prepare_memory proc mov bx,offset Finish shr bx,4 inc bx mov ah,4Ah int 21h ;Ужимаем размер отведенной памяти до метки Finish ; -- Отводим память mov ah,48h mov bx,4096 ; 4096 * 16 = 65536 байт int 21h jc Error_main mov Buffer,ax ;Сохраним сегмент первого отведенного блока ret Error_main: ;Ошибка? mov ah,9 mov dx,offset Error_alloc int 21h int 20h Prepare_memory endp ; === Копирование файла === Copy_file proc call Check_file ;Выводим сообщение "Читаю файл..." mov ah,9 mov dx,offset Info1 int 21h ;--- Читаем файл в память Next_portion: xor eax,eax mov ah,3Fh mov cx,0FFFFh xor dx,dx mov bx,Handle mov ds,Buffer int 21h push cs pop ds jc Error_copy mov Bytes,eax add Total_bytes,eax call Move_to_XMS cmp Bytes,0FFFFh je Next_portion mov ah,3Eh mov bx,Handle int 21h ;--- Пишем файл ;Выводим сообщение "Пишу файл... " mov ah,9 mov dx,offset Info2 int 21h mov dword ptr XMS_offsrc,0 mov ah,3Ch xor cx,cx mov dx,offset File_new int 21h mov Handle,ax int 3 Next_portion2: call Move_from_XMS mov ecx,Total_bytes cmp ecx,0FFFFh jbe Save_bytes sub Total_bytes,0FFFFh mov ecx,0FFFFh jmp short Step2 Save_bytes: mov Total_bytes,0 Step2: mov ah,40h xor dx,dx mov bx,Handle mov ds,Buffer int 21h push cs pop ds jc Error_copy cmp Total_bytes,0 jnz Next_portion2 ret Error_copy: mov ah,9 mov dx,offset Mess_errcopy int 21h int 20h Copy_file endp ; === Пересылаем прочитанные данные в XMS память === Move_to_XMS proc mov eax,Bytes mov XMS_str,eax ;Кол-во пересылаемых байт mov XMS_src,0 mov word ptr XMS_offsrc,0 ;Смещение в основной памяти mov ax,Buffer mov word ptr XMS_offsrc+2,ax ;Сегмент в основной памяти mov ax,XMS_id ;Идентификатор приемника (т.е. XMS-памяти) mov XMS_rec,ax mov ah,0Bh mov si,offset XMS_str call dword ptr XMS_Addr mov eax,Total_bytes mov XMS_offrec,eax ret ;XMS_str dd 0 ;Кол-во байт для пересылки ;XMS_src dw 0 ;Источник ;XMS_offsrc dd 0 ;Смещение в блоке-источнике или адрес в основной памяти ;XMS_rec dw 0 ;Идентификатор приемника ;XMS_offrec dd 0 ;Смещение в блоке-приемнике или адрес в основной памяти Move_to_XMS endp ; === Пересылаем прочитанные данные из XMS памяти === Move_from_XMS proc mov dword ptr XMS_str,0FFFFh mov ax,XMS_id mov XMS_src,ax mov XMS_rec,0 mov ax,Buffer mov word ptr XMS_offrec,0 ;Смещение в основной памяти mov word ptr XMS_offrec+2,ax ;Сегмент в основной памяти mov ah,0Bh mov si,offset XMS_str call dword ptr XMS_Addr add XMS_offsrc,0FFFFh ret ;XMS_str dd 0 ;Кол-во байт для пересылки ;XMS_src dw 0 ;Источник ;XMS_offsrc dd 0 ;Смещение в блоке-источнике или адрес в основной памяти ;XMS_rec dw 0 ;Идентификатор приемника ;XMS_offrec dd 0 ;Смещение в блоке-приемнике или адрес в основной памяти Move_from_XMS endp ; --- Проверим, существует ли исходный файл и новый файл --- Check_file proc mov ax,3D00h mov dx,offset File_new int 21h jc Step1 mov ah,9 mov dx,offset Mess_exist int 21h xor ah,ah int 16h push ax mov ah,2 mov dl,al int 21h mov ah,9 mov dx,offset Mess_cursor int 21h pop ax cmp al,'y' je Step1 cmp al,'Y' je Step1 int 20h Step1: mov ax,3D00h mov dx,offset File_name int 21h jnc Step2 mov ah,9 mov dx,offset Mess_noexist int 21h int 20h Step2: mov Handle,ax mov bx,ax ret Check_file endp Mess_about db 0Ah, 0Dh, 'XMSCOPY - Копируем файл с использованием XMS.',0Ah, 0Dh db 'Рассылка "Ассемблер? Это просто! Учимся программировать", Выпуск № 030',0Ah,0Dh db 'http://www.Kalashnikoff.ru. E-mail: Assembler@Kalashnikoff.ru',0Ah,0Dh,0Ah db '(C) Авторские права на файлы-приложения принадлежат всем подписчикам рассылки.',0Ah, 0Dh, 0Ah db 9,9,'=== Россия, Москва, 2001 год ===',0Ah,0Dh,'$' Mess_nohimem db 'Драйвер Himem.sys не загружен! Невозможно использовать XMS-память!!!' Mess_cursor db 0Ah, 0Dh,'$' Error_alloc db 'Ошибка распределения основной памяти!',0Ah, 0Dh,'$' Mess_errcopy db 0Ah,0Dh,'Ошибка при копировании!',0Ah,0Dh,'$' Info1 db 0Ah,0Ah,0Dh,'Читаю файл...$' Info2 db 0Dh,'Пишу файл... $' Mess_noexist db 'Не могу открыть файл ' File_name db 'c:\file.txt',0 db '!',0Ah, 0Dh,'$' Mess_exist db 'Файл ' File_new db 'c:\filenew.txt',0 db 'уже существует! Заменить его (Y/N)?$' XMS_Addr dd ? Number_dec dd ? Buffer dw ? Bytes dd 0 Total_bytes dd 0 XMS_str dd 0 ;Кол-во байт для пересылки XMS_src dw 0 ;Источник XMS_offsrc dd 0 ;Смещение в блоке-источнике или адрес в основной памяти XMS_rec dw 0 ;Идентификатор приемника XMS_offrec dd 0 ;Смещение в блоке-приемнике или адрес в основной памяти XMS_id dw ? Handle dw ? Finish equ $ CSEG ends end Start Сегодня рассмотрим работу XMS-памяти. А именно:

Определим объем доступной XMS-памяти (XMSmem.asm);

Скопируем файл Autoexec.bat в XMS-память, а затем выведем его на экран (XMSblock.asm);

Научимся копировать файлы, используя XMS-память (XMScopy.asm).

В приложении вы видите три файла, каждый из которых выполняет свою отдельную функцию. Как обычно будем изучать от простого к сложному (XMSmem, XMSblock, XMScopy).

Прежде, чем приступать к рассмотрению материала, я хотел бы отметить следующие аспекты:

1. Для получения доступа к XMS-памяти необходимо загрузить драйвер HIMEM.SYS либо подобный ему, который откроет линию A20, а также загрузит процедуры для работы с расширенной памятью.

2. Для использования расширенной (XMS) памяти в DOS, необходимо прибегать к помощи прерываний и процедур. Иного способа не существует. Пересылка данных при помощи команд MOVS не годится. Также невозможно читать, например, файл сразу в расширенную память.

3. Работа с XMS-памятью задача нетривиальная, как может показаться на первый взгляд. Более того, отладчики типа AFD, CodeView, Turbo Debugger и т.п. не позволяют просматривать содержимое расширенной памяти. Это значит, что при возникновении каких-либо ошибок в программе, придется самому исследовать и искать ошибку (без помощи отладчика), что, безусловно, усложняет процесс отладки.

Однако, подобных трудностей не возникает у программ, которые написаны под ОС Windows. В данной операционной системе используется совсем другой принцип обращения к расширенной памяти (примерно так, как мы обращаемся к основной памяти в DOS).

Программа XMSmem.asm.

Подготовка к использованию расширенной памяти и вывод объема XMS-памяти.

Теперь можно приступать к изучению материала.

Первое, что мы сделаем, - определим объем доступной XMS-памяти, и выведем кол-во килобайт на экран при помощи известной нам уже процедуры с использованием сопроцессора (ее мы рассматривать уже не будем) (см. файл XMSmem.asm - мы пока будем его рассматривать как самый простой).

Как уже отмечалось выше, для того, чтобы использовать расширенную память, необходимо чтобы в памяти присутствовал специальный драйвер, который бы открыл доступ к ней. В DOS / Windows такой файл называется HIMEM.SYS. Если загрузить DOS без этого драйвера, то программы смогут обращаться только к основной памяти (640 Кб). Следовательно, все файлы-приложения будут работать только, если загружен указанный выше файл (или его аналог).

Первое, что нужно сделать - проверить наличие драйвера HIMEM.SYS в памяти. Это позволяет сделать функция 4300h прерывания 2Fh:

Функция 4300h прерывания 2Fh - проверка на присутствие в памяти драйвера HIMEM.SYS:

Вход: AX = 4300h Выход: AL = 80h - драйвер загружен Делаем буквально следующее (во избежание недоразумений, проверка будет осуществляться во всех трех файлах-приложениях):

...

;Проверим на наличие Himem.sys в памяти...

mov ax,4300h

int 2Fh

cmp al,80h

je Himem_loaded ;Если AL = 80h, то Himem.sys загружен.

;Иначе выводим сообщение о том, что Himem в памяти не обнаружен...

... Если драйвер присутствует, то можно попробовать отвести блок расширенной памяти. Для этого вызываем процедуру Prepare_XMS, которая подготовится к работе с расширенной памятью, а также отведет блок.

Все процедуры по управлению XMS-памятью вызываются не через прерывания (как функции DOS - INT 21h), а с использованием команды дальний CALL и указанием после нее сегмента и смещения самой процедуры. Получить точку входа (адрес) процедур по управлению XMS-памятью позволяет функция 4310h прерывания 2Fh:

Функция 4301h прерывания 2Fh - получить точку входа процедур управления XMS-памятью:

Вход: AX = 4310h Выход: ES = сегмент, BX = смещение Ниже рассмотрим это на примере.

После того, как получили точку входа, все остальные обращения к процедурам работы с XMS-памятью будут осуществляться следующим образом (естественно, предварительно подготовив регистры или массивы данных):

call dword ptr cs:XMS_Addr

Итак, получаем обработчик XMS-функций и количество килобайт расширенной памяти:

...

mov ax,4310h

int 2Fhmov word ptr XMS_Addr,bx

mov word ptr XMS_Addr+2,es ;Сохраним обработчик XMS-функций

mov ah,88h ;Получить кол-во Кб XMS-памяти

call dword ptr XMS_Addr

mov dword ptr Number_dec,edx ;Сохраним полученное число

...

Как видно из примера, функция возвращает количество килобайт (НЕ байт!) в 32-х разрядный регистр EDX.

Теперь осталось только вывести полученный результат, используя написанную нами и изученную процедуру вывода десятичного числа (Out_dec).

Обращаю ваше внимание на тот момент, что количество килобайт свободной XMS-памяти возвращает операционная система, которая берет информацию не из CMOS, а ведет учет самостоятельно. Это значит, что та информация, которую вернет функция, может не соответствовать реальной (DOS может указать не только реальный объем XMS-памяти, но и добавить к нему размер SWAP-файла Windows, либо наоборот показать меньший размер, чем есть на самом деле, вычтя из реального объема размер памяти, отведенный под кэш).

Очень надеюсь, что все понятно!

Программа XMSblock.asm.

Чтение файла в расширенную память и вывод его на экран.

Рассматривать подготовку и отведение блока расширенной памяти мы уже не будем. В данном файле все происходит аналогично вышеописанному, кроме того, что мы еще и отводим блок расширенной памяти при помощи функции 09h процедуры управления XMS-памятью. При этом DX должен содержать размер отводимой памяти в килобайтах:

...

mov ah,9

mov dx,1024 ;Отводим 1024Кб XMS-памяти

call dword ptr XMS_Addr

or ax,ax ;Ошибка?

jnz XMS_OK

...

XMS_OK:

mov XMS_id,dx ;Сохраним ID отведенного блока

... В случае, если произошла ошибка (запрашиваемый блок больше имеющегося в распоряжении и т.п.), AX не равен нулю и содержит код ошибки.

Если ошибки не произошло, то DX содержит идентификационный номер отведенного блока. В дальнейшем мы будем обращаться к отведенному блоку, используя этот номер (как при открытии файла функции 3Dh прерывания 21h выдает номер открытого файла).

______________

Итак, теперь рассмотрим работу с расширенной памятью.

Как я уже упоминал выше, загружать данный напрямую в XMS-память в DOS невозможно. Для этого используется основная память (640 Кб). Сперва загружаем данные в отведенный массив в основной памяти, затем при помощи специальной процедуры пересылаем их в расширенную. Пересылка осуществляется блоками, но не более, чем по 64Кб.

В программе XMSblock.asm мы сперва читаем файл C:\AUTOEXEC.BAT в отведенный массив в основной памяти и выводим. Затем перебрасываем прочитанные байты в расширенную память и обратно в основную, но уже по другому адресу. И снова выводим то, что перебрасывали. Идентичность выводимой информации подтверждает то, что программа не имеет ошибок.

Структура массива при работе с XMS-памятью

Для работы с XMS-памятью (пересылка данных) заведем специальный массив. Для удобства зададим каждой переменной название. В дальнейшем адрес данного массива будет загружаться в регистры DS:SI перед вызовом специальных подфункций функции управления XMS-памятью.

...

XMS_str dd 0

XMS_src dw 0

XMS_offsrc dd 0

XMS_rec dw 0

XMS_offrec dd 0

...

;Кол-во байт для пересылки

;Источник

;Смещение в блоке-источнике или адрес в основной памяти

;Идентификатор приемника

;Смещение в блоке-приемнике или адрес в основной памяти

Рассмотрим отдельно каждую переменную.

1. XMS_str (два слова) - должна содержать количество байт для пересылки из основной памяти в XMS либо наоборот.

2. XMS_src (слово) - указывает идентификатор источника. Если эта переменная равна нулю, то источником (откуда пересылаются данные) является основная память. В противном случае, переменная должна содержать идентификатор отведенного блока XMS-памяти, который получаем при отведении блока (см. выше - XMS_id).

3. XMS_offsrc (два слова) - содержит смещение в блоке-источнике (если копирование идет из расширенной памяти в основную) или сегмент:смещение в основной памяти (если копирование идет из основной памяти в расширенную).

4. XMS_rec (слово) - указывает идентификатор приемника. Если эта переменная равна нулю, то приемником (куда пересылаются данные) является основная память. В противном случае, переменная должна содержать идентификатор отведенного блока XMS-памяти, который получаем при отведении блока (см. выше - XMS_id).

5. XMS_offrec (два слова) - содержит смещение в блоке-приемнике (если копирование идет в расширенную память из основной) или сегмент:смещение в основной памяти (если копирование идет из расширенной памяти в основную).

Теоретически мы рассмотрели работу с XMS-памятью. Вам осталось лишь изучить внимательно прилагаемый файл XMSblock.asm и описания к нему.

Программа XMScopy.asm.

Копирование файла с использованием расширенной памяти.

ВНИМАНИЕ!

1. Программа корректно копирует файл, размер которого не превышает объем XMS-памяти, установленной в вашем компьютере! Т.е. Если в вашей машине стоит 16Мб ОЗУ, то максимальный размер файла, который можно скопировать с помощью этой программы, будет 16 Мб минус 640 Кб.

2. Программа копирует файл C:\FILE.TXT в C:\FILENEW.TXT.

Все эти недоработки вы сможете сами легко доделать. Я же привел простейший алгоритм копирования файла, дабы не нагружать рассылку. Впоследствии мы будем использовать подобный алгоритм в нашей оболочке.

Принцип работы программы:

Читаем файл C:\FILE.TXT в память...

Читаем 64 Кб файла в основную память;

Перебрасываем его в расширенную память;

Сдвигаем указатель, указывающий куда помещать следующую порцию данных в расширенную память;

Если не достигнут конец файла, то читаем следующий блок.

Файл целиком загружен в память. Начинаем записывать прочитанные данные в файл C:\FILENEW.TXT...

Перебрасываем 64Кб из расширенной памяти в основную;

Записываем данные в предварительно созданный файл C:\FILENEW.TXT;

Сдвигаем указатель расширенной памяти;

Перебрасываем следующий блок, если не достигнут конец данных...

Уверен, что если вы уяснили весь приведенный выше материал, то и без проблем разберетесь с этой программой. Все элементарно!

______________

А на сегодня все! Я начинаю готовить следующий выпуск. До встречи, друзья мои!

Наши партнеры 1. Рассылка Сергея Никифорова "Программирование на Visual Basic и ASP" на Subscribe.ru (код рассылки: comp.soft.prog.vbs). Название и сайт автора: Visual Basic Streets, http://www.vbstreets.ru.

2. Рассылка "Мир программирования на Visual BASIC и HTML" (http://soobcha-vb.narod.ru/alex).

С уважением,

Калашников Олег: Assembler@Kalashnikoff.ru

Мой ICQ No.: 68951340

URL сайта подписчиков: http://www.Kalashnikoff.ru

Форма для подачи вопроса: http://www.Kalashnikoff.ru/Experts/Question.html

______________

По вопросам сотрудничества, рекламы и спонсорства обращайтесь:

Публичное размещение материала из рассылки: Cooperation@Kalashnikoff.ru

Реклама на сайте, в книге и рассылках: http://www.Kalashnikoff.ru/Reklama.html, Reklama@Kalashnikoff.ru

Издание книги по материалам рассылки (спонсорство): Sponsor@Kalashnikoff.ru

(C) Москва, 2001. Авторское право принадлежит Калашникову О.А. Публичное размещение материала из рассылки, а также его использование полностью или частично в коммерческих или иных подобных целях без письменного согласия автора влечет ответственность за нарушение авторских прав. u="u496.71.spylog.com";d=document;nv=navigator;na=nv.appName;p=1; bv=Math.round(parseFloat(nv.appVersion)*100); n=(na.substring(0,2)=="Mi")?0:1;rn=Math.random();z="p="+p+"&rn="+rn;y=""; y+=""; y+=""; y+=""; d.write(y);if(!n) { d.write("

Соседние файлы в папке Выпуски