ZX-Ревю 1992 №9-10 1991 г.

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


Темы статьи: Программирование  

Маленькие хитрости

В этом разделе мы коснемся некоторых путей повышения быстродействия часто встречающихся операций.

Так, например, в предыдущей статье мы с Вами затронули маленький вопрос об очистке 256-байтного буфера. Давайте посмотрим, как бы мы делали эту операцию, если бы программировали в машинном коде.

Мы бы загрузили в регистровую пару HL адрес NN, с которого начинается наш буфер. Затем в регистре B организовали бы счетчик на 256 байтов (FFH), обнулили бы аккумулятор командой XOR и затем в цикле поместили бы содержимое аккумулятора в ячейки буфера, на которые указывает HL. При этом на каждом шаге увеличивали бы HL на единицу.

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

LD HL,NN (10)

LD B, FFH (7)

XOR A (4)

LOOP LD (HL),A (7)*256

INC HL (6)*256

DJNZ LOOP (8)*256

Давайте посмотрим сколько времени займет это мероприятие. В скобках проставлено время, необходимое для выполнения каждой из приведенных команд процессора. Это время измеряется в тактах работы процессора, а пересчет в секунды возможен, если знать частоту задающего генератора в вашем компьютере. Но нам достаточно и тактов, чтобы сравнить между собой различные приемы.

Итак, приведенный выше пример займет: 21 + 21*256 = 5397 тактов, т.е. в среднем 21,08 такта на очистку одного байта в буфере.

Можно ли быстрее? Скорее проще, чем быстрее. Те, кто знают машинный код, осведомлены о наличии команды LDIR, которая служит для автоматической очень быстрой переброски блоков данных из одной области памяти в другую. Эта команда перебрасывает блок байтов, длина которого установлена в регистровой паре BC из области, начинающейся с адреса, установленного в регистровой паре HL в область, на начало которой указывает содержимое DE. Остается открытым вопрос, а как можно использовать LDIR для очистки, ведь если эта команда может быстро перебросить блок нулевых байтов, то ведь такой блок надо сначала создать - в общем придем к тому, от чего ушли (мы не можем в общем случае рассчитывать на то, что где-то в компьютере есть пространства с нулевым содержимым ячеек, откуда можно черпать "пустые" массивы).

Оказывается, использовать LDIR все же можно, хоть и делается это несколько необычно. Рассмотрим пример:

LD HL, NN (10)

LD DE,NN+1 (10)

LD BC, 00FFH (10)

LD (HL),B (7)

LDIR (21)* 256

To, что здесь происходит, может показаться чепухой. В HL установили адрес начала нашего буфера, в DE - адрес второго байта буфера, в BC - счетчик на 255. Командой LD (HL),B очистили первый байт буфера, а потом зачем-то передвинули все содержимое буфера на один байт вверх. Ну получим в итоге, что и второй байт станет нулевым, а дальше-то что?

Вся хитрость состоит в том, что во время работы команды LDIR содержимое HL, DE и BC не остаются неизменными. После переброски каждого очередного байта HL и DE увеличиваются на единицу, а BC на единицу уменьшается. Благодаря этому после переброски первого байта во второй, DE уже укажет на третий, a HL "подхватит" нулевой байт из второй ячейки и так далее. В общем, весь буфер будет вычищен.

Итак, при работе с командой LDIR мы затратим: 37+21*256= 5413 тактов - это хоть и не быстрее, но, главное, изящнее. Получается в среднем 21.14 такта на байт.

Те, кто любят "маленькие хитрости", наверное, ждут, что мы предложим что-либо еще более скоростное, чем LDIR. Возможно, что большинство профессионалов сказали бы, что это невозможно, ничего быстрее LDIR для манипуляции с большими блоками памяти не бывает.

Но нет, оказывается, бывает, причем не просто быстрее, а быстрее в несколько раз. Есть одно гениальное решение, которое мы не постесняемся так назвать, поскольку не мы его придумали, а "выудили" его в результате анализа машинного кода программы "STARION" фирмы "Melbourne House". На поиски натолкнул тот факт, что программа в части межзвездных сражений не уступает "ELITE", a вот графика более динамичная, гладкая и плавная. Там это решение применяется не для очистки маленьких таблиц, а для освежения всей экранной памяти, а ее размер велик и там каждая тысячная доля секунды на счету.

Рассмотрим используемый алгоритм на нашем примере с очисткой 256-байтного буфера.

LD (MM),SP (20)

LD HL,0000 (10)

LD SP,KK (10)

LD B,80H (7)

LOOP PUSH HL (11)* 128

DJNZ LOOP (8)*128

LD SP,(MM) (20)

Вся хитрость состоит в использовании стека. Исходное положение вершины стека надо запомнить в каком угодно адресе MM затем приготавливаем регистровую пару HL -обнуляем ее. Новый стек организуем в нашем буфере. Но надо помнить, что стек в памяти компьютера "растет" сверху вниз. Поэтому, чтобы очистить весь буфер, мы должны начать не с его начала, а с конца. LD SP, KK - прогружает в качестве вершины стека конец нашего буфера. Счетчик байтов создаем в регистре B, как обычно, но поскольку здесь байты будут перебрасываться не по одному, а парами, то счетчик надо настраивать не на 256, а на 128 -(LD B,80H) перемещений.

Все подготовительные операции сделаны. Теперь в цикле 128 раз помещаем содержимое HL на вершину стека, то есть обнуляем буфер. Закончив операцию, надо не забыть восстановить старое значение указателя стека, временно сохраненное в ячейке MM.

Всего мы затратили:

67+19*128 = 2499 тактов, т.е. примерно по 9.76 такта на байт!

Встает старый вопрос: "А нельзя ли еще быстрее?"

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

LD (NN),SP

(20)

LD HL,0000

(10)

LD SP,KK

(10)

LD B,20H

(7)

PUSH HL

(11 )*32

PUSH HL

(11)*32

PUSH HL

(11)*32

PUSH HL

(11)*32

DJNZ LOOP

(8)*32

LD SP,(MM)

(20)

Всего имеем: 67+52*32 = 1731 - по 6,76 такта на байт.

Подумать только, с чего мы начинали! А ведь это еще не предел. При приличном количестве команд PUSH HL, как в STARION^, можно работать быстрее, чем с LDIR в четыре раза! И, конечно, такая скорость не нужна для освежения буфера - на самом деле это нужно для работы с экраном.

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




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Анкетирование - Результаты анкетирования о состоянии платформы ZX-Spectrum в странах бывшего СССР.
КлинМозгов - Жертвоприношение.
Железо - Блокировка порта #1FFD на Scorpion ZS-256.
Enlight'97 - Неофициальные итоги Enlight'a.
Реклама - Пpодам, куплю ,обменяю пpогpаммы для ZX Spectrum.

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