ЧИТАТЕЛЬ-ЧИТАТЕЛЮ
МЕТОД КОМПРЕССИИ ТЕКСТОВЫХ СООБЩЕНИЙ (с) Павел Сотников, г.Красноярск
Метод, о котором я хочу рассказать, очень прост. Вы, наверное, замечали, что в программах редко используют все символы шрифта: это позволяет экономить на графических образах символов порядка 200 -300 байт. В самом деле, можно обойтись одними заглавными буквами, что позволяет сократить шрифт до 64 символов (вместо 96). Экономия составляет 768 - 64*8 = 768 - 512 = 256 байтов.
При таком подходе становится возможным следующий метод компрессии.
Коды печатных символов начинаются с 32 и зканчиваются 95. Нам же удобнее, чтобы они начинались с 0 и заканчивались 63. Перекодировку осуществить очень легко: просто надо от кода символа отнять 32. Такая кодировка дает нам одно большое преимущество: в двоичной системе счисления самый большой код (код символа "_" - подчеркивание) равен 01011111 = 95, а при новой кодировке код того же символа записывается как 00111111 = 63. Очевидно, что в отличие от первого случая, в котором не используется только один бит, во втором случае не используются уже 2 бита : 6-ой и 7-ой.
Если экономить эти два бита, то мы получим файл в 4/3 раза меньше исходного. Это значит, что из каждых четырех байт в исходном файле экономится один -неплохой результат. К тому же, относительная простота алгоритма декомпрессии дает довольно большую скорость.
Рассмотрим сначала алгоритм компрессии:
в исходном файле должен находиться текст, составленный из символов с кодами от 32 до 95.
ПРОЦЕДУРА 1.
10 (C) PLEXUS SOFT' 1996
20 BASE1 EQU #7530 ; адрес исходного файла
30 BASE2 EQU #9C40 ; адрес приемника (куда будет
40 ; производиться
50 ; декомпрессия)
60 |
LEN EQU #0100 ; длина исходного файла (значение |
70 |
? |
#0100 взято |
80 |
? |
для примера) |
90 |
ORG #FC00 ; процедура является |
100 |
? |
релоцируемой |
110 |
ENT $ |
|
120 |
DI ; |
мы используем регистровую пару |
130 |
? |
IY, поэтому !М1 лучше |
140 |
? |
отключить |
141 |
LD IY, BASE1 ; загрузка индексных |
150 |
LD IX, BASE2 ; регистров |
160 |
LD BC, LEN + 1; счетчик байтов в исходном файле |
170 |
? |
(источнике) |
180 |
LD E, S + 1; счетчик битов в байтах |
190 |
? |
приемника |
200 |
JR P11 |
; сначала выполним подготовительные |
210 |
? |
операции |
220 |
L1 RL L |
; вращаем источник |
230 |
RL H |
; вращаем приемник |
240 |
DEC D |
; если кончились биты в байте источника, |
250 |
JR Z, P1 |
; то переход |
260 |
L2 DEC E |
; если остались свободные биты в байте |
270 |
JR NZ, L1 |
; приемника, то продолжаем цикл |
280 |
? |
иначе |
290 |
LD (IX + O), H ; записали байт в |
300 |
? |
приемник |
310 |
INC IX |
; следующий байт |
320 |
? |
приемника |
330 |
LD E, 8 |
; восстановленный счетчик битов |
340 |
JR L1 |
; и продолжаем |
350 |
P1 INC IY |
; следующий символ |
360 |
P11 LD D,6 |
; установили счетчик использованных |
370 |
? |
битов в байте |
380 |
? |
источника |
390 |
LD A,(IY+O) ; приняли символ в |
400 |
SUB 32 |
; аккумулятор |
410 |
AND 63 |
; и пере- |
420 |
RLA |
; кодиро- |
430 |
RLA |
; вали его |
440 |
LD L, A |
; теперь он в L |
450 |
DEC BC |
; уменьшение счетчика |
460 |
LD A, B |
; длины исходного файла и |
470 |
OR C |
; проверка его на ноль |
480 |
JR NZ, L2 |
; переход на коррекцию |
490 |
? |
регистра E |
500 |
L3 DEC E |
; коррекция |
510 |
JR Z, P2 |
; последнего байта |
520 |
SLA H |
? |
530 |
JR L3 |
? |
540 |
P2 LD(IX+O),H ; поместили его в |
550 |
? |
приемник |
560 |
LD IY, 23610 ; завершающие операции |
570 |
EI ; |
|
580 |
RET |
; выход |
ПРОЦЕДУРА создает компрессированный файл, начиная с адреса BASE2. Кстати, на мой взгляд, неплохой прием ( я называю его "двойным счетчиком") лежит в основе этой процедуры. Ситуация такая, что нам надо выходить из цикла вращения (строки с 220 по 270), если переполнен байт-приемник ИЛИ опустел байт-источник. Это неплохо реализовано в строках 240 - 270.
Теперь о процедуре декомпрессии. Она аналогична процедуре компрессии. Входными параметрами служат BASE2 - адрес скомпрессированного файла и NLEN - длина скомпрессированного файла.
ПРОЦЕДУРА 2.
10 (C) PLEXUS SOFT' 1996
20 BASE2 EQU 40000 ; адрес скомпрессированного файла 30 NLEN EQU 00192 ; его длина
40 |
ORG #FA46 ; процедура релоцируемая |
50 |
ENT$ |
|
60 |
LD IX, BASE2 ; загружаем |
70 |
LD BC,NLEN +1; регистровые пары |
80 |
LD L, 0 |
; обнуление приемника |
90 |
LD D, 6 |
; счетчик битов в байте |
100 |
? |
приемника |
110 |
JR P1 |
; переход на выполнение |
120 |
? |
подготовительных |
130 |
? |
операций |
140 |
L1 RL H |
; вращаем источник |
150 |
RL L |
; вращаем приемник |
160 |
DEC D |
; если приемник переполнен, |
170 |
JR Z, P2 |
; то переход на Р2 |
180 |
L2 DEC E |
; если в источнике еще остались |
190 |
JR N2, L1 ; биты, то продолжаем |
200 |
INC IX |
; следующий байт источника |
210 |
P1 LD H(IX |
+ O); взяли байт из источника |
220 |
LD E,8 |
; установили счетчик битов |
230 |
? |
в байте источника |
240 |
DEC BC |
; проверка |
250 |
LD A,B |
; на ноль |
260 |
OR C |
; счетчика |
270 |
JR NZ,L1 |
; длины, и если не 0, то возврат |
280 |
RET |
; выход из процедуры |
290 |
P2 LD A,L |
- ; в аккумуляторе приемника |
300 |
LD L,O |
; обнуление приемника |
310 |
ADD A,32 ; перекодировка символа |
320 |
RST 1OH ; и вывод его в текущий |
330 |
? |
поток |
340 |
LD D,6 |
; установка счетчика битов |
350 |
? |
в байте приемника |
360 |
JR L2 |
; возврат на проверку |
370 |
? |
счетчика битов в байте |
380 |
1 |
источника |
Эта процедура выводит закомпрессированное сообщение в текущий поток. Но при желании можно легко изменить ее так, чтобы она декомпрессировала текст в любой адрес. Для этого нужно вставить в нее следующие строки :
55 DI
56 LD IY, ADDR
275 LD IY, 23610
276 EI
320 LD (IY + O),A
325 INC IY
Здесь ADDR - адрес памяти, куда будет производиться декомпрссирование. Кстати, еще одно преимущество (а может быть и недостаток) этого алгоритма заключается в том, что длина скомпрессированного файла зависит только от длины исходного и определяется по формуле A = 3B/L, где A - длина скомпрссированного файла, B - исходного.
B RLE - компрессорах, например, A зависит не только от В, но и от того как часто и как много будут повторяться байты в исходном файле. Поэтому, может возникнуть ситуация, когда RLE - скомпрессированный файл будет длиней исходного. С этим алгоритмом такого быть не может: длина скомпрессированного файла всегда меньше или равна длине исходного.
О том, что иногда в программах экономия памяти достигается путем уменьшения количества символов в шрифте, я говорил в самом начале. Теперь посмотрим,каким еще образом можно экономить память. Для этого рассмотрим как хранятся в памяти графические образы символов.
...................- Как видно из рисунка, для хранения гра-
+—t=T=T=T=T-----+0 фической информации в символе "С" ис-
+„T=+=j=j=j=+=T—+1 пользуется 6 байтов (с первого по шес-
+--j=+.......j=—+2 той). Нулевой и седьмой байты содержат
+--+=j.............+3 нули. Точно так же дела обстоят и с ос-
+--j=+.......T=-—+4 тальными символами, коды которых нахо-
+—=+=T=T=T=+=j---+5 дятся в диапазоне от 32 до 95. Итак,
+-----=j=j=j=j.....+6 для хранения символа мы можем обходить-
L...................7 ся шестью байтами, а остальные два
(первый и последний) добавлять при печати (они всегда равны нулю). В этом случае шрифт будет занимать в памяти 64*6 = 384 байта, или ровно половину от стандартного. Экономия составит 512 - 384 = 128 байт.
Эта процедура преобразует первые 64 символа шрифта, на начало которых в памяти указывает регистровая пара HL, и помещает их, начиная с адреса, на который указывает регистровая пара DC.
ПРОЦЕДУРА 3.
10 (C) PLEXUS SOFT' 1996
20 FONT1 EQU #3D00 ; адрес источника
30 FONT2 EQU #FA00 ; адрес приемника
40 ORG 23296 ; процедура релоцируемая
50 LD HL,FONT1; загрузка
60 LD DE,FONT2; регистров
70 LO B, 64 ; инициализация счетчика
80 L1 INC HL ; пропускаем первый байт
90 PUSH BC ; спрятали счетчик на стеке
100 LD BC, 6 ; перебросили
110 LDIR ; 6 байт
120 POP BC ; достали счетчик со стека
130 INC HL ; пропускаем последний байт
140 DJNZ L1 ; следующий символ
Вот пример процедуры, которая будет печатать таким шрифтом:
ПРОЦЕДУРА 4.
10 (C) PLEXUS SOFT' 1996
20 FONT2 EQU #FD00 ;
30 POS EQU 23681 ; адрес координат печати
40 ORG 30000 ; процедура релоцируемая
50 CP 32 ; если это не "наш" символ,
60 JP C,O9F4H ; то переход на обработку
70 CP 95 ; его
80 JP NC,#O9F4; процедурами ПЗУ
90 SUB 32 ; перекодировали символ
100 LD L, A ;
110 LD H, O ;
120 LD E, L ;
130 LD D, H ;
140 ADD HL, HL ; и умножили
150 ADD HL, HL ; его
160 ADD HL, DC ; на
170 ADD HL, DE ; 6
180 LD DE,FONT2; адрес шрифта
190 ADD HL, DE ; адрес символа в нем
200 PUSH HL ; спрятали
210 LD HL,(POS); в НЬ - координаты
220 LD A, L ; получили из них
230 AND I8H ; старший байт
240 OR 4OH ; адреса в экране
250 LD D, A ; теперь он в D
260 LD A, L ;
270 AND O7 ; получили
280 RRCA ; младший
290 RRCA ; байт
300 RRCA ; адреса
310 ADD A, H ; в экране
320 LD E, A ; теперь он в С
330 POP HL ; вспомнили адрес символа
340 EX HL, DE ;
350 LD (HL), O ; восстановили первый байт
360 ; символа
370 INC H ; следующая линия
380 LD B, 6 ; счетчик используемых байт
390 ; символа
400 L1 LD A, (DE) ; копи-
410 LD (HL), A ; руем
420 INC H ; их
430 INC DE ; на
440 DJNZ L1 ; экран
450 LD (HL), O ; восстанавливаем последний
460 ; байт символа
470 LD HL,POS+1; адрес Х-координаты в HL
480 LD A, 32 ; максимум по х
490 INC (HL) ; увеличили х
500 CP (HL) ; и проверили
510 |
RET NZ ; |
вышли, если все в порядке |
520 |
LD A, 22 ; |
максимум по оси Y |
530 |
LD (HL), O |
; х - координата равна нулю |
540 |
DEC HL ; |
у - координата |
550 |
INC (HL) ; |
увеличили ее |
560 |
CP (HL) ; |
и проверили |
570 |
RET NZ ; |
вышли, если все в порядке |
580 |
LD (HL), O |
; иначе у = 0 |
590 |
RET ; |
и выход |
Вот еще одна интересная деталь: бывают шрифты, созданные путем деформации символов стандартного шрифта, например, утолщенный шрифт. Обычно поступают так: создают в оперативной памяти шрифт на основе стандартного, затем переключают системную переменную CHARS и выполняют печать. Я же предлагаю создавать символы непосредственно перед печатью.
ПРОЦЕДУРА 5.
10 (C) PLEXUS SOFT' 1996
20 POS EQU 23681 ; адрес координат печати
30 CHARS EQU 23606 ; адрес переменной, указывающей
40 |
на адрес шрифта |
50 |
ORG 40000 ; |
процедура релоцируемая |
60 |
CP 32 ; если это не "наш" символ, |
70 |
JP C,O9F4H ; |
то переход на обработку |
80 |
CP 128 ; его |
90 |
JP NC,O9F6H; процедурами ПЗУ |
100 |
LD L, A ; |
если символ |
110 |
LD H, 0 ; |
печатный, |
120 |
ADD HL, HL |
; то |
130 |
ADD HL, HL |
; умножаем его |
140 |
ADD HL, HL |
; на 8 |
150 |
LD DE,(CHARS); адрес шрифта |
160 |
ADD HL, DE |
; адрес символа |
170 |
PUSH HL ; |
на стеке |
180 |
LD HL,(POS) |
; координаты печати |
190 |
LD A, L ; |
определяем |
200 |
AND I8H ; |
адрес |
210 |
OR LOH ; |
в |
220 |
LD D, A ; |
экранной |
230 |
LD A, L ; |
области |
240 |
AND O7 ; |
по |
250 |
RRCA ; |
координатам |
260 |
RRCA ; |
и |
270 |
RRCA ; |
помещаем |
280 |
ADD A, H ; |
его |
290 |
LD E, A ; |
в DC |
300 |
POP HL ; |
вспомнили адрес символа |
310 |
LD B, 8 ; |
счетчик байтов символа |
320 |
L1 LD A,(HL) |
; приняли байт |
330 |
RRA ; обработали |
340 |
OR (HL) ; |
его |
350 |
LD(DE), A ; |
и поместили на экран |
360 |
INC D ; |
следующая линия |
370 |
INC HL ; |
следующий байт |
DJN2 L1 ; продолжаем
; далее как в Процедуре 4 ; строки 470 - 590
Как видно из листингов, процедуры 4 и 5 легко подключаются к пользовательским потокам, т. к. входным параметром у них является код символа, содержащийся в аккумуляторе. Надо только позаботиться о том, чтобы в адресах 23681 / 82 находились координаты печати, не выходящие за пределы экрана. Все пять процедур являются полностью релоцируемыми.
О СИГНАЛЕ INT МИКРОПРОЦЕССОРА (c) И.А. Пичугин.
Надеюсь,что информация, которая содержится в этом письме, заинтересует многих любителей ZX-SPECTRUM и окажется весьма полезной в самых разных ситуациях, с которыми может столкнуться пользователь, начиная с покупки компьютера и заканчивая программированием и всевозможными схемными доработками. Со страниц журнала обрушивается целый поток различных предложений по доработкам, улучшающим совместимость выпускаемых компьютеров. Особое внимание уделяется сигналу INT микропроцессора.
Этой теме и посвящается программа, которую я привожу ниже.Результат работы программы - число, пропорционльное количеству тактов микропроцессора между началами двух подтверждений маскируемых прерываний. Многочисленные эксперименты показывают,что полученный результат зависит только от схемного решения компьютера, малочувствителен к изменению длительности /INT и не зависит от тактовой частоты микропроцессора.
Для примера привожу данные,полученные при тестировании компьютеров:
РОБИК.....3648
КВОРУМ....3881 КР-05.....4019
Исходя из этих данных, можно предположить, что программы, использующие подсчет тактовых импульсов для синхронизации работы с включенными прерываниями будут нормально работать только на компьютерах, идентичных тому, на котором эти программы были написаны.
Лучше всего, если в программе предумотрена коррекция соответствующих временных задержек, определяемая конкретными характеристиками машин. Что и планировалось реализовать в программе АТС для согласования процедур загрузки и записи на магнитофон.
Несколько слов о работе программы. Если полученный коэффициент равен 1, то приведите длительность /INT в норму. Соотношение между коэффициентом, полученным в результате работы программы и количеством тактовых импульсов можно выразить формулой:
Z=(k*18)+57, где Z-количество импульсов,
k-коэффициент. ;□ Pichugin I.A. 1996
' ORG #C350
DI |
|
LD |
HL,#C100 |
LD |
DE,#C101 |
LD |
BC,257 |
LD |
(HL),#C3 |
LDIR |
|
LD |
A,#C1 |
LD |
I,A |
LD |
A,2 |
EX |
AF,AF' |
LD |
BC,0 |
IM |
2 |
EI |
|
HALT |
|
LOOP INC BC LOOP1 JR LOOP
LD |
A,#FD |
LD |
(LOOP1+1),A |
LD |
(TABL),BC |
IM |
1 |
EI |
|
RET |
|
TABL DEFS |
2 |
ORG |
#C3C3 |
EX |
AF,AF' |
DEC |
A |
JR |
NZ,CONT |
LD |
(LOOP1+1),A |
CONT EX |
AF,AF' |
EI |
|
RET |
|
Текст программы набран в ассемблере GENS 4.
Результат возвращается в регистрвой паре ВС и сохраняется по дресу #C37C(50044)
BASIC-вариант:
10 REM □ 1996 Pichugin I.A. 20 BORDER 7: INK 0: PAPER 7:CLEAR 39999 30 FOR n=50000TO 50045: READ a: POKE n, a: NEXT n: FOR n=50114TO 50124: READ a: POKE n,a: NEXT n: 40 LET K=USR 50000: PRINT "K=";K 50 LET Z=(K*18)+57: PRINT "Z=";Z 60 REM LET T=Z*50: PRINT "T=";T;"Hz" 70 PAUSE 0: CLS : GO TO 40 110 DATA 243,33,0,193,17,1,193,1,1,1,54, 195,237,176,62,193,237,71,62,2,8,1,0,0,23 7,94,251,118,3,24,253,62,253,50,110,195,2 37,67,124,195,237,86,251,201,179,15,0 120 DATA 8,61,32,3,50,110,195,8,251,201,0
Если программные часы, например, в BETA - BASIC при работе на Вашем компьютере работают с высокой точностью, в строке 60 оператор REM можно убрать, тогда переменной Т присваивается значение тактовой частоты микропроцессора в Герцах.
По поводу совместимости. Можно более точно установить период сигнала INT, добиваясь точного хода часов, изменяя тактовую частоту процессора. Очевидно то, что различные марки компьютеров при одинаковой точности хода часов будут обладать разным быстродействием.
АРХИВАТОР ТЕКСТОВЫХ СООБЩЕНИЙ
(C) Васьков А.В., г.Верхняя Салда.
Прочитав статью "Архивация, компрессия и сжатие" в ZX-РЕВЮ 95/1, я решил заняться этим делом, и через пару дней сделал архиватор, который предназначен для архивации текстовой информации. В данном Варианте архиватора текст может содержать 47 различных символов.
Архиватор состоит, собственно, из архиватора (ARCHIV) и реархиватора (REARCH).
Архиватор занимается архивацией текста из буфера BUFF1 в буфер BUFF2. Его возможно запускать из бейсика строкой PRINT USR 49152, после работы программа напечатает длину заархивированного блока. Маркером конца является символ "#", который в тексте не может использоваться. Реархиватор, по отношению к архиватору, занимается обратной работой. Используя буфер BUFF2, как буфер заархивированного текста, он печатает текст посредством программы печати из ПЗУ SPECCY. В этом варианте реархиватор запускается из бейсика строкой PRINT (экранные координаты, атрибуты), USR 49408.
Обе эти программы используют архивационную таблицу. Она построена для английского текста по следующему правилу: чем правее столбик символов, тем они меньше встречаются, и символ "#" всегда должен оставаться на своем месте. Можно составить свою таблицу, конкретно для своего текста. От этого зависит качество архивации. Для этого необходимо составить небольшую программу, считающую количество каждого символа в Вашем тексте. А после этого, пользуясь полученными вычислениями и соблюдая приведенные выше правила, составить свою таблицу.
В защиту своей программы могу сказать, что разархиватор имеет длину 83 байта! + 48 байтов архивационной таблицы. И еще, я взял произвольный английский текст длиной 704 байта, что составляет 22 строки. После архивации он составил 391 байт - это 55.9% первоначального текстового блока. Все эти цифры меня устраивают, но я уверен, что можно добиться и лучших результатов.
(C) IMPERATOR 1996
ARCHIV ORG #C000 BUFF1 EQU #F000 BUFF2 EQU #F800 LD HL,BUFF2 LD (M4+1),HL LD (M5+1),HL LD HL,BUFF1 LD (M6),HL CALL P4 L14 LD HL,(M6) LD A,(HL) INC HL LD (M6),HL LD C,8 LD HL,TAB LD DE,1 L10 LD B,6 L9 CP (HL) JR NZ,L8 CALL P5 JR L14 L8 OR A RL E INC HL DJNZ L9 INC D LD E,1 DEC C JR NZ,L10 LD DE,#700
CALL P5 M4 LD DE,0
LD HL,(M5+1) INC HL OR A SBC HL,HL LD B,H LD C,L RET P5 RL D RL D RL D RL D RL D LD B,3 L11 RL D CALL P3 DJNZ L11 LD B,5 L13 RR E
JR C,L12 L15 CALL P3 DJNZ L13 RET L12 LD B,1 JR L15
P3
M5 LD HL,0
RR (HL) M7 LD A,8 DEC A JR NZ,L16 INC HL LD (M5+1),HL P4 LD A,8 L16 LD (M7+1),A
RET M6 DEFW 0 TAB DEFM " NGQ08" DEFM "TUPZ19" DEFM "SHWX2-" DEFM "ALY,3(" DEFM "OMF.4)" DEFM "IBK!5?" DEFM "EDV:6$" DEFM "RCJ'7#"
REARCH ORG #C100 LD HL,BUFF2 LD (M2+1),HL CALL P2 LD D,0 L4 LD C,D LD B,3
LOOP CALL P1 DJNZ LOOP INC C LD B,C XOR A L1 ADD A,6 DJNZ L1 LD E,A LD B,5 L3 LD C,D CALL P1 RR C JR C,L2 INC E DJNZ L3 L2 LD HL,TAB-6 ADD HL,DE LD A,(HL) CP "#" RET Z RST 10 JR L4
P1
M2 LD HL,0 M3 BIT 0,(HL) JR Z,L5 SCF JR L6 L5 OR A L6 RL C
LD A,(M3+1) ADD A,8 CP #86 JR NZ,L7 INC HL LD (M2+1),HL P2 LD A,#46 L7 LD (M3+1),A RET
ВЫВОД НА ЭКРАН СПРАЙТ - ФАЙЛОВ В IS DOS (c) Черешнев Андрей, г. Ростов-на-Дону.
Предлагаю программу для IS-DOS. Она позволяет выводить на экран спрайт-файлы формата графического редактора PICASSO for IS-DOS (расширение .sp). Для файлов без атрибутов можно поменять постоянный цвет программой unicolor. com.
Для вывода на экран по нажатию клавиши 3(VIEW), нужно поместить следующую строку в файл extview.txt (в каталоге SHELL): sp :Q:SHELLexesp /w Альтернативные способы вывода на экран таких файлов - это использование командной строки или текстовых командных файлов типа ".bat".
В этих случаях строка
Q:SHELLexesp Т:КАТАЛОГфайл [/w] набирается, соответственно, в командной строке либо в редакторе.(В редакторе
создается файл типа ".bat").
Поместив несколько подобных строк без ключа /w в командный файл типа ".bat", можно получить просмотр спрайтов, непрерывно сменяющих друг друга. Для управления выводом на экран используется /w - ключ ожидания.
; Exesp v1.00 ; Copyright 18.07.96 ; by Andrei Chereshnev
ORG 24000 LD A,#18 LD C,#36 RST 16 RET C JR Start
;Сохраняем текущую ;среду
;в пользовательском ;канале #18
DEFM "UnCo" ;Для настройки DEFB #01 ;постоянного цвета
COLOR DEFB <0*128>+<0*64>+<7*8>+0
ext: DEFM "sp "
XY EQU #0000 ;Координаты
;------------------------- ;окна спрайта
L0: EXX
EX DE,HL LD HL,L1 LD (addrA+1),HL Start:
LD C,#43 ;Открываем каталог RST 16 ;файла и
RET C ;снимаем ключ (если он
addrA JP NZ,Exit ;есть) AND A JR Z,L0 RES 5,A CP "W" JR NZ,Exit XOR A LD (mnemA),A JR Start
;Ждет нажатия ;клавиши
;Восстановление ;среды из канала #18
;Стандарный выход
L1: EX DE,HL CALL Begin RET C XOR A mnemA RET LD C,#07 RST 16 Exit:
LD A,#18 LD C,#37 RST 16 XOR A
LD A,#F4 ;в IS-DOS RET
Begin:
PUSH HL LD DE,8 ADD HL,DE EX DE,HL LD HL,ext LD BC,#0003 LDIR POP HL LD C,#25 RST 16 RET C
;Подставляем файлу ;расширение .sp
;Открываем файл
EXX
LD DE,14 ADD HL,DE LD E,(HL) INC HL LD D,(HL) CALL Memory RET C
;В HL-адрес 32-байтового ;описателя файла (FNAME)
;В DE-длина файла (FLENG). ;Проверяем наличие свободной ;памяти
LD IX,$SPACE XOR A PUSH HL
LD HL,#0000
LD C,#29 ;Чтение файла,$SPACE -RST 16 ;адрес в памяти
POP HL RET c
;В HL- FLENG+1. ;В HL- WORD_20.
;В BC- #hl спрайта ;Проверяем атрибуты спрайта
LD BC,5 ADD HL,BC LD C,(HL) INC HL LD B,(HL) LD A,B OR C RET Z PUSH BC CALL TestCol
LD DE,XY POP BC EXX LD HL,$SPACE EXX
JR Sp_out ;Изображаем спрайт
Memory:
PUSH DE
LD C,#10 RST 16 EXX
LD DE,5 ;В HL-адрес вектора
ADD HL,DE ;конфигурации ядра LD E,(HL) INC HL
LD D,(HL) ;В DE-адрес начала
LD HL,$SPACE ;электронного диска
EX DE,HL
AND A
SBC HL,DE
POP DE
AND A
SBC HL,DE
EXX
LD A,130 ;Не хватает памяти-RET ;ошибка 130
TestCol:
LD L,B ;B*C=HL
LD B,8 XOR A RR L mul0 JR NC,mul1
ADD A,C mul1 RRA RR L DJNZ mul0 LD H,A
ADD HL,HL ADD HL,HL ADD HL,HL AND A SBC HL,DE
RET C ;Есть атрибуты
;Mono
LD HL,L0A ; LD (HL),#21 ; LD HL,COLOR ; LD (L0A+1),HL ;LD HL,COLOR LD HL,L0A+3 ; LD (HL),#D9 ;EXX LD HL,L1A ; LD (HL),#00 ;NOP RET
Sp_out:
PUSH DE PUSH BC LD A,E AND #18 ADD A,#40 LD H,A
LD A,E AND 7 RRCA RRCA RRCA ADD A,D LD L,A
PUSH HL LD A,H RRCA RRCA RRCA AND #03 OR #58 LD H,A EX (SP),HL
;Выводим пиксели
L1_0: LD E,B LD D,8
L2_0: LD B,C
L3_0: EXX LD A,(HL) INC HL EXX
LD (HL),A INC HL DJNZ L3_0 AND A SBC HL,BC INC H DEC D JR NZ,L2_0 LD B,E
LD A,H AND 7 JR NZ,L0_0 LD A,L ADD A,32 LD L,A JR C,L0_0 LD A,H SUB 8 LD H,A
L0 0: DJNZ L1 0
L0A DEFB 00,00,00,00 POP HL POP BC POP DE
L0_1: LD E,B ;Выводим атрибуты (атрибут)
LD B,C L1_1: EXX LD A,(HL)
L1A INC HL EXX
LD (HL),A INC HL DJNZ L1_1 AND A SBC HL,BC LD B,E LD DE,32 ADD HL,DE DJNZ L0_1
AND A ;Обнуляем флаг C
RET
END
$SPACE EQU $
Обратите внимание на адрес загрузки и запуска программы exesp.com (24000). Он специально выбран для возможной работы с помощью mon.com. Длина exesp.com составляет 300 байтов.
Я хотел бы переписываться со всеми, кто программирует в системе IS-DOS. Мой адрес: 344111, г. Ростов-на-Дону, пр.40-летия Победы, 75/4, кв.3. Черешневу Андрею.
ОРГАНИЗАЦИЯ УПРАВЛЕНИЯ И ИНТЕРФЕЙС "СТРЕЛКА".
(c) Сергей Колотов, г.Шадринск, copyright SerzhSoft in 1996
Как уже не раз замечалось в ZX-РЕВЮ, множество авторских программ, мягко говоря, хронически страдает от некорректно организованного управления (опроса джойстиков, клавиатуры). Отсутствует стандарт, каждый программист, например, может "подвязать" свои особые клавиши, удобные (удобны ли?) лишь только для него самого. Хотя и существуют некоторые неофициальные стандарты (например, клавиши Q,A,O,P,SPACE), но и они не всегда выполняются.
Данная статья была написана в надежде на то, что бесчисленные отряды отечественных программистов все-же постараются при разработке своих программных продуктов быть ближе к народу, к пользователям. Пусть установка каждого кодера будет такой: "все лучшее - юзерам" (а не только детям, как гласит известный лозунг)! Автор надеется, что представленные в этой статье программы окажутся полезными для кого-либо и будут интересны как начинающим программистам, так и более опытным, которых, как мне кажется, в нашей стране большинство.
При разработке любой программы, рассчитанной на широкий круг пользователей, необходимо удовлетворить любого и всех вместе. Мудрая пословица гласит: "На вкус и цвет - товарищей нет!" При разработке программных продуктов необходимо отталкиваться именно от этой истины.
Приведенная ниже библиотека процедур предназначена для опроса всех видов джойстиков и клавиатуры. Представлены: KEMPSTON, CURSOR, SINCLAIR (LEFT&RIGHT) джойстики; клавиши Q,A,O,P,SPACE; клавиши, заданные "по вкусу" (в данном случае: Z,X,C,F,G). Все подпрограммы можно вызывать как по отдельности, так и все вместе, параллельно. Полученные данные преобразуются в формат KEMPSTON-джойстика, т. е. результатом является байт с установленными в нем битами, отвечающими за флаги направлений и FIRE.
Этот результат помещается как в регистр A (аккумулятор), так и в ячейку DIRECT.
Напомню вкратце.
Формат KEMPSTON:
! означают: ! биты: ! означают: !
вправо ! 3 ! вверх влево ! 4 ! огонь вниз ! 5,6,7 ! не исп.
Итак, библиотека SCAN LIBRARY: Listing 1.
Длина процедуры вместе с переменными равна 192 байта. Итак, можете вызывать: CALL DIRSCN - сканирование всех джойстиков и клавиатуры. Если клавиша CAPS SHIFT нажата, то опрашиваются курсоры, иначе - SINCLAIR-джойстики. CALL OUTDIR - если Вам привычно работать не с одним-единственным байтом с изменяющимися битами направлений, а с отдельными переменными (а в бейсике иначе и не получится - слишком сложно!), то вызывайте эту подпрограмму.
Биты из переменной DIRECT "расфасуются" в переменные D_RIGHT, D_LEFT, D_DOWN, D_UP, D_FIRE (0-выкл/1-вкл). CALL KEMPST - опрос кемпстон-джойстика. CALL QAOPSP - клавиши Q,A,O,P,SPACE. CALL CURSOR - курсоры. CALL SINC_L - левый синклер-джойстик. CALL SINC_R - правый синклер-джойстик.
CALL DEFINE - опрос клавиш, заданных по желанию. Описание клавиш помещается в таблицу KEYTBL. Первый байт - не что иное, как старший байт порта клавиатуры, а второй байт - маска нужной клавиши (бит установлен в единицу). Переменные:
DIRECT:db(0..31) - байт с флагами направлений в формате KEMPSTON D_RIGH:db(0/1) - "направление вправо", D_LEFT:db(0/1) - "направление влево", D_DOWN:db(0/1) - "направление вниз", D_UP :db(0/1) - "направление вверх", D_FIRE:db(0/1) - "огонь". Шестнадцатеричный дамп SCAN LIBRARY: ( для примера оттранслировано под адрес 64000 (#FA00) ) Listing 2. Адреса процедур и переменных: DIRSCN 64000 #FA00 KEYTBL 64176 #FAB0 OUTDIR 64041 #FA29 DIRECT 64186 #FABA KEMPST 64056 #FA38 D_RIGH 64187 #FABB QAOPSP 64064 #FA40 D_LEFT 64188 #FABC CURSOR 64101 #FA65 D_DOWN 64189 #FABD SINC_L 64130 #FA82 D_UP 64190 #FABE SINC_R 64144 #FA90 D_FIRE 64191 #FABF DEFINE 64157 #FA9D
Преимущества использования SCAN LIBRARY:
1. Простота и малый объем.
2. Опрос любых типов джойстиков и клавиатуры.
3. Возможность одновременного параллельного сканирования всех видов управления.
4. Единый стандарт выходных данных (KEMPSTON-формат).
5. Возможность использования из BASIC. Очень простая организация движения "наискосок" и/или с нажатием FIRE, что в бейсике реализовать довольно-таки
сложно.
Пример BASIC-программы, использующей SCAN LIBRARY. Listing 3.
Данная демонстрационная программа на бейсике представляет из себя простейший графический редактор, позволяющий рисовать "картинки", используя символ "#" (можно заменить на любой другой).
Примером использования SCAN LIBRARY в машинных кодах авляется, по сути, отдельная разработка - ARROW LIBRARY. Это библиотека процедур для управления передвижением стрелки по экрану. Она состоит из нескольких подпрограмм: формирование образа стрелки с сохранением изображения под ней, восстановление прежнего вида экрана, контроль перемещения стрелки и т. д.
ARROW LIBRARY - это интеллектуальный пользовательский интерфейс. Вы спросите: почему интеллектуальный? Все дело в том, что этот интерфейс как бы "подстраивается" под пользователя. Человек работает с какой-либо программой, перемещает стрелку по экрану, выбирая определенные пункты меню, рисуя и т. д. Но, если скорость стрелки будет постоянна, то при необходимости перегнать ее с одного края экрана к другому, пользователь неизбежно будет вынужден ждать, попусту теряя время. Можно попробовать этого избежать, увеличив скорость, но в итоге появится еще более неприятная проблема - снизится точность. Разъяренный USER, безбожно ругая очень нехорошими словами и программу, и программиста, ее написавшего, будет безрезультатно пытаться попасть в заветный пункт меню и, вполне вероятно, вскоре забросит эту программу куда подальше... Интелектуальный интерфейс действует более эффективно. Если человек, например, долго держит в нажатом состоянии кнопку "вправо", то через определенное число шагов скорость автоматически увеличивается. При отпускании кнопки, скорость вновь устанавливается минимальной. Так и организуется управление, более удобное для пользователя. Но хватит слов, больше дела... Вот листинг библиотеки ARROW LIBRARY: Listing 4.
Длина вместе с переменными (и с системой SCAN LIBRARY) равна 577 байт. Описание процедур:
ARWINT - автоматическая организация управления движением стрелки на экране. Изменение скорости происходит при продолжительном удерживании клавиш направлений. Нажатие FIRE - выход.
INITMV - инициализация изменяемых параметров стрелки (нач. скорость, число шагов, для увеличения скорости, число уровней увел. скорости).
MOVES - контроль нажатий клавиш, реагирование - изменение координат, скорости и т. д.
PUTARW - вывод стрелки на экран в текущих координатах.
GETARW - восстановление прежнего вида экрана под стрелкой.
INC_Y - расчет адреса следующей линии экрана. Используется множеством
различных графических процедур - можете использовать, вызывать.
Описание данных и переменных: ARW_X :db(0..255) - текущая X-координата стрелки ARW_Y :db(0..255) - текущая Y-координата стрелки
ARWXMN:db(0..255) - минимально возможное значение, принимаемое коор. X ARWXMX:db(0..255) - максимально возможное значение, принимаемое коор. X ARWYMN:db(0..255) - Y-м