Процедура "ЗВЕЗДЫ"
© Константин Короткое, г. Людиново, Калужская область, 1994
В программе "Norton Commander" для IBM-овских машин есть замечательный режим - режим экономии ресурса монитора, который включается автоматически, если в течение некоторого времени на клавиатуре не нажималась ни одна клавиша. При этом экран монитора гаснет, а чтобы информировать пользователя о том, что компьютер включен, на нем формируется картинка "звездного неба". При нажатии на любую клавишу информация на экране восстанавливается.
Предлагаемая процедура служит для создания подобного эффекта в Спектрумовских программах. По-моему, прикладные и системные программы, формирующие на экране статичную, в основном буквенно-цифровую информацию, должны иметь такой режим. Теперь о процедуре.
1. Условия работы.
Для нормальной работы приведенного варианта процедуры должны быть разрешены прерывания первого рода. Процедура работает со вторым (23673) байтом системной переменной FRAMES, выполняющей роль таймерного счетчика. При инициализации процедуры этот байт обнуляется, а затем процедура контролирует превышение заданного значения времени по его содержимому.
Если в программе должны работать часы, использующие ту же переменную FRAMES, то для инициализации необходимо запоминать в специальной ячейке содержимое второго байта FRAMES, а процедуру переделать так, чтобы анализировалась разница между текущим и запомненным состояниями FRAMES.
Для работы в режиме с прерываниями второго рода, программа обработки прерываний должна подсчитывать их количество, используя ту же переменную FRAMES, или свою собственную переменную-счетчик. В последнем случае в процедуре нужно указать ее адрес.
2. Рабочая среда.
Приведенный вариант формирует на экране 25 звезд. Для описания каждой из них необходимо 4 байта: 2 байта - адрес, 3-й байт - длительность текущей фазы, 4-й - яркость. Итого - 4x25=100 байтов (количество звезд может быть изменено, соответственно изменится размер массива). Этот массив памяти не будет никак использоваться до тех пор, пока не заработает процедура.
Для рационального использования ОЗУ можно предложить, по крайней мере, два способа.
Первый - использовать оверлейную структуру (структуру наложения) для локальных данных всех процедур программы (то есть данных, которые нужны и имеют значение только во время работы соответствующей процедуры) При этом под оверлей должно быть выделено столько места, сколько нужно для самого большого сегмента данных. Тогда все остальные сегменты в него поместятся.
Второй способ - использование динамической памяти. При этом массив вообще не имеет конкретного адреса, а формируется в том месте памяти, которое в это время не используется, но в этом случае должна быть введена ячейка памяти (слово), где будет храниться ссылка на выделенное место (адрес) .
Кроме массива с описанием звезд, необходим буфер для сохранения информации с экрана. В общем случае он должен иметь размер 6912 байтов. В отношении его также остаются в силе два способа использования памяти, а кроме того, можно попытаться вообще избавиться от этого буфера или свести его размеры до минимума.
Буфер нужен для того, чтобы сохранить в нем информацию с экрана на время, пока программа находится в дежурном режиме (на экране - звезды). При нажатии любой клавиши информация из буфера перебрасывается обратно на экран.
Первое, что хочется использовать - компрессию экрана перед засылкой в буфер, однако для буквенно-цифровой информации это не даст значительного выигрыша.
Второе: если изображение монохромное, то можно не сохранять атрибуты - это 768 байтов экономии.
Далее необходимо пояснить, как работает процедура. Информация с экрана переписывается в буфер, во всех знакоместах рисуется изображение звезд, затем по случайному закону выбираются 25 знакомест и подсвечиваются в течение некоторого времени. Когда время подсвечивания какого-либо знакоместа заканчивается, оно гасится и выбирается новое знакоместо.
Таким образом, процедура работает только с файлом атрибутов, а изображение звезд не имеет принципиального значения, то есть можно информацию с экрана не стирать, а подсвечивать то, что на нем есть. ,Если изображение было цветное - нужно сохранить только атрибуты, для чего потребуется всего 768 байт. Если изображение монохромное - ничего сохранять не надо. В этом случае из процедуры нужно удалить строки, в которых рисуются звезды и предусмотреть очистку только файла атрибутов.
Кроме того, в головной программе может существовать процедура регенерации или формирования изображения на экране. В этом случае также не нужно сохранять экран, а достаточно просто передать ей управление, если программа переходила в дежурный режим. Об этом можно узнать по состоянию флага "С" - если он сброшен после обращения к процедуре, значит, был дежурный режим.
Приведенный в листинге вариант использует буфер для всего экрана.
00010 |
|
ORG |
40000 |
; |
|
00020 |
ATTR |
EQU |
22528 |
; Адрес |
файла атрибутов. |
00030 |
SCRA |
EQU |
16384 |
; Адрес |
экрана. |
00040 |
TIME |
EQU |
23673 |
; Адрес |
второго байта FRAMES |
00050 |
NST |
EQU |
25 |
;Количество звезд. |
00060 |
LASTK |
EQU |
23560 |
;Символ с клавиатуры. |
00070 |
SCRL |
EQU |
6912 |
;Размер экрана. |
00080 |
OUTB |
EQU |
71 |
;Атрибут вспышки. |
00090 |
STBC |
EQU |
#2D2B |
;BC в калькулятор. |
00100 |
STST |
EQU |
#2AB1 |
;Параметры строки в калькулятор. |
00110 |
FPBC |
EQU |
#2DA2 |
;Из калькулятора в BC. |
00120 |
SETW |
EQU |
# 1 6BF |
;0чистить рабочую обл. и калькулятор |
00130 |
BEEP |
EQU |
#3F8 |
;Звуковой сигнал. |
00140 |
VAL |
EQU |
#1D |
;Команда калькулятора. |
00150 |
MULT |
EQU |
4 |
|
00160 |
INT |
EQU |
#27 |
|
00170 |
ECAL |
EQU |
#38 |
|
00180 |
DARK |
EQU |
0 |
;Атрибут гашения. |
00190 |
TIM |
EQU |
3 |
;Bремя ожидания.5 |
00200 |
|
|
|
; |
00210 |
STARS |
LD |
A, (TIME) |
;Информация из таймера.,(TIME) |
00220 |
|
CP |
TIM |
;Прошло заданное время? |
00230 |
|
RET |
С |
;Если нет, выход с установленным ;флагом "C". |
00240 |
|
CALL |
STSC |
; Охранить экран. |
00250 |
|
LD |
HL,SCRA |
|
00260 |
|
LD |
DE,SCRA+1 |
|
00270 |
|
XOR |
A |
|
00280 |
|
LD |
(LASTK),A |
^брос признака нажатия клавиши. |
00290 |
|
OUT |
(254),A |
|
00300 |
|
LD |
(HL),A |
;Дочистить экран и атрибуты. |
00310 |
|
LD |
BC,SCRL-1 |
|
00320 |
|
LDIR |
|
|
00330 |
|
LD |
HL,17152 |
|
00340 |
|
LD |
B, 3 |
;Количество сегментов экрана. |
00350 |
N1 |
PUSH |
BC |
|
00360 |
|
LD |
BC,511 |
|
00370 |
|
LD |
E, L |
|
00380 |
|
LD |
D, H |
|
00390 |
|
INC |
DE |
|
00400 |
|
LD |
(HL),24 |
;Рисование звезды. |
00410 |
|
LDIR |
|
|
00420 |
|
LD |
DE,1537 |
;Cмещение адреса до следующего сегме! |
00430 |
|
ADD |
HL, DE |
|
00440 |
|
POP |
BC |
|
00450 |
|
DJNZ |
N1 |
|
00460 |
|
LD |
B, NST |
;Количество звезд. |
00470 |
|
LD |
IX,ARR |
;Адрес массива описания звезд. |
00480 |
IST |
CALI |
INIT |
;Инициализация звезды. |
00490 |
|
LD |
DE,4 |
;Cмещение до следующего элемента. |
00500 |
|
ADD |
IX, DE |
|
00510 |
|
DJNZ |
IST |
;Инициализация всего массива. |
00520 |
ALL |
LD |
IX,ARR |
|
00530 |
|
LD |
B, NST |
|
00540 |
ONE |
DEC |
(IX+2) |
;Закончилась фаза жизни? |
00550 |
|
JR |
NZ, N2 |
; Нет. |
00560 |
|
INC |
(IX+3) |
;Иначе - увеличить яркость. |
00570 |
|
PUSH |
BC |
|
00580 |
|
LD |
BC,250 |
;Максимальная фаза жизни. |
00590 |
|
CALL |
CALC |
;Теперь в BC - случайное число. |
00600 |
|
INC |
C |
|
00610 |
|
LD |
(IX+2),C |
;Длительность очередной фазы. |
00620 |
|
POP |
BC |
|
00630 |
N2 |
LD |
A,(IX+3) |
;Яркость звезды. |
00640 |
|
LD |
L, (IX) |
|
00650 |
|
LD |
H, (IX+1) |
;B HL - адрес звезды. |
00660 |
|
CP |
8 |
; Конец жизни? |
00670 |
|
OR |
NZ, N3 |
; Нет. |
00680 |
|
LD |
|
A, #F |
|
|
|
00690 |
|
AND |
|
(IX+2) |
|
|
|
00700 |
|
LD |
|
(IX+2),А |
|
|
Время вспышки. |
00710 |
|
LD |
|
A,OUTB |
|
|
|
00720 |
N3 |
CP |
|
9 |
|
|
Звезда сгорела? |
00730 |
|
JR |
|
NZ, N4 |
|
|
Нет. |
00740 |
|
LD |
|
(HL),DARK |
|
|
Погасить звезду. |
00750 |
|
CALL |
|
INIT |
|
Инициализировать новую звезду. |
00760 |
|
JR |
|
N5 |
|
; |
|
00770 |
N4 |
LD |
|
(HL),A |
|
; |
|
00780 |
N5 |
LD |
|
DE,4 |
|
|
|
00790 |
|
ADD |
|
IX, DE |
|
; |
|
00800 |
|
LD |
|
A,(LASTK) |
|
|
|
00810 |
|
OR |
|
A |
|
|
Нажата клавиша? |
00820 |
|
JR |
|
Z,N6 |
|
|
Нет. |
00830 |
|
CALL |
|
FPSC |
|
|
Иначе - восстановить экран. |
00840 |
|
RST |
|
#28 |
|
|
Подпрограмма "ВЕЕР .25,25". |
00850 |
|
DEFB |
|
#A2,#A2,MULT |
|
|
00860 |
|
DEFB |
|
#31,#A4,#A4 |
|
|
00870 |
|
DEFB |
|
MULT,MULT |
, ECAL |
|
|
00880 |
|
CALL |
|
BEEP |
|
|
3вук, восстановить бордюр. |
00890 |
|
XOR |
|
A |
|
|
Сброс флага "С". |
00900 |
|
LD |
|
(TIME),A |
|
|
|
00910 |
|
RET |
|
|
|
|
Выход со сброшенным флагом "С" |
00920 |
N6 |
DJNZ |
|
ONE |
|
|
Повтор для каждой звезды. |
00930 |
|
JR |
|
ALL |
|
|
Повторять до нажатия клавиши. |
00940 |
; Подпрограммы |
сохранения и |
восстановления экрана. |
00950 |
STSC |
LD |
|
HL,SCRA |
|
|
|
00960 |
|
LD |
|
DE,BUSC |
|
|
|
00970 |
|
JR |
|
MOVE |
|
|
|
00980 |
FPSC |
LD |
|
HL,BUSC |
|
|
|
00990 |
|
LD |
|
DE,SCRA |
|
|
|
01000 |
MOVE |
LD |
|
BC,SCRL |
|
|
|
01010 |
|
LDIR |
|
|
|
|
|
01020 |
|
RET |
|
; |
|
|
|
01030 |
; Подпрограмма |
инициализ ации |
одного |
элемента массива |
01040 |
; на |
входе - в |
IX |
адрес элемента массива. |
01050 |
INIT |
PUSH |
|
ВС |
|
|
|
01060 |
|
LD |
|
ВС,769 |
|
|
|
01070 |
|
CALL |
|
CALC |
|
|
Случайное число 0...7 68. |
01080 |
|
LD |
|
HL,ATTR |
|
|
Адрес файла атрибутов. |
01090 |
|
ADD |
|
HL, BC |
|
|
Адрес звезды. |
01100 |
|
LD |
|
(IX),L |
|
|
|
OHIO |
|
LD |
|
(IX+1) , H |
|
|
|
01120 |
|
LD |
|
ВС,250 |
|
|
|
01130 |
|
CALL |
|
CALC |
|
|
|
01140 |
|
INC |
|
С |
|
|
|
01150 |
|
LD |
|
(IX+2),С |
|
Длительность фазы жизни. |
01160 |
|
LD |
|
(IX+3),1 |
|
|
Начальная яркость. |
01170 |
|
POP |
|
ВС |
|
|
|
01180 |
|
RET |
|
|
|
|
|
01190 |
; Подпрограмма, |
выполняющая |
функцию |
бейсик-оператора |
01200 |
; LET |
BC=INT(BC*RND) |
|
|
|
01210 |
; на |
входе - в |
ВС |
максимальное значение случайного числа |
01220 |
; на |
выходе - в |
ВС |
случайное |
число. |
|
|
01230 |
CALC |
CALL |
|
STBC |
|
|
ВС в калькулятор. |
01240 |
|
LD |
|
ВС,1 |
|
|
Длина команды RND. |
01250 |
|
LD |
|
DE,RND |
|
|
Адрес команды. |
01260 |
|
CALL |
|
STST |
|
|
Параметры строки в калькулятор |
01270 |
|
LD |
|
B, VAL |
|
|
|
01280 |
|
RST |
|
#28 |
|
|
|
01290 |
|
DEFB |
|
VAL,MULT |
|
|
|
01300 |
|
DEFB |
|
INT,ECAL |
|
|
|
01310 |
|
CALL |
|
FPBC |
|
|
Число в ВС. |
01320 |
|
PUSH |
BC |
|
01330 |
|
CALL |
SETW |
|
01340 |
|
POP |
BC |
|
01350 |
|
RET |
|
|
01360 |
RND |
DEFB |
165 |
Код токена RND |
01370 |
ARR |
DEFS |
NST |
Массив описаний. |
01380 |
|
DEFS |
NST |
Буфер экрана. |
01390 |
|
DEFS |
NST |
|
01400 |
|
DEFS |
NST |
|
01410 |
BUSC |
DEFS |
SCRL |
|
01420 |
; Пример |
использования процедуры. |
|
01430 |
|
ENT |
|
|
01440 |
OPEN |
EQU |
#1601 |
Процедура "Открыть канал". |
01450 |
CLS |
EQU |
#D6B |
Процедура "Очистить экран". |
01460 |
EXAMPL |
LD |
A, 2 |
|
01470 |
|
CALL |
OPEN |
|
01480 |
|
CALL |
CLS |
|
01490 |
|
LD |
A, 2 |
|
01500 |
|
CALL |
OPEN |
|
01510 |
UN |
XOR |
A |
|
01520 |
|
LD |
(TIME),A |
Инициализация процедуры. |
01530 |
|
RES |
5,(IY+1) |
Сбросить готовность клавиатуры |
01540 |
WAIT |
CALL |
STARS |
Контроль времени. |
01550 |
|
OR |
NC,IIN |
Если был дежурный режим. |
01560 |
|
BIT |
5,(IY+1) |
Нажата клавиша? |
01570 |
|
OR |
Z,WAIT |
Нет. |
01580 |
|
LD |
A,(LASTK) |
Иначе в А - код клавиши. |
01590 |
|
CP |
32 |
|
01600 |
|
RET |
C |
Выход, если это упр.символ. |
01610 |
|
RST |
#10 |
Иначе - печать символа |
01620 |
|
JR |
IIN |
и зацикливание. |
Start |
of object: #9C40 |
(40000) |
|
Length |
: #1C82 |
(07298) |
|
Executes |
: #B899 |
(47957} |
|
После набора программы и ее ассемблирования, запустите процедуру EXAMPL и наберите с ее помощью на экране произвольный текст (не используя клавишу ENTER и другие управляющие клавиши). Не трогайте клавиатуру в течение трех минут (для контрольного запуска это время можно уменьшить, изменив время TIM - замените число 35 на 5 в строке 220 листинга, это уменьшит время ожидания до 30 секунд). Понаблюдайте за работой процедуры>1 и затем нажмите любую клавишу. Информация на экране восстановится, раздастся звуковой сигнал, восстановится цвет бордюра. Выход из EXAMPL - клавиша ENTER.
Комментарий ИНФОРКОМа.
Как обычно, для тех, кто не владеет ассемблером, приводим полный дамп кодового блока. Он состоит из двух частей, между которыми находится буфер. Для демонстрации можете сохранить их как два разных файла: SAVE "starsl" CODE 40000,245 SAVE "stars2" CODE 40257,41