Глава 1 (продолжение 1)
Изучив вышеуказанные функции становится понятным код, с которого начинается
главная процедура main:
Вверх
;управляющая процедура ********************************************************
;Настроили ds,es на сегмент данных, очистили ax
;инициализация текущего графического режима
;очистка экрана
;ввывод собщения об авторских правах
call cursor_position
call cursor_position
Видимым на экране результатом этого кода является три сообщения:
Продолжим далее рассматривать код главной программы main.
mov al,svalue
mov ax,@data
mov ds,ax
mov es,ax
xor ax,ax
call get_screeng_mode
call clear_screeng
mov bp,offset message1
mov cx,dlmessage1
call print_string
call corretka
mov bp,offset message2
mov cx,dlmessage2
call print_string
call corretka
mov bp,offset message3
mov cx,dlmessage3
call print_string
call corretka
----------------
Cmos Editor v2.3
Programmed by Pashkov Aleksey
6.99
----------------
mov mas_svalue[0],al
call press_key
call scr_page ;процедура вывода дампа памяти
Продолжение рассмотрения кода процедуры main на странице: Далее процедура main
Рассмотрим подробнее вышепредставленный код.
Сначала помещаем в первый элемент массива mas_svalue[0] значение переменной svalue (начальный адрес для чтения из памяти):
Затем вызываем две процедуры:
call press_key
call scr_page ;процедура вывода дампа памяти
Первая процедура press_key проста, она помещает в две переменные соответственно ascii-код и scan-код клавиши:
;функция нажата ли клавиша ****************************************************
mov ah,00h
int 16h
mov ascii_code,al
mov scan_code,ah
pop ax
ret
Вызов процедуры press_key в данном месте главной процедуры main, будет означать: в зависимости от того, какую конкретно клавишу нажмет пользователь - какой именно фрагмент (один из четырех) памяти будет выведен и какое пояснение (так же одно из четырех) будет выведено.
Затем вызывается процедура scr_page вывода на эран дампа памяти.
Это для меня интересная процедура! Сначала вспомним переменные, которые
будут использоваться в процедуре:
mes_adr DW mes0, mes0D, mes10, mes20 ;адрес сообщения
mes_dl DW dl0, dl0D, dl10, dl20 ;длина сообщения
svalue DB 00h ;начальный адрес читаемой CMOS и RTS памяти
mas_svalue DB 00h,0Dh,11h,21h ;массив значений начальных адресов
mas_evalue DB 0Ch, 10h, 20h, 3Fh ;массив значений конечных адресов
evalue DB 00h ;конечный адрес читаемой CMOS и RTS памяти
page_index DW 0h ;номер видеостраницы
Key_Menu DB "F2-ЗаписьCMOS|F3-ЧтениеCMOS|F4-Редактировать|F10-EXIT "
Как видим в данных есть обычные переменные и есть массивы из четырех элементов.
Переменной page_index присваивается значение 0h, это означает, что по умолчанию
будет использоваться нулевая видеостраница для вывода.
Далее из одной процедуры будет вызываться вторая, а из нее соответственно третья:
Теперь приведем полный код процедуры scr_page (экранная страница).
Эта процедура выводит дамп памяти и комментарии к нему. Дамп памяти разбит на 4
экранных страницы. Эта процедура выводит экранную страницу номер которой указан в
переменной page_index
Вверх
;процедура вывода дампа памяти ************************************************
mov si,page_index
mov al,mas_svalue[si]
mov bx,si
pop si
push ax
call clear_screeng
push bp
;создания заголовка (Это вверху экрана)
;меню функциональныхх клавиш (Это внизу экрана)
pop cx
;вывод пояснений (вывод сообщения на экран)
;вывод адреса и содержимого
;call press_key
pop ax
Рассмотрим подробнее эту процедуру.
Вначале, после сохранения в стеке регистров, инициализируются переменные
mov si,page_index
mov al,mas_svalue[si]
Поскольку при первом вызове функции scr_page в сегменте si будет ноль, то в переменную
mas_svalue DB 00h,0Dh,11h,21h
То есть читаться будет не вся память компа, а от "сих до сих". Указан конкретный адрес
Значение переменных svalue и evalue будут использованы далее при вызове процедуры menu_byte, для побайтного вывода на экран всего содержания памяти, находящегося в пределах этих двух адресов. Будут в процедуре menu_byte выведены содержание всех ячеек и их адреса.
Далее нам надо настроить регистры bx,bp,cx для того, чтобы правильно скопировать в видеостраницу те данные, о которых мы только-что сказали.
mov bx,si
Здесь mes_adr и mes_dl так же массивы из четырех элементов.
mes_adr DW mes0, mes0D, mes10, mes20
То есть в первый вызов функции scr_page будет считан массив данных, начинающийся с метки (переменной) mes0 и будет считано столько байт данных, сколько будет содержаться в
переменной dl0, которая у нас равна $-mes0:
dl0 = $-mes0
То есть будет считано начиная с переменной, находящейся по адресу mes0, и будет считано число байт, которое содержится в переменной dl0, а это $-mes0 байт.
То есть данные будут выведены с метки mes0 и до того места, где у нас в коде (сегмент данных) стоит:
dl0 = $-mes0
Вообще этот фрагмент кода для меня довольно интересен! Именно то, как в этом фрагменте определяется та область кода (ее границы), которая будет скопирована в видеостраницу.
Теперь в CX у нас количество байт, которое необходимо скопировать.
Далее восстанавливаем ранее сохраненные регистры из стека.
Еще раз повторим для ясности этот фрагмент кода:
push ax
mov si,page_index
mov al,mas_svalue[si]
mov bx,si
pop si
Во фрагменте, который мы только-что рассмотрели, будет выведен на экран и код из памяти, который ограничен началом и концом чтения из памяти (svalue и evalue), так же будет выведен
фрагмент данных ограниченных началом и концом чтения данных (на начало указывает BP, конец будет ограничен длиной данных, содержащихся в СX).
Рассмотрим процедуру scr_page далее. Напомним еще две переменных, участвующих далее в процедуре:
zagolovok DB "Adress Value Bit Value Note"
Итак далее код процедуры scr_page:
push ax
call clear_screeng ;очистить экран
push bp
Сохраняем в стеке cx и bp чтобы в дальнейшем вывести пояснение.
;создания заголовка (Это вверху экрана)
;меню функциональныхх клавиш (Это внизу экрана)
Как видим этот код очищает экран, и создает на экране две надписи - заголовок
bp - указатель на сообщение
При этом напоминаю, что процедура print_string выводит сообщение, на которое указывает BP напрямую в видеобуфер (смотри процедуру print_screen), в указанную страницу.
При первом вызове процедуры scr_page это будет нулевая страница, как мы только что установили. Думаю, что и каждый следующий вызов процедуры print_screen будет выводить содержимое памяти компа в нулевую видеостраницу. Такова процедура print_screen.
Смотрим что происходит далее в процедуре scr_page:
pop cx
Как видим восстанавливаются cx и bp чтобы вывести пояснение.
;вывод пояснений
Здесь мы вывели в строку 02h колонки 00h содержимое, на которое указывает у нас в настоящее время BP. А указывает он у нас на фрагмент в памяти, начиная с mes0.
Вспомним:
Здесь mes_adr и mes_dl это адрес сообщения и длина сообщения. Так же массивы из четырех элементов. То есть bp указывает на сообщение,а в cx - длина сообщения.
mes_adr DW mes0, mes0D, mes10, mes20
То есть в первый вызов функции scr_page будет считан массив, начинающийся с метки (переменной) mes0 и заканчиающийся меткой $. Далее присвоим переменной dl0 некоторое значение:
dl0 = $-mes0
То есть будет считано начиная с переменной, находящейся по адресу mes0, и будет считано число байт, которое содержится в переменной dl0, а это $-mes0 байт.
Здесь произошла арифметическая операция: адрес mes0 вычли из адреса, по которому расположен
А с этого адреса у нас в памяти компа фрагмент данных, в котором содержатся пояснения:
mes0 DB " sec "
Таким образом BP у нас указывает на данные.
Теперь верхний и нижний заголовки у нас выведены, выведены пояснения. Осталось вывести
;вывод адреса и содержимого
Для этого мы позиционируем курсор в то место на экране, в которое необходимо вывести
;call press_key
Резюме:
В рассмотренном фрагменте для меня интересно еще то, что процедура scr_page заполняет экранную страницу
И так рассмотрим далее работу процедуры menu_byte. А эта процедура выводит всего лишь адрес одной ячейки и ее содержание. Да! Всего одной ячейки! Но этот код внутри функции будет повторяться столько раз, пока не будет выведено содержание и адрес всех ячеек памяти
адрес которых начинается с svalue и заканчивается адресом evalue.
То есть процедура scr_page выведет содержимое одной экранной страницы. При этом соновную работу по выводу дампа данных выполняет вызываемая процедура menu_byte, которую далее рассмотрим.
Назад |
Начало урока |
Вверх |
Вперед
;выходные параметры
;svalue - начальный адрес
;page_index - номер страницы
push bx
push si
mov al,mas_evalue[si]
mov evalue,al ;конечный адрес в памяти
mov svalue,al ;начальный адрес в памяти
add bx,bx
mov bp,mes_adr[bx] ;адрес сообщения (пояснения)
mov cx,mes_dl[bx] ;длина сообщения (пояснения)
pop bx
pop ax
push cx
call cursor_position
mov bp,offset zagolovok
mov cx,34
mov color,02h
call print_string
call corretka
mov kolonka,0
mov stroka,49
mov color,0Dh
mov bp,offset Key_Menu
mov cx,60
call print_string
;******************
pop bp
mov stroka,02h
call print_string
;***************
call print_position
call menu_byte ;печать адреса и значения по этому адресу
;**************************
ret
svalue - начальный адрес читаемой CMOS и RTS памяти
evalue - конечный адрес читаемой CMOS и RTS памяти
mov al,mas_evalue[si]
mov evalue,al
mov svalue,al
evalue будет помещено значение 0Ch, а в переменную svalue значение 00h.
mas_evalue и mas_svalue у нас массивы из четырех элементов:
mas_evalue DB 0Ch, 10h, 20h, 3Fh
начала и конца чтения. Мы сохранили в двух переменных (svalue и evalue) начальный и конечный адрес считывания. Будет считан в экранную страницу фрагмент памяти компа начинающийся с адреса 00h и заканчивающийся адресом 0Ch.
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]
mes_dl DW dl0, dl0D, dl10, dl20
BP - указывает с какого места начать копировать (указатель на сообщение).
в BX - видеостраница, в которую будем копировать (это под вопросом).
push bx
push si
mov al,mas_evalue[si]
mov evalue,al
mov svalue,al
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]
pop bx
pop ax
Здесь интересный момент, когда выведены два разных фрагмента из памяти, адресуемые по разному.
Key_Menu DB "F2-WriteCMOS|F3-ReadCMOS|F4-Editer|F10-EXIT
push cx
bp - указатель на пояснение
cx - длина строки
call cursor_position
mov bp,offset zagolovok
mov cx,34
mov color,02h
call print_string
call corretka
mov kolonka,0
mov stroka,49
mov color,0Dh
mov bp,offset Key_Menu
mov cx,60
call print_string
;******************
и меню функциональных клавиш.
cx - длина строки
color - в процедуре print_screen используется, поэтому здесь инициируем ее.
Номер колонки и строки на эране определен значением переменных stroka и kolonka
pop bp
bp - указатель на пояснение
cx - длина строки
mov stroka,02h ;номер строки на эране
call print_string
mov bx,si
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]
mes_dl DW dl0, dl0D, dl10, dl20
знак $, получилась как раз длина соответствующая длине данных от mes0 до $. И это значение
(длину) присвоили переменной dl0.
DB " sec of Alarm-Clock "
DB " min "
DB " min of Alarm-Clock
В CX у нас содержится количество байт, которое необходимо скопировать.
Ну и функция print_string выводит все это содержание дампа памяти на экран.
адреса и значения, содержащиеся в этих адресах. То есть смотрим далее процедуру scr_page:
call print_position ;установим позицию курсора
call menu_byte ;печать адреса и значения по этому адресу
;**************************
эту информацию (для этого вызываем функцию print_position), и вызываем функцию menu_byte,
работу которой далее рассмотрим более подробно. Далее функция press_key,
которая заремирована.
фрагментарно, наподобие мозаики. Действительно, сначала вывели верхний заголовок. Потом вывели меню функциональных клавиш внизу экрана. Затем вывели пояснения с позиции, которая была для этого удобной и наконец будем выводить собственно адреса и содержание ячеек
в памяти, тоже в удобную для этого позицию на экране. Это все одна видеостраница, напрямую в видеобуфер. Такого рода вывод информации возможен потому, что мы работаем с видеобуфером.
Заполняем матрицу, которая выводится на экран. Нам кажется, что экран заполняется мгновенно!
Содержание