Еще один чрезвычайно полезный при работе с текстами
рестарт - scrol(#70). Он позволяет смещать содержимое рабочей области окна на
строку вверх или вниз.
При работе рестарта предусмотрено программирование
заполнения крайнего левого и крайнего правого знакомест в освободившейся строке
(нижней при движении вверх и наоборот).
Входные параметры: IX - вектор окна
HL - значение крайних байтов заполнения
освободившейся строки (образ кодируется в двоичном представлении, например:
одинарная линия по краю кодируется как 10000000 00000001 и т.п.)
A - режим работы: A=0 - настройка
рестарта на вектор окна - вызывается один раз перед началом работы в данном
окне. Настройка сохраняется на все время работы до следующего вызова scrol c
нулевым значением в регистре A.
A=1 - скроллинг на строку вверх
A=2 - скроллинг на строку вниз
Для нормальной работы scrol необходимы еще два
параметра, добавляемые к стандартному вектору окна и располагающиеся непосредственно
перед ним:
IX-1 скорость скроллинга - возможные
значения - 1, 2, 4, 8 определяет время, в течение которого строка перемещается
на 8 пикселей по вертикали
IX-2 задержка скроллинга - возможные
значения от 0 до 255 - регулирует время паузы между последовательными вызовами
рестарта
Подбором этих двух параметров достигается наибольшая
плавность движения при требуемой скорости скроллинга.
Пример:
Листинг 15 Применение $scrol(#70)
ORG #5D64
;открытие окна
CALL CLS
LD IX,WIND
LD C,#61
LD A,2
RST #10
;настройка процедуры scroll на вектор окна:
LD IX,WIND ;вектор окна
LD C,#70 ;код рестарта
LD HL,#0000 ;заполнение
XOR A ;в регистре A - 0
RST #10
;печать строки prstr
подфункция 3
LD IX,WIND
LD HL,TEXT
LD C,#68
LD E,3
LD A,%00001010
LD B,1
RST #10
;скроллинг окна вверх в цикле на 5 строк
LD B,5
M1 PUSH BC
LD C,#70 ;код рестарта
LD A,1 ;скроллинг вверх
LD IX,WIND ;вектор окна
LD HL,#0000 ;заполнение
RST #10
POP BC
DJNZ M1
CALL WAIT
JP EXIT
;вектор окна + 2 байта для рестарта $scrol(#70)
DEFB 25 ;задержка
DEFB 01 ;скорость
WIND DEFB 0
DEFB 5
DEFB 12
DEFB 25
DEFB %00000111
DEFB %00000001
DEFB 2
DEFB 25
;текст для печати
TEXT DEFM
"Так работает scrol(#70)"
DEFB #0D
DEFB #03
Применение рестарта scrol вместе с рестартами печати
(например prstr) позволяет организовать на экране режим "бегущего
текста".
Рассмотрим еще один пример:
Листинг 16 Программа "бегущий текст"
ORG #5D64
;процедура открытия окна
CALL CLS
LD IX,WIND
LD C,#61
LD A,2
RST #10
;настройка процедуры scrol на вектор окна:
LD IX,WIND
LD C,#70
LD HL,0
XOR A
RST #10
;входные параметры для процедуры печати
LD A,%00001010
;в рег. A - биты 7 и 6 определяют режим выравнивания
;биты 5...0 определяют отступ от верхнего края окна
LD B,1 ;номер строки в тексте
(строки отделяются друг от друга символом с кодом #0D)
M1 PUSH
AF ;сохранить регистр A
PUSH BC ;сохранить BC
;печать строки по номеру ее в тексте
LD IX,WIND ;адрес вектора окна
LD HL,TEXT ;адрес начала текста
LD C,#68 ;код
prstr
LD E,3 ;код подфункции
RST #10
CALL SCROLL ;вызов
scrol
POP BC ;восстановить BC
INC B ;увеличить номер
строки в тексте
LD A,B ;проверка на число
CP 9 ;напечатанных строк
JP Z,END ;выход, если все
строки напечатаны
POP AF ;восстановить A
JR M1 ;переход к печати
следующей строки
;вектор окна + 2 байта для рестарта $scrol(#70)
DEFB 25 ;задержка
DEFB 01 ;скорость
WIND DEFB 1
DEFB 1
DEFB 12
DEFB 28
DEFB %00000111
DEFB %00000001
DEFB 4
DEFB 35
;текст для печати
TEXT DEFM
"Эта программа"
DEFB 13
DEFM "представляет собой
пример"
DEFB 13
DEFM "организации в системе"
DEFB 13
DEFM "IS-DOS работы с
экраном"
DEFB 13
DEFM "в режиме 'бегущий
текст'"
DEFB 13
DEFM "Вывод текста
организуется"
DEFB 13
DEFM "при помощи рестартов"
DEFB 13
DEFM "scrol(#70) и
prstr(#68)"
DEFB 13
;Дополнительные процедуры:
SCROLL LD
C,#70 ;процедура скрол-
LD A,1 ;линга окна на
LD IX,WIND ;строку вверх
LD HL,#0000
RST #10
RET
END POP
AF ;завершение работы
CALL WAIT
JR EXIT
Распечатка строки по вектору для edstr от XS (позиции
курсора) до конца видимой области.
Вход: IX - адрес вектора ("ошибок
быть не может")(см. ПРИЛОЖЕНИЯ 10..13)
Возвращение в регистре HL' адреса вектора экрана и
beep'a (см. ПРИЛОЖЕНИЕ 14)
Если при вызове рестарта cls в регистре A находится
0, то происходит полная очистка экрана - все пиксели сбрасываются, область
цветовых атрибутов заполняется текущим значением системной переменной PAPER, находящейся
в векторе экрана, адрес которого можно получить, используя рестарт $q_scr(#72).
Также при этом цвет бордюра приводится в соответствие с текущим значением
системной переменной BORD из того же вектора. Формат задания значений цветов
стандартный, атрибуты бордюра кодируются тремя младшими байтами, остальные
байты игнорируются.
Если же перед вызовом cls в регистре A находится
число, отличное от нуля, то сброс пикселей не происходит, а инициализируется
только область атрибутов экрана, причем значение регистра A трактуется как байт
атрибутов в стандартном представлении. Изменения цвета бордюра в этом случае не
происходит.
Как уже говорилось выше, доступ к системным
переменным PAPER и BORD можно получить через вектор экрана, адрес которого
возвращает в регистре HL' рестарт $q_scr(#72). Вектор экрана (не путать с
вектором окна) представляет собой область системных переменных, уровня
WIND.SYS. Необходимые нам переменные располагаются в нем следующим образом:
Если в регистре IX - адрес вектора экрана, то
(IX+0) - значение PAPER
(IX+1) - значение BORD
Остальные системные переменные этого вектора будут
рассмотрены позднее.
Процедура для занесения необходимых значений цветов в
соответствующие системные переменные может выглядеть примерно так:
LD C,#72 ;код рестарта q_scr
RST #10
EXX ;HL - адрес вектора
PUSH HL ;переносим его
POP IX ;в регистр IX
LD A,%00101010
LD (IX+0) ;загрузка атрибутов
экрана
LD A,%00000100
LD (IX+1) ;загрузка атрибутов
бордюра
После этого Вы смело можете обнулять регистр A и
вызывать cls:
XOR A
LD C,#73
RST #10
значения цветов будут установлены именно так, как Вы
и хотели.
Рассмотрим пример:
Листинг 17 Пример работы $cls
ORG #5D64
;установка цветовых атрибутов без сброса пикселей (A
- байт атрибутов)
LD A,%00111000
LD C,#73 ;код рестарта
$cls
RST #10
CALL WAIT
;установка значений системных переменных PAPER и BORD
LD C,#72 ;получение адреса
RST #10 ;вектора экрана
EXX ;в HL - адрес
PUSH HL ;перенос адреса
POP IX ;в регистр IX
LD A,%00101010
LD (IX+0),A ;установка цветов
экрана
LD A,%00000011
LD (IX+1),A ;установка цветов
бордюра
;полная очистка экрана, цвета берутся из системных
переменных PAPER и BORD
XOR A ;в A
- 0
LD C,#73
RST #10
CALL WAIT
JR EXIT
Не используется
Не используется
#76
(118) $y, #77 (119) $n
Еще два рестарта отвечают за включение и выключение в
текущей позиции экрана мигающего курсора.
Положение курсора определяется уже знакомой нам
системной переменной XYPOS, находящейся в векторе символьного устройства
вывода.
Рестарт $y(#76) включает курсор в текущей позиции, а
рестарт $n(#77) - выключает. Координаты курсора абсолютные.
Процедура изображения мигающего курсора добавляется в
цепочку процедур, вызываемых по прерываниям от таймера при помощи рестарта
$im2(#1E) из уровня DOS.SYS.
При включении следующего курсора не забывайте убирать
предыдущий, хотя никаких серьезных последствий, кроме "засорения" экрана
останками курсоров это не вызовет, а рестарт $n(#77) спокойно уберет их все за
один прием.
Пример:
Листинг 19 Пример работы с курсором
ORG #5D64
;открытие окна
CALL CLS
LD IX,WIND
LD C,#61
LD A,2
RST #10
;печать строк текста из буфера в окне через
подфункцию 3 рестарта $prstr
LD IX,WIND
LD C,#68
LD E,3
LD HL,TEXT
LD A,%11000010
LD B,1
RST #10
LD C,#68
LD E,3
LD B,2
LD HL,TEXT
LD A,%11000100
RST #10
CALL WAIT
;включение и перемещение курсора по экрану
LD B,12
LD H,4 ;Y-смещение для wtpos
LD L,5 ;X-смещение для $wtpos
M1 PUSH BC
PUSH HL
LD C,#6B ;вызов
wtpos, уста-
RST #10 ;новка начальных
координат курсора
LD C,#76 ;включение курсора
RST #10
CALL WAIT ;ожидание клавиши
LD C,#77 ;выключение курсора
RST #10
POP HL ;увеличение смеще-
INC HL ;ния координат
POP BC
DJNZ M1 ;перейти к началу
цикла с новыми координатами
CALL WAIT
JP EXIT
;вектор окна
WIND DEFB 1
DEFB 1
DEFB 8
DEFB 30
DEFB %00001111
DEFB %00000001
DEFB 3
DEFB 38
;текстовый буфер
TEXT DEFM
"Рестарты y(#76)"
DEFM "и n(#77)"
DEFB #0D
DEFM "включение-выключение"
DEFM "курсора"
DEFB #0D
DEFB #03
Не используется.
Не используется.
Не используется.
Не используется.
#7C (124) $d_a, #7D (125) $a_d
Еще два рестарта могут быть необходимы Вам при работе
с числами. Они позволяют переводить целые числа из стандартного 2-х или 4-х
байтового представления в ASCII-строку и наоборот. При помощи этих двух
рестартов Вы сможете привести любое число в форму, приемлемую для печати на
экране, а также сможете сделать понятным компьютеру число, введенное в
символьной форме.
Рестарт d_a(#7C) - преобразует целое 2-х или 4-х
байтовое число в ASCII-строку
Входные параметры: C - код рестарта (#7C)
DE - число, которое надо преобразовать
HL - адрес выходного буфера
A - длина выходного буфера
B - основание системы счисления (2, 8,
10, 16)
Состояние флага C определяет формат
числа:
флаг C=0 - 2-х байтовое число
флаг C=1 - 4-х байтовое число
На выходе образуется требуемое число в символьной
форме, причем строка внутри буфера выравнивается по правой границе, а
оставшаяся левая часть дополняется пробелами. При переполнении буфера рестарт
возвращается в вызывающую программу с установленным флагом C (независимо от его
первоначального состояния) и кодом ошибки 1 (переполнение буфера) в регистре A.
При переводе чисел в 16-ричную, 8-ричную и двоичную
системы символы этих систем (#, o, % и т. п. ) не применяются и в буфер не
вносятся, поэтому за принадлежностью числа к той или иной системе следите самостоятельно.
Рассмотрим пример:
Листинг 20 Перевод чисел в символьную форму и
распечатка их в окне
ORG #5D64
;открытие окна
CALL CLS
LD IX,WIND
LD C,#61
LD A,2
RST #10
;перевод числа из 2-х байтовой формы в символьную (в
DE - число)
LD C,#7C ;код рестарта
LD DE,#9C40 ;исходное число
LD HL,TEXT ;адрес буфера
LD A,5 ;длина буфера
SCF ;сбросим
CCF ;флаг C
LD B,10 ;десятичная
система счисления
RST #10
;печать числа в символьной форме через подфункцию 1 рестарта $prstr
LD IX,WIND
LD C,#68
LD E,1
LD HL,TEXT
LD A,%11000010
LD B,5
RST #10
CALL WAIT
;перевод числа из 4-х байтовой формы в символьную (в
DE - адрес числа)
LD C,#7C ;код рестарта
LD HL,TEXT ;адрес буфера
LD DE,TABL ;адрес числа
LD A,8 ;длина буфера
LD B,16 ;16-ричная система
счисления
SCF ;установим флаг
C
RST #10
;печать числа в окне
LD IX,WIND
LD C,#68
LD E,1
LD HL,TEXT
LD A,%11000100
LD B,8
RST #10
CALL WAIT
JP EXIT
;вектор окна
WIND DEFB 1
DEFB 1
DEFB 8
DEFB 30
DEFB %00001111
DEFB %00000001
DEFB 3
DEFB 38
;текстовый буфер
TEXT DEFM
" "
;исходное 4-х байтовое число
TABL DEFW
#0000 ;младшие 2 байта
DEFW #9C40 ;старшие 2 байта
Рестарт $a_d(#7D) предназначен для обратного перевода
числа из символьной формы в стандартную четырехбайтовую. Он преобразует
ASCII-строку указанной длины, или завершенную кодом #0D, игнорируя ведущие
пробелы. Результат располагается в альтернативных регистрах - младшие байты в
регистровой паре HL', старшие байты - в регистровой паре DE', при этом в
регистровой паре BC' остается адрес продолжения входного буфера.
Входные параметры: C - код рестарта (#7D)
HL - адрес входного буфера
A - длина входного буфера;
если A=0, то преобразуется строка до символа с кодом #0D
B - основание системы счисления по умолчанию.
Основание системы счисления не должно быть больше 16, причем 0 трактуется как
10 (десятичная система)
Система счисления может также определяться первым
символом ASCII-строки:
# h H - 16-ричная система
d - десятичная система
o O - восьмеричная система
%b - двоичная система
Выходные параметры: DE'- старшие
байты числа
HL'- младшие байты числа
BC'- адрес следующего символа ASCII
буфера
Этот рестарт в комплексе с предыдущим позволяет
производить арифметические действия над числами, хранящимися в символьной форме
(например внутри текста).
Рассмотрим пример. Пусть необходимо напечатать строку
"10000+12=", выполнить указанное в ней арифметическое действие и
напечатать результат (см. Листинг 21).
Листинг 21 Пример использования $a_d(#7D)
арифметические действия над числом в символьной форме
ORG #5D64
;открытие окна
CALL CLS
LD IX,WIND
LD A,2
LD C,#61
RST #10
;печать строки с исходным числом
LD HL,TEXT
LD C,#68
LD E,1
LD B,9 ;длина всей строки
LD A,%11000001
RST #10
CALL WAIT
;перевод числа в 4-х байтовую форму
LD HL,TEXT ;адрес входного
буфера
LD A,5 ;кол-во символов
в исходном числе
LD B,10 ;система счисления
LD C,#7D ;код рестарта
RST #10
EXX
;на выходе в HL - младшие байты, а в DE - старшие
LD BC,12 ;сложение чисел
ADD HL,BC
PUSH DE ;помещение резуль-
PUSH HL ;тата в буфер
LD HL,TABL
POP DE
LD (HL),E
INC HL
LD (HL),D
INC HL
POP DE
LD (HL),E
INC HL
LD (HL),D
;перевод числа в символьную форму результат
помещается в текст на место исходного числа
LD C,#7C
LD HL,TEXT
LD A,5 ;кол-во символов
числа - результата
LD B,10
LD DE,TABL
SCF
RST #10
;печать результата
LD C,#68
LD E,1
LD IX,WIND
LD HL,TEXT
LD B,5
LD A,%11000011
RST #10
CALL WAIT
JP EXIT
;вектор окна
WIND DEFB 1
DEFB 1
DEFB 5
DEFB 30
DEFB %00000111
DEFB %00000001
DEFB 3
DEFB 35
;текстовый буфер
TEXT DEFM
"10000+12="
;буфер числа
TABL DEFB
#00
DEFB #00
DEFB #00
DEFB #00
Еще одним практическим примером использования
рестартов $a_d и $d_a может служить Листинг 22 - программа перевода чисел из
одной системы счисления в другую
Листинг 22 Перевод чисел в 16-ричную систему (пример
использования $d_a)
ORG #5D64
;открытие окна
CALL CLS
LD IX,WIND
LD C,#61
LD A,2
RST #10
;печать пояснительного текста
LD C,#66
RST #10
;ввод числа с клавиатуры
START LD C,#88 ;рестарт $ed_dig
LD A,17 ;из уровня SHELL
LD DE,#0402 ;будет рассмотрен
LD HL,#0000 ;в следующих
LD IX,WIND ;выпусках серии
RST #10
JP C,START
JP NZ,EXIT
;помещение числа в буфер
EXX
EX DE,HL
LD HL,TABL
LD (HL),E
INC HL
LD (HL),D
;перевод числа из 4-х байтовой формы в символьную (в
DE - адрес числа)
LD C,#7C ;код рестарта
LD HL,TEXT ;адрес буфера
LD DE,(TABL) ;адрес числа
LD A,16 ;длина буфера
LD B,16 ;система счисления
SCF
CCF сбросим флаг C
RST #10
;печать числа в окне
LD IX,WIND
LD C,#68
LD E,1
LD HL,TEXT
LD A,%10000100
LD B,16
RST #10
CALL WAIT
CP #10
JP Z,EXIT
JP START
;вектор окна
WIND DEFB 1
DEFB 1
DEFB 8
DEFB 30
DEFB %00001111
DEFB %00000001
DEFB 3
DEFB 36
;пояснительный текст
DEFM "Перевод чисел в
16-ричную"
DEFM "систему"
DEFB #0D
DEFM " Входное значение"
DEFM " Результат "
DEFB #0D
DEFB #0D
DEFM " "
DEFM " 0"
DEFB #0D
DEFB #0D
DEFM " (C) PENCRAFT
1994 "
DEFM "SS+A - Выход"
DEFB #0D
DEFB #03
;текстовый буфер
TEXT DEFM
" "
;буфер числа
TABL DEFW
#0000
Рестарт analys(#7E) позволяет организовать в Вашей
программе таблицу процедур. Он находит в таблице адрес необходимой процедуры по
ее коду и передает ей управление.
Входные параметры: HL - адрес таблицы процедур
A - код процедуры
Таблица состоит из записей по три байта, из которых
первый - код процедуры, а два оставшихся - ее адрес в стандартном формате (первый
байт - младший).
Последней записью должна быть процедура обработки
ситуации "код не найден", для нее зарезервирован код #FF, после
которого и следует поместить ее адрес.
На выходе из рестарта при передаче управления
процедуре в регистре HL сохраняется адрес таблицы, в A - код команды, а регистр
BC' содержит адрес процедуры, которой передается управление. Остальные регистры
(кроме альтернативного набора) не изменяются и могут быть использованы для
передачи параметров. Переход к процедуре осуществляется путем помещения ее
адреса рестартом analys на стек и подачей команды RET, поэтому передача
параметров через стек в данном случае нежелательна во избежание путаницы с
адресами.
Все процедуры должны заканчиваться инструкцией RET,
которая возвращает управление в точку, следующую за вызовом рестарта analys.
При помощи рестарта analys можно организовать,
например, программу для обработки клавиш управления курсором передавая
управление процедурам перемещения его в разных направлениях в зависимости от
кода нажатой клавиши (см. Листинг 23).
Листинг 23 Вызов процедур по таблице рестарт $analys(#7E)
ORG #5D64
CALL CLS
;установка координат курсора
LD H,10 ;Y-coord
курсора
LD L,20 ;X-coord
курсора
LD C,#0C ;вызов
prapd, уста-
RST #10 ;новка начальных
координат курсора
;основная программа
MAIN LD
C,#76 ;включение курсора
RST #10
LD C,#12 ;вызов вектора
RST #10 ;символьного
устройства
EXX ;вывода, HL - адрес
INC HL ;координат курсора
EX DE,HL ;помещаем его в DE
CALL WAIT ;ожидание клавиши, в A -
код клавиши
PUSH AF ;сохраним его
LD C,#77 ;выключение курсора
RST #10
POP AF ;восстановим регистр A
LD HL,TABL ;адрес таблицы процедур
LD C,#7E ;код рестарта analys
RST #10 ;вызов рестарта
;управление передается по адресу из таблицы в
соответствии с кодом клавиши по окончании отработки процедуры - возврат по RET
на следующую после вызова рестарта команду
CP #F4 ;проверка на
RET Z ;окончание работы
JP MAIN ;повторить цикл
;таблица процедур
TABL DEFB
#0B ;CS+7
DEFW UP
DEFB #0A ;CS+6
DEFW DOWN
DEFB #08 ;CS+5
DEFW LEFT
DEFB #09 ;CS+8
DEFW RIGHT
DEFB #10 ;SS+A
DEFW END
DEFB #FF ;остальные клавиши
DEFW NO_KEY
;процедуры
UP EX DE,HL ;увеличение
INC HL ;координаты Y
DEC (HL)
RET
DOWN EX DE,HL ;уменьшение
INC HL ;координаты Y
INC (HL)
RET
LEFT EX DE,HL ;уменьшение
DEC (HL) ;координаты X
RET
RIGHT EX DE,HL ;увеличение
INC (HL) ;координаты X
RET
NO_KEY RET ;"ключ не найден"
END XOR
A ;установка парамет-
LD A,#F4 ;ров для выхода в
RET ;IS-DOS и флага Z
для выхода из цикла MAIN
;после отработки процедур инструкция RET осуществляет
переход к следующей после вызова рестарта analys команде.
Редактирование строки в тексте. Отрабатывает все
печатные коды (символы) + 6 управляющих: клавиши 1,2,3,5,8,0 с Caps Shift'ом.
Вход: IX - вектор, (на входе необходимо
инициировать LNST, XS и COM)
Выход: CARRY - системная ошибка (см. ПРИЛОЖЕНИЯ
10..13).