Назад | Начало урока | Вперед
Содержание

Глава 1 (продолжение 1)

Изучив вышеуказанные функции становится понятным код, с которого начинается
главная процедура main:

Вверх

;управляющая процедура ********************************************************

main proc
;инициализация сегмента данных
mov ax,@data
mov ds,ax
mov es,ax
xor ax,ax

;Настроили ds,es на сегмент данных, очистили ax

;инициализация текущего графического режима
call get_screeng_mode

;очистка экрана
call clear_screeng

;ввывод собщения об авторских правах
mov bp,offset message1
mov cx,dlmessage1
call print_string
call corretka

call cursor_position
mov bp,offset message2
mov cx,dlmessage2
call print_string
call corretka

call cursor_position
mov bp,offset message3
mov cx,dlmessage3
call print_string
call corretka

Видимым на экране результатом этого кода является три сообщения:
----------------
Cmos Editor v2.3
Programmed by Pashkov Aleksey
6.99
----------------

Продолжим далее рассматривать код главной программы main.

mov al,svalue
mov mas_svalue[0],al
call press_key
call scr_page ;процедура вывода дампа памяти


Продолжение рассмотрения кода процедуры main на странице: Далее процедура main

Рассмотрим подробнее вышепредставленный код.
Сначала помещаем в первый элемент массива mas_svalue[0] значение переменной svalue (начальный адрес для чтения из памяти):


mov al,svalue
mov mas_svalue[0],al

Затем вызываем две процедуры:

call press_key
call scr_page ;процедура вывода дампа памяти

Первая процедура press_key проста, она помещает в две переменные соответственно ascii-код и scan-код клавиши:

;функция нажата ли клавиша ****************************************************

press_key proc
push ax

mov ah,00h
int 16h
mov ascii_code,al
mov scan_code,ah

pop ax
ret

press_key endp
;******************************************************************************

Вызов процедуры 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

Вверх

;процедура вывода дампа памяти ************************************************
;выходные параметры
;svalue - начальный адрес
;page_index - номер страницы

scr_page proc
push ax
push bx
push si

mov si,page_index
mov al,mas_evalue[si]
mov evalue,al ;конечный адрес в памяти

mov al,mas_svalue[si]
mov svalue,al ;начальный адрес в памяти

mov bx,si
add bx,bx
mov bp,mes_adr[bx] ;адрес сообщения (пояснения)
mov cx,mes_dl[bx] ;длина сообщения (пояснения)

pop si
pop bx
pop ax

push ax

call clear_screeng

push bp
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 cx
pop bp

;вывод пояснений (вывод сообщения на экран)
mov stroka,02h
call print_string
;***************

;вывод адреса и содержимого
call print_position
call menu_byte ;печать адреса и значения по этому адресу
;**************************

;call press_key

pop ax
ret

scr_page endp
;******************************************************************************

Рассмотрим подробнее эту процедуру.

Вначале, после сохранения в стеке регистров, инициализируются переменные
svalue - начальный адрес читаемой CMOS и RTS памяти
evalue - конечный адрес читаемой CMOS и RTS памяти

mov si,page_index
mov al,mas_evalue[si]
mov evalue,al

mov al,mas_svalue[si]
mov svalue,al

Поскольку при первом вызове функции scr_page в сегменте si будет ноль, то в переменную
evalue будет помещено значение 0Ch, а в переменную svalue значение 00h.
mas_evalue и mas_svalue у нас массивы из четырех элементов:

mas_svalue DB 00h,0Dh,11h,21h
mas_evalue DB 0Ch, 10h, 20h, 3Fh

То есть читаться будет не вся память компа, а от "сих до сих". Указан конкретный адрес
начала и конца чтения. Мы сохранили в двух переменных (svalue и evalue) начальный и конечный адрес считывания. Будет считан в экранную страницу фрагмент памяти компа начинающийся с адреса 00h и заканчивающийся адресом 0Ch.

Значение переменных svalue и evalue будут использованы далее при вызове процедуры menu_byte, для побайтного вывода на экран всего содержания памяти, находящегося в пределах этих двух адресов. Будут в процедуре menu_byte выведены содержание всех ячеек и их адреса.

Далее нам надо настроить регистры bx,bp,cx для того, чтобы правильно скопировать в видеостраницу те данные, о которых мы только-что сказали.

mov bx,si
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]

Здесь mes_adr и mes_dl так же массивы из четырех элементов.

mes_adr DW mes0, mes0D, mes10, mes20
mes_dl DW dl0, dl0D, dl10, dl20

То есть в первый вызов функции scr_page будет считан массив данных, начинающийся с метки (переменной) mes0 и будет считано столько байт данных, сколько будет содержаться в переменной dl0, которая у нас равна $-mes0:

dl0 = $-mes0

То есть будет считано начиная с переменной, находящейся по адресу mes0, и будет считано число байт, которое содержится в переменной dl0, а это $-mes0 байт.

То есть данные будут выведены с метки mes0 и до того места, где у нас в коде (сегмент данных) стоит:

dl0 = $-mes0

Вообще этот фрагмент кода для меня довольно интересен! Именно то, как в этом фрагменте определяется та область кода (ее границы), которая будет скопирована в видеостраницу.

Теперь в CX у нас количество байт, которое необходимо скопировать.
BP - указывает с какого места начать копировать (указатель на сообщение).
в BX - видеостраница, в которую будем копировать (это под вопросом).

Далее восстанавливаем ранее сохраненные регистры из стека.

Еще раз повторим для ясности этот фрагмент кода:

