ZX-Ревю 1991 №1 1990 г.

Machine code - оригинальный метод выполнения компрессии и декомпрессии экранной области.


В данной статье разобран оригинальный метод выполнения компрессии и декомпрессии экранной области "СПЕКТРУМА". Подробные комментарии позволяют использовать этот материал не только как полезную процедуру, но и как пособие тем, кто самостоятельно изучает программирование в машинных кодах и на языке АССЕМБЛЕРА.

ИНФОРКОМ выражает глубокую признательность И. Девятко из г. Нальчика, разработавшему и прокомментировавшему эти процедуры.

Техническое редактирование выполнено ИНФОРКОМом.

Экранная область в памяти компьютера начинается с адреса 16384 и занимает 6912 байтов. Если ваша программа содержит несколько картинок (экранов), то хранить их в памяти - дело довольно расточительное, поэтому желательно провести компрессию (архивацию) экрана перед отправлением его в память на хранение и, соответственно надо выполнять декомпрессию перед выдачей картинки на экран.

Если внимательно проанализировать содержимое экранной области памяти, то можно увидеть, что некоторые значения повторяются многократно. Предлагаемый здесь алгоритм основан на том, что если соседние ячейки не повторяются, то их значения просто переписываются в новую область, иначе переписываются первые два числа из группы повторяющихся, а за ними ставится двухбайтное число, показывающее количество повторений.

LD HL, 16364 LD ВС, 6911 LD DE, ADDR

1. ПРОГРАММА КОМПРЕССИИ

В HL -счетчик в экранной области.

- в BC -количество байтов экрана.

- в DE - адрес, в котором организуется хранение экрана.

Величину ADDR выберите сами. Экран содержит 6912 байтов, тем не менее мы

поместили в BC число 6911, и было это сделано вот почему. В дальнейшем мы организуем в BC счетчик повторений одинаковых байтов, т.е. эта регистровая пара будет работать "за двоих". Возникает необходимость как-то сообщить программе о том, что экранная область кончилась, для этого с последним 6912-ым байтом мы сделаем несложную манипуляцию. Мы сохраним его на стеке, а вместо него поставим инвертированную копию предпоследнего байта. Теперь мы можем компрессировать 6911 байтов, твердо зная, что 6912-ый снимем со стека. На АССЕМБЛЕРе это выглядят так:

ADD HL,BC ; HL = HL+BC, теперь в HL находится адрес последнего байта.

LD A,(HL) ; Значение последнего байта засылается в аккумулятор и

PUSH AF ; отправляется на стек.

DEC HL ; HL=HL-1. теперь в HL находится адрес предпоследнего байта.

LD A, (HL) ; Его значение поступает в аккумулятор.

CPL ; инвертируется и

INC HL ; копируется в последний

LD (HL),A ; байт.

После этого последний байт равен 255-предпоследний.

XOR А ; Сброс флага переноса.

Это необходимо потому, что далее мы применяем команду SBC, ведь простого вычитания SUB для двухбайтных чисел не бывает.

SBC HL,BC ;HL=HL-BC - установка в HL адреса начала компрессируемой области.

Мы могли бы эти операции и упростить, если бы пользовались готовыми значениями адресов, но мы этого не делали, чтобы процедура была универсальной и могла бы применяться и для компрессирования других областей памяти.

L0 LD A,(HL) LDI DEC C INC C JR HZ,L1 DEC B

В акк-р идет байт из исходной области

и переносится по адресу, на который указывает DE.

это проверка BC

на 0 и переход на

метку LK (конец),

если 0

INC B JR Z,LKON

Обычно проверку на ноль делают не так, а проще:

LD A, B OR C

В нашем случае этого делать нельзя, т. к. регистр А уже занят и пришлось бы его сохранять на стеке:

достигнут

PUSH AF

LD A, B

OR C

POP AF

но это уже работает не так быстро, как приведенный нами метод.

CP (HL)

Следующий байт равен предыдущему?

JR NZ, L0

Если нет, то на L0 (копирование).

LDI

Иначе копируем

PUSH BC

еще раз и запоминаем BC на стеке.

