Нестандартные загрузчики
Многие читатели обращаются к пак с просьбой опубликовать ин формацию о нестандартной загрузчике, в которой загрузка заставки на экран происходит по знакоместам а любой предварительно задан ной последовательности: при этом по экрану как бы "бегает " курсор, который прорисовывает картинку.
Сегодня мы располагаем такими материалами и можем поделиться ими с нашими читателями в этой подборке.
Загрузка экрана "бегающим курсором"
© Смоленцев А.В., г. Белебей, Башкирия, 1994.
Идея этого способа загрузки взята мною из программы N.O.M.A.D. фирмы OCEAN, однако загрузчик эк рана я подвергнул существенным изменениям в лучшую, я надеюсь, сторону.
Для начала о самом экранном файле нового формата. Данные о загружаемой картинке хранятся в следующем формате:
Байт 0 - младший байт адреса верхней пиксельной линии загружаемого знакоместа.
Байт 1 - старший байт адреса верхней пиксельной линии загружаемого знакоместа.
Байт 2-9 - последовательно восемь линий знакоместа сверху вниз.
Байт 10 - атрибут данного знакоместа.
Далее следует информация о другом знакоместе в том же порядке.
Таким образом, с помощью специального загрузчика можно загружать знакоместа экрана в произвольном порядке, причем в самом загрузчике отсутствуют какие-либо параметры загружаемого экранного файла, то есть загрузчик является полностью универсальным.
При таком способе загрузки ин формация о каждом знакоместе занимает 11 байтов и для полностью заполненного экрана файл будет длиной 11*32*24=8448 байтов. Очевидно, что данный способ загрузки может выиграть в скорости загрузки, если на картинке есть какие-то "не закрашенные" области.
Теперь листинг нестандартного загрузчика на Ассемблере (опять-таки с адреса 40000 только для примера).
00010 |
|
ORG |
40000 |
00020 |
|
ENT |
|
00030 |
|
CALL |
BEGIN |
00040 |
|
EI |
|
00050 |
|
RET |
|
00060 |
BEGIN |
DI |
|
00070 |
|
LD |
A, #0F |
00080 |
|
OUT |
(#FE),A |
00090 |
|
IN |
A,(#FE) |
00100 |
|
RRA |
|
00110 |
|
AND |
#20 |
00120 |
|
OR |
#02 |
00130 |
|
LD |
C,A |
00140 |
|
CP |
A |
00150 |
BREAK |
RET |
NZ |
00160 |
START |
CALL |
EDGE1 |
00170 |
|
JR |
NC,BREAK |
00180 |
|
LD |
HL,#0415 |
00190 |
WAIT |
DJNZ |
WAIT |
00200 |
|
DEC |
HL |
00210 |
|
LD |
A, H |
00220 |
|
OR |
L |
00230 |
|
JR |
NZ,WAIT |
00240 |
|
CALL |
EDGE2 |
00250 |
|
JR |
NC,BREAK |
00260 |
LEADER |
LD |
B,#9C |
00270 |
|
CALL |
EDGE2 |
00280 |
|
JR |
NC,BREAK |
00290 |
|
LD |
A, #C6 |
00300 |
|
CP |
B |
00310 |
|
JR |
NC,START |
00320 |
|
INC |
H |
00330 |
|
JR |
NZ,LEADER |
00340 |
SYNC |
LD |
B, #C9 |
00350 |
|
CALL |
EDGE1 |
00360 |
|
JR |
NC,BREAK |
00370 |
|
LD |
A, B |
00380 |
|
CP |
#D4 |
00390 |
|
JR |
NC,SYNC |
00400 |
|
CALL |
EDGE1 |
00410 |
|
RET |
NC |
00420 |
|
LD |
A, C |
00430 |
|
XOR |
#03 |
00440 |
|
LD |
C,A |
00450 |
|
LD |
B, #B0 |
00460 |
|
CALL |
MARKER |
00470 |
LOOP |
CALL |
PLACE |
00480 |
|
RET |
NC |
00490 |
|
JR |
LOOP |
00500 |
PLACE |
LD |
B, #B0 |
00510 |
|
CALL |
MARKER |
00520 |
|
LD |
L, E |
00530 |
|
LD |
b, #B0 |
00540 |
|
CALL |
MARKER |
00550 |
|
RET |
NC |
00560 |
|
LD |
H, E |
00570 |
|
LD |
D, #08 |
00580 |
|
LD |
b, #B0 |
00590 |
GRAF |
CALL |
MARKER |
00600 |
|
RET |
NC |
00610 |
|
LD |
(HL),E |
00620 |
|
INC |
H |
00630 |
|
DEC |
D |
00640 |
|
LD |
B, #B1 |
00650 |
|
JR |
NZ,GRAF |
00660 |
|
LD |
A, H |
00670 |
|
SUB |
#08 |
00680 |
|
RRA |
|
00690 |
|
RRA |
|
00700 |
|
RRA |
|
00710 |
|
AND |
#03 |
00720 |
|
OR |
#58 |
00730 |
|
LD |
H, A |
00740 |
|
LD |
B, #B2 |
00750 |
|
CALL |
MARKER |
00760 |
|
LD |
(HL),E |
00770 |
|
RET |
|
00780 |
MARKER |
LD |
E, #01 |
00790 |
LD8BIT |
CALL |
EDGE2 |
00800 |
|
RET |
NC |
00810 |
|
LD |
A, #CB |
00820 |
|
CP |
B |
00830 |
|
RL |
E |
00840 |
|
LD |
B, #B0 |
00850 |
|
JR |
NC,LD8BIT |
00860 |
|
RET |
|
00870 |
EDGE2 |
CALL |
EDGE1 |
00880 |
|
RET |
NC |
00890 |
EDGE1 |
LD |
A, #16 |
00900 |
DELAY |
DEC |
A |
00910 |
|
JR |
NZ,DELAY |
00920 |
|
AND |
A |
00930 |
SAMPLE |
INC |
B |
00940 |
|
RET |
Z |
00950 |
|
LD |
A, #7F |
00960 |
|
IN |
A,(#FE) |
00970 |
|
RRA |
|
00980 |
|
RET |
NC |
00990 |
|
XOR |
C |
01000 |
|
AND |
#20 |
01010 |
|
JR |
Z, SAMPLE |
01020 |
|
LD |
A, C |
01030 |
|
CPL |
|
01040 |
|
LD |
C,A |
01050 |
|
AND |
#07 |
01060 |
|
OR |
#08 |
01070 |
|
OUT |
(#FE),A |
01080 |
|
SCF |
|
01090 |
|
RET |
|
Start |
of object: #9C40 |
(40000) |
Length: |
#OOB6 |
(00182) |
Executes: |
# 9C4 0 |
(40000) |
Большая, часть программы соответствует стандартной процедуре LD_BYTES, которая находится в ПЗУ с адреса #0556 (01366).
Для более глубокого понимания процессов, происходящих при загрузке блока кодов с магнитофона, мы можем посоветовать взять (или .заказать у нас) подшивку ZX-РЕВЮ) за 1991. Там, в ' 4-5 на стр. 71-79, подробно разобраны процедуры работы с магнитофоном. Загляните также и в подшивку ZX-РЕВЮ за 1993 год - на стр. 13-20 Вы найдете подробное описание стандартной процедура загрузки.
Используемые регистры: А,В,С - аналогично процедуре LD_BYTES.
D - счетчик цикла для загрузки 8 пиксельных линий знакоместа.
Е - используется вместо регистра L в LD_BYTES, в нем "собирается" по битам принимаемый с ленты байт.
HL - хранение адреса в области экрана, куда будут перебрасываться данные из регистра Е.
В программу можно внести несколько изменений по своему усмотрению. Если удалить строку 980, программа перестанет реагировать на клавишу BREAK. Если Вы не хотите, чтобы на бордюре при загрузке мелькали полосы, нужно уда лить строки 70, 80, 120, 420-440, 1050-1070.
В приведенной программе отсутствует контроль правильности считывания, так что если Вы попробуете загрузить этим загрузчиком не заранее подготовленный экранный файл, то результат будет непредсказуемый - как правило это приводит к зависанию системы, так как загружается неизвестно что, и неизвестно куда.
Шестнадцатеричный дамп загрузчика с контрольными суммами:
9C4 0 |
CD |
45 |
9C |
FB |
C9 |
F3 |
3E |
0F |
8E |
9C4 8 |
D3 |
FE |
DB |
FE |
1F |
E 6 |
20 |
F 6 |
A9 |
9C50 |
02 |
4F |
BF |
C0 |
CD |
D8 |
9C |
30 |
2D |
9C58 |
FA |
21 |
15 |
04 |
10 |
FE |
2B |
7C |
DD |
9C60 |
B5 |
20 |
F9 |
CD |
D4 |
9C |
30 |
EB |
22 |
9C68 |
06 |
9C |
CD |
D4 |
9C |
30 |
E4 |
3E |
35 |
9C7 0 |
C6 |
B8 |
30 |
E0 |
24 |
20 |
F1 |
06 |
D5 |
9C7 8 |
C9 |
CD |
D8 |
9C |
30 |
D5 |
78 |
FE |
99 |
9C80 |
D4 |
30 |
F4 |
CD |
D8 |
9C |
D0 |
79 |
9E |
9C88 |
EE |
03 |
4F |
06 |
B0 |
CD |
C4 |
9C |
47 |
9C90 |
CD |
96 |
9C |
D0 |
18 |
FA |
06 |
B0 |
C3 |
9C98 |
CD |
C4 |
9C |
6B |
06 |
B0 |
CD |
C4 |
13 |
9CA0 |
9C |
D0 |
63 |
16 |
08 |
06 |
B0 |
CD |
AC |
9CA8 |
C4 |
9C |
D0 |
73 |
24 |
15 |
06 |
B1 |
D7 |
9CB0 |
20 |
F5 |
7C |
D 6 |
08 |
1F |
1F |
1F |
18 |
9CB8 |
E 6 |
03 |
F 6 |
58 |
67 |
06 |
B2 |
CD |
77 |
9CC0 |
C4 |
9C |
73 |
C9 |
1E |
01 |
CD |
D4 |
B8 |
9CC8 |
9C |
D0 |
3E |
CB |
B8 |
CB |
13 |
06 |
75 |
9CD0 |
B0 |
30 |
F3 |
C9 |
CD |
D8 |
9C |
D0 |
19 |
9CD8 |
3E |
16 |
3D |
20 |
FD |
A7 |
04 |
C8 |
95 |
9CE0 |
3E |
7F |
DB |
FE |
1F |
D0 |
A9 |
E 6 |
90 |
9CE8 |
20 |
28 |
F3 |
79 |
2F |
4F |
E 6 |
07 |
A3 |
9CF0 |
F 6 |
08 |
D3 |
FE |
37 |
C9 |
00 |
00 |
5B |
Итак, предположим, что Вы набрали данный загрузчик, ассемблировали его и выгрузили на ленту. Тут появляется вторая проблема: а что этим загрузчиком загружать? Ведь ему требуется специальный блок кодов на ленте с закодированной информацией о порядке загрузки и содержимом знакомест экрана, эту проблему поможет успешно решить небольшая Бейсик-программа, которая из стандартного экрана, не без Вашего участия, сформирует закодированный блок. Эта скромная программа, приведенная ниже, не слишком удобна в управлении и имеет минимальный набор сервисных возможностей. Однако их вполне хватит, чтобы отладить загрузчик и закодировать один-другой экран. А дальше можно расширить её в соответствии со своими желаниями и возможностями.
Конечно, можно было бы сразу делать кодирующую программу в кодах и с шикарным сервисом, но вся прелесть Бейсика, несмотря на его "неповоротливость", заключается в том, что набрать, а тем более, отладить килобайт Бейсика гораздо легче и быстрее, чем 200 байтов машинного кода. А когда в Бейсике полностью отмакетирована и выяснена логика работы, можно заняться и машинным кодом. 10 PAPER 0: INK 7: BORDER 0: CLEAR 3 9999 20 LET a=22528: LET b=55000 30 LOAD "" SCREEN$ 40 LET a$=INKEY$
50 LET a=a-(a$="6" AND a>22528)+(a$="7" AND a<23295)-32*(a$="9" AND
a>22559)+32*(a$="8" AND a< 23264) 60 LET at=PEEK a: POKE a,0: PAUSE 5: POKE a,127: PAUSE 5: POKE a,at 70 IF a$="0" THEN GO TO 200
80 IF a$=" " THEN LET b=b-11: POKE a,at: BEEP 1,0 90 IF a$="1" THEN GO TO 300 100 GO TO 40
200 BEEP .1,30: LET ad=a-2 5 60-17 92*(a<2 3040)-1792*(a<22784) 210 LET ah=INT (ad/256): LET al=ad-256*ah 220 POKE b,al: POKE (b+l),ah
230 FOR n=0 TO 7: POKE (b+n+2), PEEK (ad+256*n): NEXT n 240 POKE b+10,at: LET b=b+11: LET at=at 250 POKE a,0: GO TO 4 0 300 INPUT "Filename : ";a$ 310 SAVE a$ CODE 55000, (b-55000) Назначение переменных в программе: а - адрес атрибута текущего знакоместа; b - первый свободный адрес создаваемого файла; at - значение атрибута текущего знакоместа; ad - адрес первой линии текущего знакоместа;
al, ah - младший и старший байты адреса верхней пиксельной линии знакоместа; atl - значение атрибута текущего знакоместа для временного хранения.
Назначение строк программы: 40-100 - определение нажатой клавиши;
50 - пересчет адреса атрибута знакоместа в зависимости от перемещения курсора; 60 - печать курсора в текущем знакоместе; 80 - реакция на нажатие "пробела";
200-250 - пересылка данных из текущего знакоместа в создаваемый файл в нужном формате.
После запуска с начальной строки программа ждет первый, встретившийся на ленте файл? и попытается загрузить его в экран. После успешной загрузки картинки в левом верхнем углу появится курсор, который мигает то белым, то черным, то - цветом данного знакоместа. Курсор перемещается клавишами SINCLAIR-джойстика. При нажатии на "огонь" (при этом раздается короткий звуковой сигнал), содержимое знакоместа экрана запишется в буфер, а данное знакоместо станет черным. Так Вам предлагается последовательно закодировать весь экран. Последнюю запись можно аннулировать нажатием SPACE. Нажатием "1" можно выгрузить созданный файл на ленту. Загрузка экрана будет происходить в том порядке, в каком Вы производили запись знакомест в буфер.
Как уже говорилось, программа предназначена для отработки алгоритма, поэтому она имеет некоторые ограничения.
1. Если нажать "огонь" два раза на одном знакоместе, при загрузке здесь будет черный квадрат.
2. Если нажать на "пробел" два раза подряд. Вы отмените две последние записи, но на экране ничего не заметите.
3. Если Вы хотите отменить последнюю запись, установите курсор на это знакоместо, иначе будут изменены атрибуты не там, где надо.
4. Имя файла, естественно, не должно быть более 10 символов; при записи готового файла заголовок нужно пропустить.
В заключение хочу добавить, что загрузчик запускается с начального адреса и является неперемещаемой программой, т.е. должен работать только в тех адресах, куда был ассемблирован. Например, если Вы в 10 строке листинга 1 поставите: 00010 ORG 65000
то запускать загрузчик нужно следующим образом:
10 CLEAR 64999: LOAD "loader" CODE: RANDOMIZE USR 65000
А теперь предлагаем небольшое, но очень "емкое" письмо другого нашего корреспондента на ту же тему. Обратите на него, пожалуйста, вникание - едва ли Вы встретите загрузчик короче!
© Павел Бобровников, г. Челябинск, 1994.
Мое письмо я в большей степени посвящаю Спектруму и магнитофону (я думаю, меня поймут: мы все начинали с него). Привожу программу, предназначенную для загрузки кодовых блоков при помощи "бегающего курсора" в произвольном порядке, в зависимости от кодирования картинки.
00010 |
ORG |
40000 |
00020 |
ENT |
|
00030 |
LD |
IX,M2+2 |
00040 |
LD |
DE,2 |
00050 |
XOR |
A |
00060 |
SUB |
1 |
00070 |
EX |
AF,AF' |
00080 |
DI |
|
00090 |
CALL |
#0562 |
00100 M2 |
LD |
IX,0 |
00110 |
EXX |
|
00120 |
LD |
B, 8 |
00130 M1 |
EXX |
|
00140 |
INC |
E |
00150 |
CALL |
#05A9 |
00160 |
DEC |
IX |
00170 |
DEFB |
#DD |
00180 |
DEFB |
#24 |
00190 |
EXX |
|
00200 |
DJNZ |
M1 |
00210 |
DEFB |
#DD |
00220 |
DEFB |
#7C |
00230 |
RRCA |
|
00240 |
RRCA |
|
00250 |
RRCA |
|
00260 |
DEC |
A |
00270 |
AND |
#03 |
00280 |
OR |
#58 |
00290 |
DEFB |
#DD |
00300 |
DEFB |
#67 |
00310 |
EXX |
|
00320 |
INC |
E |
00330 |
CALL |
#05A9 |
00340 |
LD |
IX,M2+2 |
00350 |
LD |
E, 2 |
00360 |
CALL |
#05A9 |
00370 |
DEC |
E |
00380 |
INC |
E |
00390 |
JR |
Z,M2 |
00400 |
LD |
A,(M2+2) |
00410 |
CP |
1 |
00420 |
JP |
#053F |
Start of object: #9C40 (40000) Length: #0048 (00072)
Executes: #9C40 (40000)
Пользователю требуется только набрать этот кусок текста в ассемблере и запустить его с того адреса, куда он ассемблировался. Еще замечу, чтобы загрузка выглядела солидней, замените в строке 90 CALL #0562 на CALL #056A - это вызовет изменение цвета полос.
Комментарий ИНФОРКОМА.
Не скроем, длина загрузчика нас просто покорила. Однако прежде, чем давать комментарии, проведем некоторые изменения. Обращаем Ваше внимание на строки 170-180, 210-220, 290-300. Что бы это могло означать? Да ни что иное, как недокументированные команды с половинками индексного регистра IX! В свое время Игорь Комаров из Иркутска (см. ZX-PEBIO-94, № 2, стр. 56-57) предлагал способ, как включать в ассемблерный текст такие команды. Воспользуемся этим приемом. Заодно сделаем замену цвета бордюрных полос, предложенную автором письма. Кстати, и без того короткую программу можно сократить еще на пару байтов, если вместо использования альтернативного набора регистров, сохранять данные B на стеке. Изменению подверглись строки 130 и 190, благодаря чему удалось исключить строки 110 и 310. Теперь несколько видоизмененный листинг программы:
00010 |
|
ORG |
40000 |
00020 |
|
ENT |
|
00030 |
|
LD |
IX,M2+2 |
00040 |
|
LD |
DE,2 |
00050 |
|
XOR |
A |
00060 |
|
SUB |
1 |
00070 |
|
EX |
AF,AF' |
00080 |
|
DI |
|
00090 |
|
CALL |
#056A |
00100 |
M2 |
LD |
IX,0 |
00120 |
|
LD |
B, 8 |
00130 |
M1 |
PUSH |
BC |
00140 |
|
INC |
E |
00150 |
|
CALL |
#05A9 |
00160 |
|
DEC |
IX |
00170 |
|
DEFB |
#DD |
00180 |
|
INC |
H |
00190 |
|
POP |
BC |
00200 |
|
DJNZ |
M1 |
00210 |
|
DEFB |
#DD |
00220 |
|
LD |
A, H |
00230 |
|
RRCA |
|
00240 |
|
RRCA |
|
00250 |
|
RRCA |
|
00260 |
|
DEC |
A |
00270 |
|
AND |
#03 |
00280 |
|
OR |
#58 |
00290 |
|
DEFB |
#DD |
00300 |
|
LD |
H, A |
00320 |
|
INC |
E |
00330 |
|
CALL |
#05A9 |
00340 |
|
LD |
IX,M2+2 |
00350 |
|
LD |
E, 2 |
00360 |
|
CALL |
#05A9 |
00370 |
|
DEC |
E |
00380 |
|
INC |
E |
00390 |
|
JR |
Z,M2 |
00400 |
|
LD |
A,(M2+2 |
00410 |
|
CP |
1 |
00420 |
|
JP |
#053F |
Start |
of |
object: # 9C4 0 |
(40000) |
Length: |
#0046 |
(00070) |
Executes: |
: # 9C4 0 |
(40000) |
В строках 180, 220 и 300 речь идет о старшей байте регистра IX (High).
Теперь некоторые комментарии. Раскладку кодового блока Вы уже знаете из предыдущей статьи. Итак, начинается загрузка. Вначале в регистр IX задается адрес того места в самой программе, где находится число, загружаемое в дальнейшем в регистр IX (строка 100 - пока что там ноль), а длина загружаемого блока в DE - два байта, то есть в строку 100 загрузится адрес первой линии загружаемого знакоместа экрана, далее (в строке 120 организуется цикл из 8 повторений для загрузки 8 пиксельных линий (байтов) знакоместа. Команда в строке 140 каждый раз обеспечивает единицу в регистре DE - число загружаемых процедурой #05 А9 байтов в строке 150. Так как каждый следующий байт знакоместа имеет адрес на 256 больший, чем предыдущий, то здесь то и удобно оказалось увеличивать старший байт регистра IX, определяющего адрес загрузки для процедуры #05 А9 (строки 170-180), вернув предварительно исходное (до загрузки байта процедурой #05А9) значение регистра IX в строке 160. После загрузки всех 8 байтов знакоместа в строках 210-300 рассчитывается адрес атрибутов этого знакоместа (результат - тоже в IX), а строка 320 обеспечивает единицу в регистре DE для загрузки 1 байта атрибутов строкой 330.
В строке 340 начинается загрузка следующего знакоместа. Как и в начале программы, в IX опять заносится пара ячеек программы, куда будет загружено 2 байта, определяющие следующее знакоместо, затем в регистр Е записывается двойка, но так как в D - ноль, то в DE получается 2. Затем все повторяется со следующей группой из 11 байтов.
В конце программа переходит на процедуру завершения загрузки SA/LD-RET (строка 420), как это сделала бы обычная LD-BYTES (#0556).
В заключение - дамп второго (более короткого) варианта процедуры загрузки.
9C4 0 |
DD |
21 |
51 |
9C |
11 |
02 |
00 |
AF |
89 |
9C4 8 |
D 6 |
01 |
08 |
F3 |
CD |
6A |
05 |
DD |
CF |
9C50 |
21 |
00 |
00 |
06 |
08 |
C5 |
1C |
CD |
C9 |
9C58 |
A9 |
05 |
DD |
2B |
DD |
24 |
C1 |
10 |
7C |
9C60 |
F4 |
DD |
7C |
0F |
0F |
0F |
3D |
E 6 |
99 |
9C68 |
03 |
F 6 |
58 |
DD |
67 |
1C |
CD |
A9 |
2B |
9C7 0 |
05 |
DD |
21 |
51 |
9C |
1E |
02 |
CD |
E9 |
9C7 8 |
A9 |
05 |
1D |
1C |
28 |
D1 |
3A |
51 |
7F |
9C80 |
9C |
FE |
01 |
C3 |
3F |
05 |
00 |
00 |
BE |
Дополнение ИНФОРКОМА.
Мы думаем, не будет преувеличением сказать, что этот прекрасный способ загрузки, является наиболее эффектным из всех типов нестандартных загрузчиков. Ко всему прочему здесь добавляется творческий момент на этапе кодирования блока-экрана - каждый автор может сделать эту часть работы по-своему для одного и того же экрана, и эффект при этом будет совершенно различным. Жалко только, что в связи с появлением дисководов, этот способ загрузки вынужден отправляться на пенсию. Не в силах смириться с этим, мы, как смогли, попытались исправить это положение.
Идея такая. При адаптации программы под диск надо сохранить закодированный блок-экран в том виде, в каком он был для магнитофонного варианта программы. А загружать его будет псевдо-загрузчик ("Pseudo-Loader"), имитирующий загрузку с магнитофона, сохраняя последовательность вывода знакомест на экран (только, естественно, с увеличенной скоростью). Сейчас мы предлагаем такой псевдо-загрузчик.
00001 |
; |
(С) ALANSOFT |
|
00002 |
; |
"Pseudo |
-Loader" |
|
00010 |
|
ORG |
40000 |
|
00020 |
|
ENT |
|
|
00030 |
WAIT |
EQU |
#0600 ; |
Задержка. |
00040 |
BEG |
CALL |
#007C ; |
Эта часть служит для |
00050 |
|
DEC |
SP ; |
привязки к адресу |
00060 |
|
DEC |
SP ; |
загрузки блока кодов. |
00070 |
|
POP |
IX ; |
В результате в IX |
00080 |
|
LD |
BC,END-BEG-1 |
получим адрес, |
00090 |
|
ADD |
IX, ВС ; |
следующий за END. |
00100 |
|
LD |
DE,0 ; |
Здесь будет задана длина |
00110 |
LOOP |
LD |
L, (IX) |
Начало основного цикла: |
00120 |
|
INC |
IX ; |
|
00130 |
|
LD |
H, (IX) |
в IX - текущий адрес |
00140 |
|
INC |
IX ; |
в закодированном |
00150 |
|
LD |
В,8 ; |
блоке-экране; |
00160 |
L1 |
LD |
A, (IX) |
|
00170 |
|
LD |
(HL),A |
B HL - адрес в |
00180 |
|
INC |
H ; |
дисплейном файле. |
00190 |
|
INC |
IX |
|
00200 |
|
DJNZ |
L1 ; |
|
00210 |
|
LD |
A, H ; |
Расчет |
00220 |
|
SUB |
8 |
адреса |
00230 |
|
RRA |
|
в |
00240 |
|
RRA |
|
файле |
00250 |
|
RRA |
|
атрибутов; |
00260 |
|
AND |
#03 ; |
результат |
00270 |
|
OR |
#58 ; |
расчета |
00280 |
|
LD |
H, A ; |
в регистре HL. |
00290 |
|
LD |
A, (IX) |
|
00300 |
|
LD |
(HL),A |
|
00310 |
|
INC |
IX ; |
|
00320 |
|
LD |
BC,WAIT |
Пауза |
00330 |
L2 |
DEC |
BC |
|
00340 |
|
LD |
A, B |
;Проверка |
00350 |
|
OR |
C |
;содержимого BC |
00360 |
|
JR |
NZ, L2 |
;на достижение нуля. |
00370 |
|
LD |
B, 11 |
;Переходим к следующему знакоместу |
00380 |
L3 |
DEC |
DE |
;уменьшение счетчика на 11. |
00390 |
|
LD |
A, D |
; Проверка содержимого BC |
00400 |
|
OR |
E |
;на достижений нуля; |
00410 |
|
RET |
Z |
;выход из программы, |
00420 |
|
DJNZ |
L3 |
;если ноль достигнут. |
00430 |
END |
JR |
LOOP |
;Иначе - повтор основного цикла. |
Start |
of |
object: # 9C4 0 |
(40000) |
|
Length: |
#0047 |
(00071) |
|
Executes: |
# 9C4 0 |
(40000) |
|
Дамп блока кодов:
9C4 0 |
CD |
7C |
00 |
3B |
3B |
DD |
E1 |
01 |
5A |
9C4 8 |
44 |
00 |
DD |
09 |
11 |
00 |
00 |
DD |
FC |
9C50 |
6E |
00 |
DD |
23 |
DD |
66 |
00 |
DD |
7A |
9C58 |
23 |
06 |
08 |
DD |
7E |
00 |
77 |
24 |
1B |
9C60 |
DD |
23 |
10 |
F7 |
7C |
D6 |
08 |
1F |
7C |
9C68 |
1F |
1F |
E6 |
03 |
F6 |
58 |
67 |
DD |
BD |
9C7 0 |
7E |
00 |
77 |
DD |
23 |
01 |
00 |
06 |
08 |
9C7 8 |
0B |
78 |
B1 |
20 |
FB |
06 |
0B |
1B |
8F |
9C80 |
7A |
B3 |
C8 |
10 |
FA |
18 |
C8 |
00 |
FB |
Теперь о том, как же пользоваться псевдо-загрузчиком.
Во-первых, приведенный блок кодов "Pseudo-Loader" является релоцируемым, хотя для примера стартовый адрес равен 40000. После ассемблирования Вы можете загружать его в любое место и запускать с адреса загрузки.
Во вторых, запускаться он дол жен только будучи "присоединенным" к закодированному блоку-экрану, который располагается сразу же за 71 байтом самого псевдо-загрузчика.
В-третьих, псевдо-загрузчик (как и его прообраз) универсален: никакой предварительной настройки для конкретного закодированного блока-экрана не требуется. Длина последнего заносится В блок кодов автоматически при присоединении к псевдо-загрузчику закодированного блока-экрана.
Теперь о том, как это присоединение выполняется. Как известно, закодированный блок-экран на магнитной ленте не имеет заголовка. Перенесите его на дискету любым копировщиком типа ЛЕНТА-ДИСК. При этом, например, копировщик "AMCOPIER" присвоит блоку имя "*00"C0DE. Длина его, исходя из формата данных, должна быть крат на 11 - убедитесь в этом. Теперь соедините псевдо-загрузчик, имеющий длину 71 байт с закодированным блоком "*00"C0DE при помощи следующей Бейсик-программы: 10 BORDER 0: PAPER 0: INK 7: CLEAR 3 9999 20 RANDOMIZE USR 15619: REM : LOAD "pseudo" CODE 40000 30 RANDOMIZE USR 15619: REM : LOAD "*00" CODE 40071
40 LET l=PEEK 23771+256*PEEK 23772: PRINT l: POKE 40013,PEEK 23771: POKE 40014,PEEK 23772
50 RANDOMIZE USR 15619: REM : SAVE "Filename" CODE 40000, (71 + l) 60 RANDOMIZE USR 40000
В строке 20 загружается сам 71-байтовый псевдо-загрузчик, в строке 30 - закодированный блок, перенесенный с ленты, в строке 40 определяется длина закодированного блока, индицируется на экране и заносится в блок кодов псевдо-загрузчика. В строке 50 записывается готовый "саморазворачивающийся" релоцируемый модуль, его демонстрация в работе происходит в строке 60. Для другого блока-экрана поменяйте только имена файлов в Бейсик-строках 30 и 50.
Единственным параметром, который, возможно, потребуется подобрать - является задержка, определяющая скорость вывода картинки на экран. Числовое значение задержки задано двумя байтами по адресу 40054. Точнее, младший байт равен нулю, а подбирать достаточно только старший байт по адресу 40055. При этом скорости вывода может быть изменена в широчайших пределах. При значении, заданном в строке 30 листинга на ассемблере, обеспечивается вывод на экран заполненной на 80-90% картинки примерно за 7 секунд что, хотя и несколько замедляя процесс загрузки программы с диска, однако эффектно воспроизводит последовательную прорисовку картинки, как это было в магнитофонном варианте.
Мы продолжаем публиковать материалы, связанные с нестандартной загрузкой. На этот раз письма пришло от Владимира Кашникова.
Линейная загрузка экрана.
© Владимир Кашников, г. Кинель, 1994.
Загрузчик, листинг которого приводится ниже, загружает картинку плавно, линию за линией, правда длину
картинки пришлось увеличить. Конечно, это не самый: лучший из подобных загрузчиков, но зато самый простой.
(Листинги приводятся с непринципиальными изменениями ИНФОРКОМА).
00010 |
|
ORG |
40000 |
00020 |
|
ENT |
|
00030 |
|
LD |
IX,0 |
00040 |
|
LD |
DE,17 |
00050 |
|
LD |
A,0 |
00060 |
|
SCF |
|
00070 |
|
CALL |
#0556 |
00080 |
|
LD |
IX,0 |
00090 |
|
LD |
DE,1 |
00100 |
|
LD |
A,255 |
00110 |
|
SCF |
|
00120 |
|
DI |
|
00130 |
|
INC |
D |
00140 |
|
EX |
AF,AF' |
00150 |
|
DEC |
D |
00160 |
|
CALL |
#056A |
00170 |
|
LD |
HL,16384 |
00180 |
|
LD |
B, 3 |
00190 |
LK |
PUSH |
BC |
00200 |
|
PUSH |
HL |
00210 |
|
LD |
B, 8 |
00220 |
KL |
PUSH |
BC |
00230 |
|
PUSH |
HL |
00240 |
|
PUSH |
HL |
00250 |
|
POP |
IX |
00260 |
|
LD |
B, 8 |
00270 |
ST |
PUSH |
BC |
00280 |
|
LD |
DE,32 |
00290 |
|
PUSH |
HL |
00300 |
|
PUSH |
IX |
00310 |
|
PUSH |
DE |
00320 |
|
LD |
IX,0 |
00330 |
|
LD |
DE,1 |
00340 |
|
CALL |
#05A9 |
00350 |
|
POP |
DE |
00360 |
|
POP |
IX |
00370 |
|
CALL |
#05A9 |
00380 |
|
POP |
HL |
00390 |
|
INC |
H |
00400 |
|
PUSH |
HL |
00410 |
|
POP |
IX |
00420 |
|
POP |
BC |
00430 |
|
DJNZ |
ST |
00440 |
|
POP |
HL |
00450 |
|
LD |
DE,32 |
00460 |
|
ADD |
HL, DE |
00470 |
|
POP |
BC |
00480 |
|
DJNZ |
KL |
00490 |
|
POP |
HL |
00500 |
|
LD |
DE,2048 |
00510 |
|
ADD |
HL, DE |
00520 |
|
POP |
BC |
00530 |
|
DJNZ |
LK |
00540 |
|
LD |
IX,0 |
00550 |
|
LD |
DE,1 |
00560 |
|
CALL |
#05A9 |
00570 |
|
LD |
IX,22528 |
00580 |
|
LD |
DE,768 |
00590 |
|
CALL |
#05A9 |
00600 |
|
EI |
|
00610 |
|
RET |
|
Start |
of |
object: # 9C4 0 |
(40000) |
Length: #0074 (00116)
Executes: #9C40 (40000)
Далее - программа, конвертирующая стандартный экран в вид, пригодный для данного загрузчика:
10 LOAD "filename" CODE 16384
20 LET l=16384
30 LET k=41000
40 POKE k,0: LET k=k+1
50 FOR h=1 TO 3
60 FOR f=1 TO 8
7 0 FOR n=1 TO 8
80 POKE k,0: LET k=k+1
90 FOR m=0 TO 31
100 POKE k,PEEK (l+m)
110 LET k=k+1
120 NEXT m
130 LET l=l+256
140 NEXT n
150 LET l=l-2016
160 NEXT f
170 IF h=1 THEN LET l=18432 180 IF h=2 THEN LET l=20480 190 NEXT h
200 POKE k,0: LET k=k+1
210 FOR n=0 TO 767
220 POKE k,PEEK (22528+n)
230 LET k=k+1
240 NEXT n
250 BEEP 1,0
260 SAVE "name" CODE 41000,7106
Комментарий ИНФОРКОМА.
Загрузчик, действительно, почти самый простой, из всех, которые нам приходилось встречать. Реализовать его удалось благодаря тому, что в основе лежит использование процедуры ПЗУ #05 А9 LD-LOOP - это вершина цикла загрузки последовательности байтов. На входе в эту процедуру должны быть заданы: в IX - адрес загрузки; в DE -число загружаемых байтов. Однако, процедура используется уже тогда, когда зафиксирован и обработан пилоттон и установлена синхронизация с сигналом, поступающим с магнитофона. То есть, когда, как говорится, процесс уже пошел. Кроме того, начальный (флаговый) байт поступающей кодовой последовательности 0 или 255 - определяет тип загружаемого блока - заголовок или блок кодов. Загрузка происходит "пакетами" по 32 байта - это максимальная непрерывная последовательность, учитывающая раскладку дисплейного файла, то есть одна пиксельная линия экрана. Причем для имитации флагового байта, каждый пакет должен состоять из 33 байтов, независимо от значения этого самого фиктивного флагового байта.
Рассмотрим, как же происходит загрузка при помощи этого загрузчика. Отметим сразу, что возможно использование экранного блока кодов, как с заголовком, так и без него. Строки 30-70 (см. листинг на Ассемблере) выполняют фиктивную загрузку 17 байтов заголовка стандартной процедурой LD-BYTES. Фиктивную потому, что адрес загрузки равен нулю, то есть загрузка идет в область ПЗУ. Можно изменить строку: 00050 LD A,255
и загрузка заголовка вообще не произойдет. А если будете использовать блок кодов без заголовка, то можете взять да и удалить строки 30-70, еще более укоротив, загрузчик.
Далее. Строки 80-110 - в них идет подготовка исходных данных для загрузки блока кодов длиной 1 байт в адрес 0. Эта часть, судя по адресу в IX, как Вы понимаете, тоже является фиктивной загрузкой и нужна для синхронизации с пилоттоном и успешного начала того самого процесса. Но в этом фрагменте происходит одна нефиктивная вещь - загрузка настоящего флагового байта (255), определяющего, что загружаемый блок является не заголовком, а блоком кодов.
Собственно загрузка заданного в DE одного байта происходит при помощи вызова части процедуры LD-BYTES (строка 160) и предшествующих ей нескольких команд в строках 120-150, копирующих начальный фрагмент LD-BYTES (по адресам #0556-#0559). Суть такой замены вот в чем: исключается та часть процедуры LD-BYTES, где задается на стеке адрес завершения процедуры (#053F) для перехода на SA/LD-RET.
Итак, зафиксирован пилоттон, принят настоящий флаговый байт, он равен 255, то есть загружается блок кодов, далее начинается загрузка и, согласно условию, загружается один байт по адресу 0. При этом программа, после возврата по RET, не завершает загрузку, как это сделала бы LD-BYTES переходом на SA/LD-RET, а попадает на строку 170. А между тем, поток информации с магнитофона продолжается.
Только теперь начинается загрузка дисплейного файла. В HL начальный адрес загрузки, далее - три вложенных цикла: загрузка трех сегментов экрана по 8 строк по 8 пиксельных линий - каждая. Загрузка, как уже говорилось, происходит пакетами по 32, а точнее, по 33 байта (вместе с фиктивным флаговым байтом). Такая раскладка кодового блока предусматривается при кодировании стандартного экрана. Считывание флагового байта пакета происходит в строках 320-340 (причем, опять же, фиктивное, но оно необходимо, так как чтение флагового байта предусмотрено процедурой с точкой входа #05А9 - LD-LOOP). А считывание информационных 32 байт про исходит в строках 350-370, после чего следует переход к следующей пиксельной линии1 (адреса в HL увеличивается на 256 байтов в строке 390).
После загрузки всех 6144 байтов дисплейного файла надо загрузить файл атрибутов. Здесь загрузка выполняется аналогичным образом, только используется один пакет, так как все 768 байтов файла атрибутов идут подряд. Сначала (в строках 540-560) идет фиктивная загрузка флагового байта, (уже ясно, для чего), далее загрузка файла атрибутов (строки 570-590).
Посмотрим теперь, какой же расклад должен иметь закодированный кодовый блок-экран. 3 сегмента по 8 строк по 8 линий по 32 байта, то есть 3*8*8=192 пакета по 32 байта (в соответствующей последовательности) с предшествующими им фиктивными флаговыми байтами увеличат длину закодированного блока на 192 байта, плюс один фиктивный (нефлаговый) байт в начале блока и плюс еще один фиктивный флаговый байт, пред шествующий файлу атрибутов. Итого получается: 6912 + 192 + 2 = 7106 байтов. Такая кодировка и выполняется приведенной выше Бейсик-программой, а фиктивные байты вставляются Бейсик-строками 40, 80 и 200. причем, поскольку байты эти -фиктивные, совершенно не важно, что вы занесете в ячейки: можете задать: РОКЕ к,255 - это абсолютно ни на что не повлияет, так как значение флагового байта в память не заносится. Однако Вы можете "увидеть" процесс загрузки фиктивных байтов, задав в регистре IX, например, адрес последней ячейки атрибутов. Для этого измените строку 320: 00320 LD IX,23295
при этом получите эффект хаотичного мигания правого нижнего знакоместа экрана при загрузке картинки.
Следует сказать, что при записи кодового массива командой SAVE будет добавлен еще и настоящий флаговый байт, равный 255, определяющий, что это блок кодов, а не заголовок.
Заметим, что, несмотря на длину загружаемого файла, большую на 194 байта, чем обычный экран, сам загрузчик короче, чем аналогичные, поэтому несколько большее время при загрузке экрана компенсируется меньшим временем при загрузке самого загрузчика.
Теперь, по традиции, приводим шестнадцатеричный дамп загрузчика с контрольными суммами:
9C4 0 |
DD |
21 |
00 |
00 |
11 |
11 |
00 |
3E |
3A |
9C4 8 |
FF |
37 |
CD |
56 |
05 |
DD |
21 |
00 |
40 |
9C50 |
00 |
11 |
01 |
00 |
3E |
FF |
37 |
F3 |
65 |
9C58 |
14 |
08 |
15 |
CD |
6A |
05 |
21 |
00 |
82 |
9C60 |
40 |
06 |
03 |
C5 |
E5 |
06 |
08 |
C5 |
C2 |
9C68 |
E5 |
E5 |
DD |
E1 |
06 |
08 |
C5 |
11 |
70 |
9C7 0 |
20 |
00 |
E5 |
DD |
E5 |
D5 |
DD |
21 |
A6 |
9C7 8 |
00 |
00 |
11 |
01 |
00 |
CD |
A9 |
05 |
A1 |
9C80 |
D1 |
DD |
E1 |
CD |
A9 |
05 |
E1 |
24 |
2B |
9C88 |
E5 |
DD |
E1 |
C1 |
10 |
E0 |
E1 |
11 |
6A |
9C90 |
20 |
00 |
19 |
C1 |
10 |
D1 |
E1 |
11 |
F9 |
9C98 |
00 |
08 |
19 |
C1 |
10 |
C5 |
DD |
21 |
E9 |
9CA0 |
00 |
00 |
11 |
01 |
00 |
CD |
A9 |
05 |
C9 |
9CA8 |
DD |
21 |
00 |
58 |
11 |
00 |
03 |
CD |
7B |
9CB0 |
A9 |
05 |
FB |
C9 |
00 |
00 |
00 |
00 |
BE |
В том случае, если Вы будете использовать картинку, как блок кодов без заголовка, то набор и запуск загрузчика производите с адреса #9C4D (40013). Заметим также, что загрузчик этот - релоцируемый, возможна загрузка его под любой адрес и запуск с адреса загрузки.
В заключение, мы хотим обратить Ваше внимание на то, что существуют специальные приемы для того, чтобы избежать загрузки большого числа фиктивных флаговых байтов. Предлагаем на досуге, в качестве "зарядки для мозгов", подумать об этом. Можем только заверить Вас, что решение существует, и довольно простое, хотя и не совсем очевидное. В качестве информации к размышлению можете использовать предыдущий материал Павла Бобровникова - там тоже используется процедура с точкой входа #05A9, однако без загрузки фиктивных байтов. Если Вы "прочувствуете" принцип построения этих загрузчиков и найдете ключ к использованию процедуры #05А9, то сможете без проблем создавать загрузчики нового поколения минимальной длины. Это своего рода RAXXLA -"дорога к другим галактикам" - где Вы получаете полную свободу для загрузки чего угодно, куда угодно и в каком угодно порядке.
Можно также попробовать непосредственное использование процедуры загрузки 8 битов и формирования из них байта: LD-8-BITS (#05СА-#05Е2). Можете предусмотреть также контроль правильности считывания. В общем -пишите! А лучший вариант (или варианты) мы обязательно опубликуем в ZX-РЕВЮ в новом 1995 году.