#70 (112) $scrol
Еще один чрезвычайно полезный при работе с текстами рестарт - 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
#71 (113) $tylin
Распечатка строки по вектору для edstr от XS (позиции курсора) до конца видимой области.
Вход: IX - адрес вектора ("ошибок быть не может")(см. ПРИЛОЖЕНИЯ 10..13)
#72 (114) $g_scr
Возвращение в регистре HL' адреса вектора экрана и beep'a (см. ПРИЛОЖЕНИЕ 14)
#73 (115) $cls
Если при вызове рестарта 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
#74 (116) EMPTY
Не используется
#75 (117) EMPTY
Не используется
#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
#78 (120) EMPTY
Не используется.
#79 (121) EMPTY
Не используется.
#7A (122) EMPTY
Не используется.
#7B (123) EMPTY
Не используется.
#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
#7E (126) $analys
Рестарт 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 команде.
#7F (127) $edstr
Редактирование строки в тексте. Отрабатывает все печатные коды (символы) + 6 управляющих: клавиши 1,2,3,5,8,0 с Caps Shift'ом.
Вход: IX - вектор, (на входе необходимо инициировать LNST, XS и COM)
Выход: CARRY - системная ошибка (см. ПРИЛОЖЕНИЯ 10..13).