push ax
push bx
push si

mov si,page_index
mov al,mas_evalue[si]
mov evalue,al

mov al,mas_svalue[si]
mov svalue,al

mov bx,si
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]

pop si
pop bx
pop ax

Во фрагменте, который мы только-что рассмотрели, будет выведен на экран и код из памяти, который ограничен началом и концом чтения из памяти (svalue и evalue), так же будет выведен фрагмент данных ограниченных началом и концом чтения данных (на начало указывает BP, конец будет ограничен длиной данных, содержащихся в СX).
Здесь интересный момент, когда выведены два разных фрагмента из памяти, адресуемые по разному.

Рассмотрим процедуру scr_page далее. Напомним еще две переменных, участвующих далее в процедуре:

zagolovok DB "Adress Value Bit Value Note"
Key_Menu DB "F2-WriteCMOS|F3-ReadCMOS|F4-Editer|F10-EXIT

Итак далее код процедуры scr_page:

push ax

call clear_screeng ;очистить экран

push bp
push cx

Сохраняем в стеке cx и bp чтобы в дальнейшем вывести пояснение.
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
;******************

Как видим этот код очищает экран, и создает на экране две надписи - заголовок
и меню функциональных клавиш.

bp - указатель на сообщение
cx - длина строки
color - в процедуре print_screen используется, поэтому здесь инициируем ее.
Номер колонки и строки на эране определен значением переменных stroka и kolonka

При этом напоминаю, что процедура print_string выводит сообщение, на которое указывает BP напрямую в видеобуфер (смотри процедуру print_screen), в указанную страницу.

При первом вызове процедуры scr_page это будет нулевая страница, как мы только что установили. Думаю, что и каждый следующий вызов процедуры print_screen будет выводить содержимое памяти компа в нулевую видеостраницу. Такова процедура print_screen.

Смотрим что происходит далее в процедуре scr_page:

pop cx
pop bp

Как видим восстанавливаются cx и bp чтобы вывести пояснение.
bp - указатель на пояснение
cx - длина строки

;вывод пояснений
mov stroka,02h ;номер строки на эране
call print_string

Здесь мы вывели в строку 02h колонки 00h содержимое, на которое указывает у нас в настоящее время BP. А указывает он у нас на фрагмент в памяти, начиная с mes0.

Вспомним:


mov bx,si
add bx,bx
mov bp,mes_adr[bx]
mov cx,mes_dl[bx]

Здесь mes_adr и mes_dl это адрес сообщения и длина сообщения. Так же массивы из четырех элементов. То есть bp указывает на сообщение,а в cx - длина сообщения.

mes_adr DW mes0, mes0D, mes10, mes20
mes_dl DW dl0, dl0D, dl10, dl20

То есть в первый вызов функции scr_page будет считан массив, начинающийся с метки (переменной) mes0 и заканчиающийся меткой $. Далее присвоим переменной dl0 некоторое значение:

dl0 = $-mes0

То есть будет считано начиная с переменной, находящейся по адресу mes0, и будет считано число байт, которое содержится в переменной dl0, а это $-mes0 байт.

Здесь произошла арифметическая операция: адрес mes0 вычли из адреса, по которому расположен
знак $, получилась как раз длина соответствующая длине данных от mes0 до $. И это значение
(длину) присвоили переменной dl0.

А с этого адреса у нас в памяти компа фрагмент данных, в котором содержатся пояснения:

mes0 DB " sec "
DB " sec of Alarm-Clock "
DB " min "
DB " min of Alarm-Clock

Таким образом BP у нас указывает на данные.
В CX у нас содержится количество байт, которое необходимо скопировать.
Ну и функция print_string выводит все это содержание дампа памяти на экран.

Теперь верхний и нижний заголовки у нас выведены, выведены пояснения. Осталось вывести
адреса и значения, содержащиеся в этих адресах. То есть смотрим далее процедуру scr_page:

;вывод адреса и содержимого
call print_position ;установим позицию курсора
call menu_byte ;печать адреса и значения по этому адресу
;**************************

Для этого мы позиционируем курсор в то место на экране, в которое необходимо вывести
эту информацию (для этого вызываем функцию print_position), и вызываем функцию menu_byte,
работу которой далее рассмотрим более подробно. Далее функция press_key,
которая заремирована.

;call press_key

Резюме:

В рассмотренном фрагменте для меня интересно еще то, что процедура scr_page заполняет экранную страницу
фрагментарно, наподобие мозаики. Действительно, сначала вывели верхний заголовок. Потом вывели меню функциональных клавиш внизу экрана. Затем вывели пояснения с позиции, которая была для этого удобной и наконец будем выводить собственно адреса и содержание ячеек в памяти, тоже в удобную для этого позицию на экране. Это все одна видеостраница, напрямую в видеобуфер. Такого рода вывод информации возможен потому, что мы работаем с видеобуфером.
Заполняем матрицу, которая выводится на экран. Нам кажется, что экран заполняется мгновенно!

И так рассмотрим далее работу процедуры menu_byte. А эта процедура выводит всего лишь адрес одной ячейки и ее содержание. Да! Всего одной ячейки! Но этот код внутри функции будет повторяться столько раз, пока не будет выведено содержание и адрес всех ячеек памяти адрес которых начинается с svalue и заканчивается адресом evalue.

То есть процедура scr_page выведет содержимое одной экранной страницы. При этом соновную работу по выводу дампа данных выполняет вызываемая процедура menu_byte, которую далее рассмотрим.


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz