FORUM
Как эффективнее всего освоить машинные коды? Опыт показывает, что лучше всего освоение проходит, когда берешь какую-нибудь несложную готовую программу в машинных кодах и пытаешься понять, что и как там делается. При этом неизбежно возникает вопросы: "А почему так? Может можно все это сделать по-другому?" Начинаешь пробовать сделать по-другому и выясняется, что по-другому не выходит. Тогда становится понятно, почему автор организовал программу именно так, а не иначе. Но иногда встречаются ситуации, когда приходят действительно ценные идеи. Именно потому, что "ход мысли" начинающего еще не оформился в каких-то рамках, он не знает, что "можно", а что "нельзя". И он пытается выполнить задачу по-своему, а это зачастую приводит к находке новых, оригинальных решений.
Александр Балашов из г. Конаково Тверской обл. пишет нам о том, что он начал заниматься машинными кодами совсем недавно. Исследуя программы компрессии и декомпрессии, опубликованные в "ZX-РЕВЮ" N 1-2 за 1991 г., Александр обратил внимание, что под счетчик числа одинаковых байтов используется двухбайтный регистр BC. Учитывая организацию экранной области "Спектрума", он предположил, что выгоднее, видимо, использовать один байт, так как 256 байтов перекрывают 8-ю штрихами третью часть экрана и старший байт двухбайтного регистра BC используется лишь при практически пустом экране. Число, записанное в этом регистре занимает в скомпрессированном блоке 2 байта, один из которых почти всегда в нуле.
Этот факт побудил Александра разработать свою программу компрессии, в которой под счетчик числа одинаковых байтов он использовал только регистр B. Этот вариант позволяет получать длину скомпрессированного блока на 10-20% меньшую. Лишь при почти незаполненном экране, когда длина скомпрессированного блока меньше 300-400 байтов, длина его скомпрессированной картинки равна или уступает указанному варианту компрессора. Кроме того, его вариант не приводит к сбоям, которые могут иметь место при определенных ситуациях в варианте компрессора, упомянутом выше.
Александр приводит результаты сравнительных испытаний двух компрессоров для взятых наугад нескольких экранов игровых программ. Вот полученные длины скомпрессированных блоков (в байтах) соответственно для двух вариантов компрессоров:
4619 и 5936 3228 и 2821 5958 и 5265 4985 и 4372 4027 и 3474
'Scooby Doo
'XENO"
Saboteur"
Вариант компрессора, который приводит Александр, заинтересовал нас и мы провели тестирование присланного им блока кодов, которое подтвердило основные моменты, изложенные выше. Но выяснилось, что полученный скомпрессированный блок кодов нельзя загружать для декомпрессии под любой адрес, а только под адрес, в котором он был скомпрессирован. Это серьезное ограничение для пользователей, которое может свести к нулю преимущество нового варианта компрессора. Хотя проблема в общем-то решается довольно просто. Те, кто регулярно читают "РЕВЮ", наверняка знают, как осуществить привязку к конкретным адресам загрузки.
Мы сделали такое усовершенствование программы, присланной Александром. Изменения коснулись программы декомпрессии (она стала длиннее на 7 байтов), из-за чего пришлось на 7 байтов отодвинуть программу компрессии в сторону младших адресов. В таком усовершенствованном виде мы предлагаем программу читателям (см. Лист. 1)
Листинг 1.
В HL указатель адреса в экранной области.
В BC счетчик байтов экрана. В DE задан адрес, куда будет производиться компрессирование.
PUSH DE
DEC DE INC DE
LD A,B OR C
JR Z,#7FC3 LD A,(HL) LDI
7F9E
7F9F 7FA1 7FA2 7FA3 7FA5 7FA6 7FA7 7FA9
7FAA
BE
20F6
0D
0C
2004
05
04
281A 12
13
CP (HL)
JR NZ,#7F97 DEC C INC C
JR NZ,#7FA9 DEC B INC B
JR Z,#7FC3 LD (DE),A
INC DE
7FAB
7FAC 7FAE
7FAF
7FB1 7FB2 7FB3 7FB4 7FB5 7FB6 7FB8 7FB9 7FBA 7FBC
7FBD 7FBE 7FC0 7FC1
7FC3
3E00 3C
28E5
12 23 0B 0D 0C
2004 05 04 2608 08
BE
20D6 08
18EB 1B
EX AF,AF'
LD A,#00 INC A
JR Z,#7F96
LD (DE),A INC HL DEC BC DEC C INC C
JR NZ,#7FBC DEC B INC B
JR Z,#7FC4 EX AF,AF'
CP (HL) JR NZ,#7F96 EX AF,AF' JR #7FAE
Он запоминается на стеке для того, чтобы потом можно было вычислить длину полученного скомпрес-сированного блока. Эта операция выполняется ввиду того, что при возврате из операции подсчета повторов и сравнений байтов в DE должен находиться адрес первого байта пустого места. Проверка BC на ноль, то есть определение конца компрессирования. Если ноль, то переход на END1 в аккумулятор заносится байт из экранной области и переносится по адресу, который указан в DE. DE и HL увеличиваются, а BC - уменьшается на единицу. Сравнение следующего байта с предыдущим.
Если не равны, то возврат на L1. Проверка BC на ноль (конец). В данном случае нельзя использовать аккумулятор, т.к. в нем находится байт из экранной области, который сравнивается со следующим.
Загрузка первого повторяющегося байта в приемник. Приращение DE для того, чтобы организовать по этому адресу счетчик повторов. Один повтор уже есть, поэтому сразу заносится единица, а не ноль. Это оказывается удобнее при декомпрессировании. Сохраняем в A экранный байт, вызываем альтерн. регистр для орга-низании в нем счетчика повторов. Как было сказано выше, в счетчик сразу заносится единица. Здесь будет организован счетчик повторов. Проверка на переполнение. Максимальное число повторов - 255. Запись в приемник числа повторов. Переход к следующему байту экрана. Уменьшение счетчика байтов экрана. Проверка BC на ноль без
задей-
ствовования
аккумулятора.
Обратный обмен регистров для сравнения текущего байта с предыдущим. Сравнение.
Если не равны, то возврат на L1 Если равны, то восстанавливаем счетчик повторов и переходим на L3 для наращивания счетчика. Эта операция нужна для того, чтобы при выходе из программы компрессии в DE содержался адрес последнего байта скомпрессированного блока. Берем последний байт из DE, инвертируем его
и записываем в следующий адрес ;
LD (DE),A
EX DE,HL POP DE
XOR A
SBC HL,DE
7FCD
7FD0
7FD3 7FD4 7FD6 7FD7 7FD8 7FD9
22E57F
012600
AF
ED4A
E5
C1
03
C9
LD (#7FE5),HL
LD BC,#0026
XOR A ACD HL,BC PUSH HL POP BC INC BC RET это сделано для упрощения декодирующей процедуры, т.к. в ней можно будет избежать лишней проверки счетчика на ноль. Обмен DE и HL для сохранения DE. Возвращаем со стека начальное значение DE.
Сброс флага переноса, необходимо для выполнения следующей команды. Отняв от конечной величины DE (которая теперь в HL) начальную, получим число байт скомпрессированн-ной области, но без учета последнего контрольного байта, который является инверсной копией предпоследнего.
Подставляем полученное значение в программу декомпрессии. Смещение, учитывающее длину декомпрессирующей процедуры. Сброс флагов.
Получение в HL суммарной длины блока кодов с учетом декодирующей процедуры. Перезапись полученного значения в регистр BC и увеличение его на 1 для учета последнего (контрольного) байта.
Последняя часть программы (с 7FD0H) позволяет получить выходной параметр в удобном для последующего использования виде. Для этого он был предусмотрительно помещен в регистр BC. Подав команду PRINT USR 32651 (7F8BH) результат работы компрессирующей процедуры (из регистра BC) будет выведен на экран: длина скомпрессированного блока (с учетом контрольного байта) плюс длина декомпрессора. А при подаче команды LET L=USR 32651
- результат будет помещен в переменную L. На магнитную ленту должен быть выгружен блок кодов с адреса 32730 (7FDAH), длиной L.
Так выполняется привязка к адресу загрузки. В результате в HL получается адрес начала скомпрессированного блока кодов. Оно образуется в результате увеличения адреса загрузки на величину, занимаемую программой декомпрессии.
Сейчас здесь ноль, но при работе программы компрессии сюда будет подставлена длина скомпрессиро-ванного блока кодов. Адрес приемника - экрана. Проверка BC на ноль.
Выход, если ноль. В аккумулятор заносится байт из скомпрессированной области. Перезапись байта в экран и переход к следующему байту экрана и приемника.
Сравнение его с предыдущим. Если не равен, то переход на L0 и повтор операции перезаписи и сравнения.
CD7TO0 3B 3B E1
012300 09
CALL #007C DEC SP DEC SP POP HL LD BC,#0023 ADD HL,BC
7FDA 7FDB 7FDE 7FDF 7FE0 7FE3
LD DE,#4000 LD A,B OR C RET Z LD A,(HL)
Переход к следующему байту, в котором находится кол-во повторов. Счетчик запоминается на стеке. Организуем в B счетчик повторов, число которых берется из HL. Запись байта в экран. Переход к следующему байту экрана. Уменьшение счетчика, если не 0 -то продолжение перезаписи байта из аккумулятора в экран. Снимаем BC со стека без проверки на ноль, т.к. переход в цикл загрузки одинаковых байтов может быть только из положительных значений BC (нулевой байт инвертирован по отношению к последнему). Переход к следующему байту ском-прессированной области. Теперь BC указывает на байт в HL, в котором находится число повторов и тоже не может быть в нуле. Уменьшение счетчика. Переход на проверку BC и перезапись байтов.
Скомпрессированный блок кодов.
PUSH BC LD B,(HL)
LD (DE),A INC DE DJNZ #7FF6
Для того, чтобы можно было компрессировать экраны, записанные без заголовка, Александр рекомендует дополнить программу компрессора процедурой загрузки блока кодов без заголовка, которая использует процедуру 1386 (0556H) ПЗУ:
7F7E DD210040 LD IX,#4000
7F6E 11001B LD DE,#1B00
7F85 3EFF LD A,#FF
7F87 37 SCF
7F88 CD5605 CALL #0556
Эффективность той или иной программы во многом зависит от того, насколько продумана Бейсиковая ее часть. Мы приводим вариант программы "Компрессор", которая в основе содержит программу, присланную Александром. Она русифицирована способом, которым мы постоянно пользуемся (см. "ZX-РЕВЮ"-92 N 1,2, стр. 30).
1 GO TO 100
2 CLEAR 30000: LOAD "chr" CODE 64600
3 FOR N=32636 TO 32767: READ M: POKE N,M: NEXT N
4 RUN
5 SAVE "COMPR" LINE 2: STOP
6 POKE 23606,88: POKE 23607,251: RETURN 9 POKE 23606,0: POKE 23607,60: RETURN 100 BORDER 7: PAPER 7: INK 0: CLS
110 GO SUB 8
200 PRINT AT 7,1;"<1> - ЗАГРУЗКА ЭКРАННОГО ФАЙЛА" ' TAB 7; "С ЗАГОЛОВКОМ" 210 PRINT AT 10,1;"<2> - ЗАГРУЗКА БЛОКА КОДОВ-'TAB 7;"БЕЗ ЗАГОЛОВКА" TAB 7;"С КОНТРОЛЕМ СЧИТЫВАНИЯ"
220 PRINT AT 14,1;"<3> - ЗАГРУЗКА БЛОКА КОДОВ-'TAB 7;"БЕЗ ЗАГОЛОВКА" TAB 7;"БЕЗ КОНТРОЛЯ СЧИТЫВАНИЯ"
300 PAUSE 0: IF INKEY$<>"1" AND INKEY$<>"2" AND INKEY$<>"3" THEN GO TO 300 310 LET I$=INKEY$
400 CLS : PRINT #0; TAB 11; FLASH 1;" ЗАГРУЗКА ": GO SUB 9
410 IF I$="1" THEN LOAD ""CODE 16384,6912: LET L=USR 32651
420 IF I$="2" THEN POKE 32649,2: POKE 32650,8: LET L=USR 32638
430 IF I$="3" THEN POKE 32649,66: POKE 32650, 5: LET L=USR 32636
500 GO SUB 8: INPUT ; : PRINT #0; PAPER 0; INK 7; BRIGHT 1, FLASH 1;" ДЛИНА="; L.
510 BEEP .1,20: PAUSE 400 600 PRINT AT 21,0;"ИМЯ ФАЙЛА ДЛЯ ЗАПИСИ: ": GO SUB 9: INPUT F$
610 SAVE F$ CODE 32730,L
700 RUN
900 DATA 221,33,0,64,17,0,27,62,255,55,205,86,5
910 DATA 33,0,64,1,0,27,17,0,128,213,27,19,120,177,40,40,126
920 DATA 237,160,190,32,248,13,12,32,4,5,4,40,26,18,19,8,62,0
930 DATA 60,40,229,16,35,11,13,12,32,4,5,4,40,8,8,190,32,214,8
940 DATA 24,235,27,26,47,19,18,235,209,175,237,32,34,229,127,1,38,0,175,237,74,229,193,3,201
950 DATA 205,124,0,59,59,225,1,35,0,9,1,0,0,17,0,64,120,177,200
960 DATA 126,237,160,190,32,247,36,197,70,18,19,16,252,193,35,11,11,24,234
Со строки 200 выводится меню программы. Возможны три варианта загрузки. Первый - обычная загрузка экрана, записанного с заголовком. Второй и третий - загрузка экрана, записанного без заголовка. Эти два режима могут оказаться довольно удобными, так как во многих играх встречаются блоки кодов - экраны, записанные без заголовка. Режимы загрузки экрана без заголовка отличаются между собой тем, что в одном случае для загрузки вызывается подпрограмма 2050 из ПЗУ, которая в случае ошибки выводит сообщение: "Таре loading error", а в другом случае используется подпрограмма 1366 ПЗУ, при этом работа БЕЙСИКа не прекращается независимо от правильности считывания.
Сразу же после окончания загрузки внизу экрана Вы увидите результат работы компрессирующей программы: длину скомпрессированного блока кодов. После нажатия любой клавши программа предложит Вам ввести имя для записи полученного результата вместе с Программой декомпрессии в виде единого файла. После записи можете загружать скомпрессированной блок в произвольный адрес ADR. Вывод на экран - RANDOMIZE USR ADR.
Другой вариант компрессии.
Продолжая разговор о компрессорах экрана, приведем еще одну программу.
Очень часто при разработке каких-либо (например обучающих) программ, приходится решать вопрос размещения в памяти компьютера большого количества графической информации, рисунков, схем и т. д. Причем во многих случаях графика занимает не весь экран, а скажем, только средний сегмент экрана. При этом верхний и нижний сегменты используются для других целей. Поэтому за счет компрессии не полного экрана, а лишь одного его сегмента, можно значительно сократить длину скомпрессированного блока кодов. Кроме того, при декомпрессии можно вызывать сегменты из памяти независимо один от другого, не нарушая соседние, правда в этом случае придется компрессирование проводить за два этапа, отдельно для дисплейной части и атрибутов, так как между вами появляется разрыв.
Декомпрессирущий блок является единственным для всех скомпрессированных экранов. При таком подходе в памяти можно получать десятки (a если небольшие, то может быть даже сотни) экранов. Перед запуском декомпрессирующей программы надо номер нужного экрана занести в системную ячейку декомпрессора при помощи POKE, а затем вызывать декодирующую процедуру.
В основе приводимой программы содержится известный многим пользователям "Спектрума" блок кодов "compress" CODE 28000,650. Но Бейсиковая часть сделана практически заново, что позволило пользоваться программой с большим удобством и удовольствием. Кроме того, мы приводим два варианта программы: для магнитофона и для дисковода.
Этот вариант компрессора является более изощренным, чем приведенные до сих пор программы. (Достаточно обратить внимание на длину его кодового блока). Однако эта длина сама по себе ни о чем не говорит. Ведь важна длина конечного продукта -скомпрессированного экрана плюс программы декомпрессии. Этот вариант компрессора позволяет получить более высокую степень компрессии, чем те, которые мы приводили до сих пор. Мы провели сравнительные испытания этого компрессора для тех же экранов.
"Death Star" 3185 байт
"Cauldron" 2128 байт
"Scooby Doo" 3946 байт "XENO" 3439 байт
"Saboteur" 2545 байт
Кроме более высокой степени компрессии, этот вариант компрессора позволяет получить следующие режимы, недоступные другим программам:
Возможно компрессирование как всего экрана, так и произвольно взятых одного любого или двух соседних сегментов экрана. Программа анализирует расположение графической информации на экране и выбирает, в зависимости от этого, наиболее выгодный способ компрессирования. При этом во время декомпрессии Вы можете увидеть, что некоторые экраны разворачиваются сверху вниз, аналогично тому, как это происходит при загрузке. А другие экраны - разворачиваются слева направо, (что несомненно усиливает зрительный эффект). Правда работает эта программа медленнее, чем другие варианты компрессоров. Компрессия полного экрана занимает порядка 1-3 секунд (однако это время не имеет значения для конечного продукта).
Так как кодовый блок программы (мы его полностью приводим ниже) расположен с адреса 28000, при использовании программы с дисководом Вам может не хватить свободного места. Для этого в программе используются приемы по сохранению памяти. Мы уже приводили такие материалы в "РЕВЮ". Это, в частности, замена числа 0 на NOT PI, числа 1 - на SGN PI, использование вместо числа выражения: VAL "число". Без таких преобразований оставлены только строки программы, реализующие работу меню, чтобы не замедлять время выполнения этих операций. Все эти приемы могут оказаться излишними для магнитофонного варианта, но они обязательны для дискового. Текст БЕЙСИК-программы вначале приведен для магнитофонного варианта. Затем будут даны дополнительные строки, которые позволят Вам получить дисковый вариант программы.
Вот Бейсиковая часть программы. Она традиционно русифицирована по известной Вам схеме.
1 GO TO VAL "100"
2 BORDER VAL "7": PAPER VAL "7": INK NOT PI: CLEAR VAL "27995": LOAD "chr"CODE 64600
3 LOAD "compress"CODE 28000,650
4 GO TO NOT PI
5 SAVE "COMPRESS"LINE 2: SAVE "compress"CODE 28000, 650: STOP
8 POKE VAL "23606", VAL "86": POKE VAL "23607", VAL "251":RETURN
9 POKE VAL "23606"^ОТ PI: POKE VAL "23607",CODE "<": RETURN
30 BORDER 1: PAPER 0: INK 7: CLS : GO SUB 8: GO SUB 40
31 FOR M=1 TO NN: READ M$: PRINT INK 6;AT (Y0+(M-1)*DY),X0;M$: NEXT M: PRINT INK 4; AT Y1,
3; "SPACE,DOWN,UP,ENTER,BREAK"
32 IF MM<1 THEN LET MM=NN
33 IF MM>NN THEN LET MM=1
34 PRINT AT (Y0+(MM-1)*DY),X0-DX: PAPER 7; INK 2; BRIGHT 1; OVER 1;S$: BEEP .03,2*MM+10
35 PAUSE 0: LET I=(INKEY$=" " OR 1 INKEY$= "6" OR CODE INKEY$=10)+(INKEY$="7" OR CODE
INKEY$=11)*2+(INKEY$ = "0" OR CODE INKEY$=12 OR CODE INKEY$=13)*3: GO TO (35+I)
37 PRINT INK 6;AT (Y0+(MM-1)*DY),X0-DX; OVER 1;S$: LET MM=MM-2*I+3: GO TO 32
38 FOR M=1 TO NN: PRINT PAPER 8; INK 8; BRIGHT 6; FLASH (M=MM); OVER (M=MM);AT (Y0+(M-
1)*DY),X0-DX:S$: NEXT M: BEEP .1,36: PAUSE 10: RETURN 40 PRINT AT 2,9;"ЧИСЛО ЭКРАНОВ: ";SCR
42 PRINT AT 3,3;"КОМПРЕССИЯ СЕГМЕНТА : ";BEG;: IF END<>BEG THEN PRINT AT 3,21;"OB";AT 3,26:"-";END
44 PRINT AT 4,6: "СВОБОДНОЙ ПАМЯТИ : ";65536-LAST
49 RETURN
50 BORDER VAL "7": PAPER VAL "7": INK NOT PI: CLS
52 PRINT AT VAL "21",NOT Р^'ИМЯ ФАЙЛА:": GO SUB VAL "9": INPUТ F$: CLS 59 RETURN
100 LET BEG=SGN PI: LET END=VAL"3": LET SCR=NOT PI: LET FIRST=VAL "28350": LET LAST=VAL
"28650": LET S=NOT PI 190 LET MM=SGN PI
200 DATA "ЗАГРУЗКА ЭКРАНА","РЕЖИМ КОМПРЕССИИ","ПРОСМОТР ЭКРАНА","УДАЛЕНИЕ ЭКРАНА","ЗАПИСЬ
ФАЙЛА"
201 RESTORE VAL "200": LET NN=VAL "5": LET X0=VAL "8": LET V0=VAL "9": LET DY=SGN PI; LET
DX=VAL "3": LET S$=" ": LET Y1=VAL "19": GO SUB VAL "30" 210 IF SCR=NOT PI AND MM>=VAL "3" THEN PRINT #NOT PI; FLASH SGN PI;" НЕТ ЭКРАНОВ!
": BEEP SGN PI, NOT PI: PAUSE VAL "100": GO TO VAL "190" 220 GO TO VAL "1E3"*MM
300 DATA " ВЕСЬ ЭКРАН","СЕГМЕНТЫ 1-2","СЕГМЕНТЫ 2-3"," СЕГМЕНТ 1"," СЕГМЕНТ 2"," СЕГМЕНТ
3"
301 RESTORE VAL "300": LET NN=VAL "6": LET X0=VAL "10": LET Y0=VAL "8": LET DY=SGN PI: LET
DX=VAL "3": LET S$=" ": LET Y1=VAL "19": GO SUB VAL "30": RETURN
1000 GO SUB VAL "50" 1010 LOAD F$ CODE 16384,6912
1030 POKE VAL "28005",INT (LAST/VAL "256"): POKE VAL "28004",LAST-VAL "256"*PEEK VAL "28005 1040 POKE VAL "28006",BEG-SGN PI: POKE VAL "28007",END-(BEG-SGN PI) 1050 RANDOMIZE USR VAL "28010"
1060 LET LEN=PEEK VAL "28008"+VAL "256"*PEEK VAL "26009": LET LAST=LAST+LEN+SGN PI: LET
SCR=SCR+SGN PI: LET S=SCR-SGN PI 1070 GO SUB VAL "8": PRINT #NOT PI; PAPER NOT PI; INK VAL "7"; BRIGHT SGN PI; FLASH SGN PI;
ДЛИНА=";LEN;" " 1080 PAUSE VAL "400" 1090 GO TO VAL "200" 2000 LET MM SGN PI: GO SUB VAL "300"
2010 RESTORE VAL "2000": FOR N=SGN PI TO MM: READ BEG: READ END:NEXT N 2020 GO TO VAL "190"
2100 DATA SGN PI,VAL "3",SGN PI, VAL "2",VAL "2", VAL "3",SGN PI,SGN PI,VAL "2",VAL "2",VAL
"3",VAL "3" 3000 LET S=S*(S<SCR)+(S<=SCR)
3010 INPUT ("НОМЕР ЭКРАНА (1-";SCR;"): ";S;" : "); LINE F$: IF F$<>"" THEN LET S=VAL F$
3020 IF S<SGN PI OR S>SCR THEN GO TO VAL "3010"
3030 BORDER VAL "7": PAPER VAL "7": INK NOT PI: CLS
3040 POKE VAL "28352",S: RANDOMIZE USR VAL "28350": PAUSE NOT PI
3050 GO TO VAL "200"
4000 IF SCR SGN PI THEN LET LAST=VAL "28650": GO TO VAL "4100"
4010 LET A=NOT PI: LET C=A: LET LEN=VAL "28649": FOR N=SGN PI TO SCR: LET LEN=LEN+A+C*VAL
"256"+SGN PI: LET A=PEEK LEN: LET C=PEEK (LEN+SGN PI): NEXT N: LET LAST=LEN 4100 LET SCR=SCR-SGN PI: LET S=SCR-SGN PI 4110 GO TO VAL "200" 5000 GO SUB VAL "50" 5010 SAVE F$CODE 28350,LAST-FIRST 5030 VERIFY F$ CODE
5050 GO SUB VAL "8" : PRINT #NOT PI; INVERSE SGN PI; " ЗАПИСЬ И ВЕРИФИКАЦИЯ - O.K. " 5060 BEEP VAL ".1",VAL "26": BEEP VAL ".1",VAL "20": PAUSE VAL "100" 5070 GO TO VAL "190"
Программы, подобные этой, Вы уже встречали на страницах "РЕВЮ", поэтому не будем подробно останавливаться на каждой ее части. Перечислим только основные фрагменты:
Строка 2 - автостарт, загрузка кодовых блоков.
Строка 5 - самозапись программы на магнитную ленту.
Строки 8 и 9 - переключатели шрифтов, соответственно русского и латинского.
Строка 30 - подпрограмма работы меню. Она была подробно рассмотрена в "ZX-РЕВЮ" N 9-10 за 1992 г., стр. 197.
Строка 40 - вывод основных режимов и состояния компрессора. На экран выводится следующая информация: число скомпрессированных экранов, режим компрессии - какие сегменты заданы для компрессирования, количество оставшейся свободной памяти компьютера.
Строка 50 - ввод имени файла для загрузки и записи. Если при выполнении загрузки в ответ на запрос имени нажать ENTER, ничего не вводя, то загрузится первый встретившийся кодовый файл.
Строка 100 - инициализация.
Строка 200 - главное меню программы, задающее режимы работы компрессора.
Строка 300 - второе меню, задающее сегменты для компрессирования.
Строка 1000 - загрузка очередного экрана.
Строка 2000 - задание сегментов для режима компрессии (вызов второго меню).
Строка 3000 - просмотр скомпрессированных экранов. Здесь следует отметить организацию ввода номера просматриваемого экрана. При запросе предлагается вариант по соглашению. Если предложенное число Вас не устраивает, введите свое значение, если устраивает - просто нажмите ENTER. Предложение варианта по соглашению (строка 3000) организовано так, что после загрузки очередного экрана к просмотру предлагается этот последний экран. После его просмотра по соглашению в следующий раз будет предложен первый экран, после его просмотра - второй и так далее до последнего, затем опять первый и так далее. Так можно просмотреть все экраны, ничего не вводя, а можно в любой момент вмешаться в этот порядок и ввести свое значение.
Строка 4000 - удаление экрана. Надо ли здесь организовать запрос для подтверждения Вашего решения? Организуйте его сами, если хотите. Удаляется всегда только последний экран. Это может создавать некотрое неудобство. Хорошо, если бы можно было удалять любой из скомпрессированных экранов, но это потребует вмешательство в блок кодов. В общем-то ничего принципиально сложного здесь нет. Надо только рассчитать место удаляемого экрана, определить его длину и организовать при помощи машиннокодовой команды LDIR переброску следующих экранов на место удаляемого. Все, что необходимо для такого рассчета, находится в строках с 4000. Может быть кто-нибудь из читателей и сделает такое усовершенствование.
Строка 5000 - запись всех скомпрессированных экранов вместе с программой декомпрессии в виде единого файла. Если при задании имени файла нажать ENTER, ничего не вводя, то программа вернется в режим основного меню (см. строку 5000).
При работе с БЕТА-диском, должны быть изменены строки, связанные с загрузкой и выгрузкой. Мы приводим ниже вариант строк для адаптации программы под дисковод. Вы можете набрать и хранить их отдельно, а при адаптации подгрузить к основной БЕЙСИК-программе при помощи MERGE.
2 BORDER VAL "7": PAPER VAL "7": INK BIN : CLEAR VAL "27999": RANDOMIZE USR VAL "15619": REM
: LOAD "chr"CODE 64600
3 RANDOMIZE USR VAL "15619": REM : LOAD "compress"CODE 28000,650
5 GO SUB VAL "90": STOP
6 RANDOMIZE USR VAL "15616"
7 STOP
90 RANDOMIZE USR VAL "15619": REM : ERASE "COMPRESS" 92 RANDOMIZE USR VAL "15619": REM : SAVE "COMPRESS" LINE 2 99 RETURN
1000 GO SUB VAL "50": IF F$="" THEN GO TO VAL "200"
1010 LET ERR USR VAL "15619": REM : LOAD F$ CODE 16364,6912
1020 IF ERR<>NOT PI THEN GO TO VAL "1500"
1500 GO SUB VAL "8": PRINT AT VAL "10",VAL "9"; FLASH SGN PI;" ОШИБКА ";ERR:..... FLASH NOT
PI'" ВЫВОДИТЬ КАТАЛОГ ДИСКА? (Y/N)" 1510 BEEP SGN PI, NOT PI: PAUSE NОТ PI: IF INKEY$<>"y" AND INKEY$<>"Y" THEN GO TO VAL "200" 1520 GO SUB VAL "9": RANDOMIZE USR VAL "15619": RЕМ : CAT 1530 PAUSE VAL "400" 1540 GO TO VAL "200"
5010 LET ERR=USR VAL "15619": REM : SAVE F$ CODE 28350,LAST-FIRST
5020 IF ERR<>NOT PI THEN GO TO VAL "1500"
5030 LET ERR=USR VAL "15619": REM : VERIFY F$ CODE
5040 IF ERR<>NOT PI THEN GO TO VAL "1500"
Строка 5 - как и раньше, самозапись программы (только Бейсиковой части) на диск. Она выполняется при помощи подпрограммы со строки 90, так как в одной пятой БЕЙСИК-строке не может выполняться более одного оператора TRDOS.
Строка 6 - переход в TR-DOS для выполнения каких-либо действий. После возврата оттуда по команде RETURN, попадаем на STOP в строке 7.
Строки с 1000 - загрузка экрана с диска. Здесь в случае ошибки при загрузке (например отсутствие файла на диске), происходит переход на строку 1500. Выведенный на экран код ошибки позволит Вам сориентироваться, почему произошла ошибка (коды ошибок см. в руководстве по TR DOS).
Строка 1500 предлагает вывести каталог диска, для того, чтобы Вы могли еще раз уточнить, есть ли нужный файл на этом диске или нет. На строку 1500 программа может перейти и из строк с 5000.
Строка 5000 - режим записи файла на диск, а также выполнение его верификации после записи.
Для тех читателей, которым не знаком кодовый блок программы "COMPRESS", мы приводим его полностью. (Тем, у кого он есть, можно его не набирать, а взять из имеющейся программы в готовом виде.) Для набора его Вы можете воспользоваться рекомендациями и программой для шестнадцатиричного ввода см. '^-РЕВЮ"-91, N 3, с. 59.
6D60 |
30 |
01 |
00 |
00 |
EA |
6F |
00 |
01 |
58 |
6EA8 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
16 |
6D68 |
8D |
03 |
FD |
21 |
60 |
6D |
FD |
36 |
83 |
6EB0 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
1E |
6D70 |
03 |
01 |
CD |
85 |
6D |
E5 |
FD |
36 |
B8 |
6EB8 |
00 |
00 |
00 |
00 |
00 |
00 |
18 |
04 |
42 |
6D78 |
03 |
00 |
CD |
85 |
6D |
D1 |
ED |
52 |
B7 |
6EC0 |
01 |
FF |
FF |
0C |
CD |
7C |
00 |
38 |
BD |
6D80 |
D8 |
FD |
36 |
03 |
01 |
FD |
6E |
04 |
6B |
6EC8 |
3B |
E3 |
33 |
33 |
A7 |
11 |
07 |
00 |
79 |
6D68 |
KD |
66 |
05 |
11 |
04 |
00 |
19 |
1E |
A9 |
6ED0 |
ED |
52 |
E5 |
FD |
E1 |
11 |
2A |
01 |
7C |
6D90 |
00 |
FD |
7E |
06 |
87 |
87 |
87 |
C6 |
D9 |
6ED8 |
19 |
FD |
7E |
00 |
3D |
28 |
06 |
5E |
A3 |
6D98 |
40 |
57 |
FD |
77 |
08 |
1A |
2F |
FD |
5E |
6EE0 |
23 |
56 |
19 |
18 |
F7 |
11 |
00 |
40 |
40 |
6DA0 |
77 |
00 |
FD |
36 |
01 |
01 |
FD |
36 |
EC |
6EE8 |
23 |
23 |
FD |
7E |
01 |
3C |
20 |
04 |
78 |
6DA8 |
02 |
00 |
FD |
7E |
03 |
18 |
74 |
FD |
1E |
6EF0 |
7E |
FD |
77 |
01 |
23 |
FD |
7E |
02 |
F1 |
6DB0 |
4E |
00 |
1A |
FD |
77 |
00 |
B9 |
28 |
DA |
6EF8 |
3C |
20 |
04 |
7E |
FD |
77 |
02 |
23 |
DD |
6DB8 |
0E |
FD |
CB |
02 |
46 |
28 |
08 |
FD |
70 |
6F00 |
7E |
FD |
77 |
03 |
FD |
7E |
01 |
FE |
DE |
6DC0 |
CB |
02 |
86 |
FD |
36 |
01 |
01 |
A7 |
5C |
6F08 |
03 |
38 |
04 |
FD |
36 |
01 |
00 |
FD |
E7 |
6DC8 |
20 |
16 |
FD |
CB |
02 |
46 |
20 |
10 |
AB |
6F10 |
7E |
02 |
FE |
04 |
38 |
04 |
FD |
36 |
70 |
6DD0 |
FD |
7E |
01 |
3D |
23 |
04 |
23 |
71 |
B6 |
6F18 |
02 |
01 |
FD |
86 |
01 |
FE |
04 |
38 |
48 |
6DD8 |
18 |
F9 |
3C |
23 |
0E |
00 |
18 |
13 |
EE |
6F20 |
04 |
FD |
36 |
02 |
01 |
FD |
7E |
02 |
46 |
6DE0 |
B9 |
20 |
30 |
FD |
CB |
02 |
46 |
20 |
86 |
6F28 |
A7 |
20 |
04 |
FD |
36 |
02 |
01 |
23 |
BB |
6DE8 |
15 |
FD |
7E |
01 |
3C |
FD |
77 |
01 |
97 |
6F30 |
1E |
00 |
FD |
7E |
01 |
87 |
87 |
87 |
CE |
6DF0 |
FE |
04 |
D8 |
36 |
00 |
23 |
77 |
23 |
2A |
6F38 |
C6 |
40 |
57 |
4F |
06 |
01 |
FD |
CB |
22 |
6DF8 |
71 |
FD |
36 |
02 |
01 |
C9 |
2B |
34 |
34 |
6F40 |
03 |
46 |
20 |
02 |
06 |
20 |
C5 |
FD |
02 |
6E00 |
08 |
23 |
FD |
36 |
01 |
01 |
08 |
C0 |
96 |
6F48 |
46 |
02 |
C5 |
06 |
08 |
C5 |
06 |
08 |
A5 |
6E08 |
7E |
2F |
FD |
77 |
00 |
FD |
36 |
02 |
CC |
6F50 |
C5 |
06 |
01 |
FD |
CB |
03 |
46 |
28 |
C4 |
6E10 |
00 |
C9 |
71 |
23 |
FD |
35 |
01 |
20 |
2E |
6F58 |
02 |
06 |
20 |
D5 |
C5 |
18 |
43 |
C1 |
A5 |
6E18 |
F9 |
77 |
FD |
36 |
01 |
01 |
FD |
36 |
5E |
6F60 |
13 |
10 |
F9 |
D1 |
C1 |
14 |
10 |
E8 |
89 |
6E20 |
02 |
00 |
C9 |
77 |
06 |
01 |
FD |
CB |
9F |
6F68 |
7A |
D6 |
08 |
57 |
7B |
C6 |
20 |
5F |
46 |
6E28 |
03 |
46 |
20 |
02 |
06 |
20 |
C5 |
FD |
E9 |
6F70 |
C1 |
10 |
DA |
7A |
C6 |
08 |
57 |
C1 |
EA |
6E30 |
46 |
07 |
C5 |
06 |
08 |
C5 |
06 |
08 |
91 |
6F78 |
10 |
D0 |
51 |
1C |
C1 |
10 |
C7 |
1E |
EA |
6E38 |
C5 |
06 |
01 |
FD |
CB |
03 |
46 |
28 |
AB |
6F80 |
00 |
3E |
58 |
FD |
86 |
01 |
57 |
FD |
5D |
6E40 |
02 |
06 |
20 |
D5 |
CD |
AF |
6D |
13 |
A7 |
6F88 |
46 |
02 |
4B |
FD |
CB |
03 |
DE |
C5 |
F8 |
6E48 |
10 |
FA |
D1 |
C1 |
14 |
10 |
E9 |
7A |
D9 |
6F90 |
18 |
10 |
C1 |
0B |
33 |
78 |
B1 |
20 |
4F |
6E50 |
D6 |
08 |
57 |
7B |
C6 |
20 |
5F |
C1 |
74 |
6F98 |
F6 |
FD |
36 |
01 |
FF |
FD |
36 |
02 |
65 |
6E58 |
10 |
DB |
7A |
C6 |
00 |
57 |
C1 |
10 |
21 |
6FA0 |
FF |
C9 |
FD |
CB |
03 |
56 |
28 |
0D |
2D |
6E60 |
D1 |
FD |
56 |
08 |
1C |
C1 |
10 |
C6 |
AD |
6FA8 |
D9 |
05 |
79 |
D9 |
28 |
03 |
12 |
18 |
9C |
6E68 |
11 |
00 |
58 |
0E |
01 |
FD |
46 |
07 |
98 |
6FB0 |
18 |
FD |
CB |
03 |
96 |
7E |
23 |
A7 |
E0 |
6E70 |
FD |
7E |
06 |
82 |
57 |
C5 |
CD |
AF |
79 |
6FB8 |
20 |
0E |
7E |
D9 |
47 |
D9 |
23 |
7E |
6D |
6E78 |
6D |
C1 |
0B |
13 |
78 |
B1 |
20 |
F5 |
70 |
6FC0 |
D9 |
4F |
D9 |
23 |
FD |
CB |
03 |
D6 |
F4 |
6E60 |
FD |
5E |
04 |
FD |
56 |
05 |
A7 |
ED |
39 |
6FC8 |
12 |
FD |
CB |
03 |
5E |
20 |
C3 |
18 |
6D |
6E83 |
52 |
EB |
73 |
23 |
72 |
FD |
7E |
06 |
BC |
6FD0 |
8E |
08 |
10 |
11 |
12 |
12 |
14 |
00 |
2E |
6E90 |
23 |
77 |
23 |
FD |
7E |
07 |
77 |
EB |
9F |
6FD8 |
03 |
00 |
01 |
02 |
01 |
00 |
03 |
00 |
51 |
6E98 |
22 |
68 |
6D |
C9 |
00 |
00 |
00 |
00 |
C6 |
6FE0 |
0F |
19 |
0E |
00 |
04 |
00 |
08 |
18 |
A9 |
6EA0 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
0E |
6FE8 |
22 |
22 |
00 |
00 |
00 |
00 |
00 |
00 |
9B |
Михайленко В.С., Турович А.К.