LD ВС, 0

организуем в BC счетчик повторов.

CP (HL)

следующий байт равен предыдущему?

JR NZ,L2

Если нет, то на L2 (восстановление прежнего состояния)

INC ВС

Наращиваем счетчик

INC HL

и переходим к следующему байту.

JR L3

Повторяем проверку

LD A, C

записываем в

LD (DE), А

приемник количество

INC (DE)

повторений,

LD A, B

взятое из ВС.

LD (DE), A

INC DE

DE=DE+1. После этого в DE содержится адрес первого пустого места в приемнике.

EX (SP),HL

HL coxp. на стеке и из стека установленное значение BC восстанавл. в HL,

XOR A

Сброс флага C.

SBC HL^

HL=HL-BC Теперь мы имеем в HL количество байтов, которое осталось компрессировать.

EX (SP,BC)

двухходовая переброска

POP BC

из HL в BC через стек с восстановлением HL.

LD A,B

проверка BC на 0

OR C

(на конец работы)

JR Z, L0

POP AF

Восстановление последнего байта и

LD (DE),A

напр. в приемник.

INC DE

DE=DE+1

PUSH DE

Переброска из DE в

POP BC

BC через стек.

RET

Выход.

L1

L3

L2

LK

Длина сжатого блока равна содержимому BC минус начальный адрес. Мы специально поместили результат в BC, чтобы из БЕЙСИКа по команде PRINT USR его можно было бы легко выдать на экран.

ПРИМЕР

Рассмотрим конкретный пример. Адрес трансляции программы примем 30000, а адрес хранения компрессированного экрана - 32766.

Адрес Маш

.код

Метка Мнемоника

7530

21

00 40

LD HL,16384

7533

01

FF 1A

LD ВС,6911

7536

11

00 80

LD DE,32768

7539

09

ADD HL,ВС

753А

LD A, (HL)

753В

F5

PUSH HL

753C

2B

DEC HL

753D

LD A,(HL)

753E

2F

CPL

753F

23

INC HL

7540

77

LD (HL), А

7541

AF

XOR A

7542

ED

42

SBC HL,BC

7544

7E

L0

LD A,(HL)

7546

ED

A0

LDI

7540

0D

DEC C

7549

INC C

754A

20

04

JR NZ,L1

754C

05

DEC B

754D

04

INC B

754E

28

20

JR Z, LK

7550

BE

L1

CP (HL)

7551

20

F2

JR NZ,L0

7553

ED

A0

LDI

7554

C5

PUSH ВС

7555

01

00 00

LD ВС, 00

7556

BE

L3

CP (HL)

7559

20

04

JR HZ,L2

755B

03

INC ВС

755C

23

INC HL

755D

18

F9

JR L3

755F

79

L2

LD A, С

7560

12

LD (DE),A

7561

13

INC DE

7562

78

LD A, B

7563

12

LD (DE),A

7564

13

INC DE

7565

E3

EX (SP),HL

7566

AF

XOR A

7567

ED

42

SBC HL, ВС

7569

E3

EX (SP),HL

756A

C1

POP ВС

756B

78

LD A, B

756C

B1

OR C

756D

2O

D5

JR NZ,L0

756F

F1

LK

POP AF

7570

12

LD (DE), A

7571

13

INC DE

7572

C9

RET

Загрузите в экран какую-либо картинку, вызовите из БЕЙСИКа компрессирующую программу PRINT USR 30000 и запомните число, которое получили, его надо будет указывать при декомпрессии.

Зная конечный адрес и начало, можно вычислить и длину: длина = результат-32768

Теперь можно выгрузить блок кодов: SAVE"имя"CODE 32768,длина. Процедуру декомпрессии мы дадим в следующем выпуске.




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
News - 3 ноября на улице, возвращаясь с работы, убит ножом Дмитрий Козлов (Dr.Envelope).
Games - Игры, которые ждет весь мир.
Рассказ - "Доктор Шахов" (окончание).
Мелочи - доработка ассемблера ALASМ 4.1.
Дневник oсликa Феди - юмористический рассказ.

В этот день...   29 марта