4.7.1 Системный таймер

Начиная с IBM AT, персональные компьютеры содержат два устройства для управления процессами - часы реального времени (RTC) и собственно систем­ный таймер. Часы реального времени получают питание от аккумулятора на ма­теринской плате и работают даже тогда, когда компьютер выключен. Это устрой­ство можно применять для определения/установки текущих даты и времени, установки будильника с целью выполнения каких-либо действий и для вызова прерывания IRQ8 (INT 4Ah) каждую миллисекунду. Системный таймер исполь­зуется одновременно для управления контроллером прямого доступа к памяти, для управления динамиком и как генератор импульсов, вызывающий прерывание IRQO (INT 8h) 18,2 раза в секунду. Таймер предоставляет богатые возможностПСТМИИШ:   Основы программирования для MS DOS

для препрограммирования на уровне портов ввода-вывода, но на уровне DOS

и BIOS часы реального времени и системный таймер используются только как средство определения/установки текущего времени и организации задержек.

Функция DOS     Определить дату

Вход:   AH = 2Ah

Выход: СХ = год (1980-2099)

DH = месяц

DL = день

AL = день недели (О - воскресенье, 1 -

Функция DOS     Определить время

Вход:   АН = 2Ch Выход: СН = час

CL = минута

DH = секунда

DL = сотая доля секунды

Эта функция использует системный таймер, поэтому время изменяется толь­ко 18,2 раза в секунду и число в DL увеличивается сразу на 5 или б.

Функция DOS     Установить дату Вход:  AH = 2Bh

СХ - год (1980 - 2099) DH = месяц DL = день

Выход: АН = FFh, если введена несуществующая дата; АН    OOh, если дата

установлена

Функция DOS     Установить время Вход:  АН = 2Dh

СН = час

= минута DH = секунда DL = сотая доля секунды Выход: AL = FFh, если введено несуществующее время, и AL = 00, если время установлено

Функции 2Bh и 2Dh устанавливают одновременно как внутренние DOS, которые управляются системным и обновляются 18,2 раза в

так и часы реального времени. BIOS позволяет управлять часами напрямую.

INTIAhАН- 04h: Определить дату RTC Вход:   AH = 04h

Выход: CF = 0, если дата прочитана

СХ - год (в формате BCD, то есть 200Ш для 2001-го года)

DH = месяц (в формате BCD) DL = день (в формате BCD)

CF = 1, если часы не работают или попытка чтения пришлась на мо­мент обновления

INTIAh АН = 02k. Определить время RTC Вход:    АН = 02h

Выход: CF = 0, если время прочитано

СН = час (в формате BCD)

CL = минута (в формате BCD)

DH = секунда (в формате BCD) DL = Olh, если действует летнее время; 00h, если нет CF = 1, если часы не работают или попытка чтения пришлась на мо­мент обновления

INTIAh АН = 05к Установить дату RTC Вход:    АН = 05h

СХ = год (в формате BCD) DH = месяц (в формате BCD) DL = день (в формате BCD)

INT 1 Ah АН = 03h: Установить время RTC Вход:    AH = 03h

. СН = час (в формате BCD) CL - минута (в формате BCD) DH - секунда (в формате BCD) DL = Olh, если используется летнее время, 0 — если нет

Кроме того, BIOS позволяет использовать RTC для организации будильников и задержек.

INTIAh АН = 06к. Установить будильник

Вход:    АН = 06h

СН - час (BCD)

CL = минута (BCD)

DH = секунда (BCD) . Выход: CF = 1, если произошла ошибка (будильник уже установлен или преры вание вызвано в момент обновления часов); CF = 0, если будильник установлен

Теперь каждые 24 часа, когда время совпадет с заданным, часы реального време­ни вызовут прерывание IRQ8 (INT 4Ah), которое должна обрабатывать установив­шая будильник программа. Если при вызове СН = OFFh, CL = OFFh, a DH = OOh, то будильник начнет срабатывать раз в минуту.

INT    АН =

Вход: АН

07: Отменить будильник

- 07h

Эта функция позволяет отменить будильник, например для того, чтобы уста­новить его на другое время.

1    Основы программирования для MS DOS

BIOS отслеживает каждый отсчет системного таймера с помощью своего об­работчика прерывания IRQO (INT 8h) и увеличивает на 1 значение 32-битного счетчика, который располагается в памяти по адресу OOOOh:046Ch, причем во вре­мя переполнения этого счетчика байт по адресу 0000h:0470h увеличивается на 1.

INT 1AhAH= ООк Узнать значение счетчика времени Вход:    АН = 00h

Выход:   CX:DX - значение счетчика

AL = байт переполнения счетчика

INT 1AhAH= 01 к Изменить значение счетчика времени Вход:   АН = Olh

CX:DX - значение счетчика

Программа может считывать значение этого счетчика в цикле (через прерывание или просто командой MOV) и организовывать задержки, например, пока счетчик не увеличится на 1. Но так как этот счетчик использует системный таймер, мини­мальная задержка будет равна приблизительно 55 мкс. Частоту таймера можно изменить, программируя его на уровне портов, но BIOS предоставляет для этого специальные функции.

INT 15h АН = 86к Формирование задержки Вход:    АН = 86h

CX:DX - длительность задержки в микросекундах (миллионных долях секунды!)

Выход: AL = маска, записанная обработчиком в регистр управления прерыва­ниями

CF = 0, если задержка выполнена CF = 1, если таймер был занят

" Если нужно запустить счетчик времени и продолжить выполнение програм­мы, можно воспользоваться еще одной функцией.

INT15h АН = 83к Запуск счетчика времени Вход:   АН = 83h

AL = 0 - запустить счетчик

CX:DX - длительность задержки в микросекундах ES:BX - адрес байта, старший бит которого по окончании работы счетчика будет установлен в 1 AL = 1 - прервать счетчик

Минимальный интервал для этих функций на большинстве систем обычно составляет около 1000 микросекунд. Воспользуемся функцией организации за­держки для небольшой интерактивной игры:

; worm.asm

; Игра "Питон" (или "Змея", или "Червяк"). Управление осуществляется

; курсорными клавишами. Питон погибает, если он выходит за верхнюю

; или нижнюю границу экрана либо самопересекается.

.model tiny . code

start:

.186

org

mov

add

mov

push

pop

mov

int

mov mov

rep

xor mov jmp main_cycle:

Использование АХ

ВХ

lOOh

ax, cs ax,1000h ds, ax

OAOOOh

es

ax,13h

10h

di,320*200 cx,600h

stosb

si, si bp, 10

init_food

Для, команды push OAOOh. СОМ-файл.

Текущий сегментный адрес плюс

1000h = следующий сегмент,

который будет использоваться

для адресов головы и хвоста.

OAOOOh - сегментный адрес

видеопамяти (в Графический режим 13h.

Заполнить часть видеопамяти, остающуюся за пределами экрана, ненулевыми значениями (чтобы питон не смог выйти за пределы экрана). Начальный адрес хвоста Начальная длина питона Создать первую еду.

в

DS:SI.

10.

регистров

в этой программе:

различное.

адрес головы,  хвоста или еды на экране.

СХ - 0 (старшее слово числа микросекунд для функции задержки).

DX - не исполвзуется  (модифицируется процедурой random).

- сегмент данных программы  (следующий после сегмента кода).

ES - видеопамять.

DS:DI - адрес головы.

- адрес хвоста.

BP - добавочная длина (питон растет,

шаге, пока не станет нулем).

пока BP > 0;  BP уменьшается на каждом

mov

dx,20000 ;

Пауза - 20 000 мкс.

mov

ah,86h ;

(СХ = 0 после REP STOSB

 

 

и больше не меняется)

int

15h ;

Задержка.

mov

ah,1 ;

Проверка состояния клавиатуры.

int

16h

 

jz

short no keypress

Если клавиша нажата -

xor

ah, ah ;

АН = 0 - считать скан-код

int

16h                            .;

нажатой клавиши в АН.

cmp

ah,48h ;

Если это стрелка вверх,

jne

short not_up

 

mov

word ptr cs:move_direction,

; изменить

; направление движения на "вверх"

not_up:

cmp jne mov

not.down:

cmp jne mov

not_left:

cmp

jne

mov

no_keypress:

and

jnz lodsw

xchg

mov

mov

inc

advance_head:

dec

add

mov

and

jz cmp

je

mov

int retn

move_worm:

mov

inc inc

mov cmp ah,50h ;  Если это стрелка вниз,

short not_down

word ptr cs:move_direction, 320 ; изменитв

; направление движения ' на "вниз". ■

;   Если это стрелка влево,

short notjeft

word ptr cs:move_direction,-1 ; изменитв

;   направление движения на "влево".

;   Если это стрелка вправо,

short no_keypress

word ptr cs:move_direction,1 ; изменитв

направление движения на "вправо".

bp, bp

short advance head

bx, ax

byte ptr es:[bx],0 bx, ax

bp

Если питон растет  (ВР > 0), пропустить стирание хвоста. Иначе: 'считать адрес хвоста из 08:81 в АХ и увеличить гі на 2.

Стереть хвост на экране.

Увеличить ВР, чтобы следующая команда вернула его в 0.

Ьр ; Уменьшить ВР, так как питон

: вырос на 1, если стирание хвоста .

было пропущено,  или вернуть его

; в 0 - в другом случае. Ьх,\дагЬ рИ cs-.move_direcT.ion

; Ьх = следующая координата головы. al.es:.[Ьк] : Проверить содержимое экрана ь точке

; с этой координатой. Если там ничего нет, впоп  тоуе_и/огт ; передвинуть голову.

аі, ООгі ; Если там еда,

вЬогт  дго\огагт ; увеличить длину питона.

Иначе - питон умер, 101і ; Перейти в текстовый режим :

и завершить программу.

[di],bx

di di

byte ptr es:[bx],09 byte ptr cs:eaten_food,1

Поместитв адрес головы в БЗ:Б1

и увеличитв Б1 на 2. Вывести точку на экран. Если предыдущим ходом была съедена еда -

je jmp

grow_worm:

push moy

xor

call

call

and

mov

pop jmp

if_eaten_food:

mov init^food:

push

raake_food:

call

and

mov

xor

cmp

jne cmp

jne mov

mov

call

pop jmp if_eaten_food short main_cycle

bx

bx.word ptr cs:food_at

ax, ax draw_food random ax,3Fh bp, ax

byte ptr cs:eaten_food,1

bx

short movej/rorm

byte ptr

bx

random ax,OFFFEh bx.ax

ax, ax

word ptr es:[bx],ax make_food

word ptr es:[bx+320],ax make_food

word ptr cs:food_at,bx

ax.ODODh

draw_food bx

main_cycle

создать новую еду.

Иначе - продолжить основной

цикл.

Процедура draw_food.

Изображает четыре точки на экране - две ■строке. Цвет первой точки из пары - АР,

draw^food:

mov mov retn es:[bxj,ax

word ptr

Сохранитв адрес головы.

ВХ - адрес еды,

АХ = 0.

Стеретв еду.

АХ - случайное число.

АХ - случайное число от 0 до 63.

Это число будет добавкой

к длине питона.

Установитв флаг

для генерации еды на следующем ходе. Восстановитв адрес  головы ВХ.

Перейти к движению питона.

Переход сюда,  если еда была съедена.

Восстановитв флаг.

Переход сюда в самом начале.

Сохранитв адрес головы.

АХ - случайное число.

АХ - случайное четное число.

ВХ - новый адрес для еды.

Если по этому адресу

находится тело питона,

еще раз сгенерироватв случайный адрес.

Если на строку ниже

находится тело питона -

то же самое.

Поместитв новый адрес

еды в food_at, цвет еды в АХ и нарисоватв еду на экране.

по адресу BХ и две на следующей

второй - АН.

Генерация числа.

Возвращает число'в АХ, модифицирует DX.

mov

random:   mov       ах,word ptr cs:seed

mov        dx,8E45h mul dx

inc ax

mov cs:word ptr seed,ax retn

; Переменные.

eaten_food db 0

movejiirection dw 1 ; Направление движения: 1 - вправо,

;  -І - влево, 320 - вниз,  -320 - вверх. seed: ; Это число хранится за концом программы,

food_at  equ seed+2 ; а это - за предыдущим.

end start