Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Влияние команды OUTD на флаг переноса

(ZX.SPECTRUM,
 Insanity #7,
 «Радиолюбитель. Ваш компьютер» 5/2001, «Радиомир. Ваш компьютер» 8/2003 (под псевдонимом BV_Creator))
Дополненная версия. Дата последнего редактирования: 20.04.2003.

При написании одной программы мне понадобилось наиболее оптимально (по объёму) реализовать запись данных в первые 11 регистров музыкального сопроцессора из области памяти #8000—#800A. Сначала я сделал это так:

        LD     HL,#800A
M1      LD     BC,#FFFD
        OUT    (C),L
        LD     B,#BF
        OUTD
        BIT    7,L
        JR     Z,M1

При трассировке я заметил, что при последнем повторе цикла после команды OUTD флаг C оказался равным 1 (а при предыдущих повторах цикла он был сброшен). Естественно, этот факт был тут же использован для оптимизации:

        LD     HL,#800A
M1      LD     BC,#FFFD
        OUT    (C),L
        LD     B,#BF
        OUTD
        JR     NC,M1

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

В различных справочниках про влияние команды OUTD на флаги написано, что, во-первых, она устанавливает в 1 флаг N, и во-вторых, если в результате выполнения команды регистр B обнуляется, то флаг Z равен 1, иначе — 0. Про остальные флаги сказано лишь, что их значения после выполнения команды не определены.

Я предположил, что флаг переноса устанавливается, когда при уменьшении HL изменяется регистр H (как в приведённом примере, когда HL уменьшается с #8000 до #7FFF). При проведении экспериментов это подтвердилось, но при одном условии: в ячейке памяти, адресуемой HL, должен быть не 0. Если там будет 0, то флаг C всегда будет сброшен.

Знание этой особенности Z80 позволяет в некоторых случаях сократить программу и уменьшить время её выполнения. Приведённый выше пример это наглядно демонстрирует. Может быть, кому-то это пригодится: бывает ведь, что при создании intro не хватает всего одного-двух свободных байтов памяти…

Кстати, заодно выяснилось, что флаг N устанавливается в 1 далеко не всегда. Вот, проверьте сами: при HL=#8000, (HL)=0, BC=#BFFD, после команды OUTD флаг N будет сброшен. А достаточно при тех же значениях регистров поместить в (HL), скажем, #FF — и после OUTD этот флаг будет установлен.

Эксперименты проводились на оригинальном процессоре Z80 фирмы ZiLOG и на отечественном аналоге КР1858ВМ1.

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

Я понимаю, что, возможно, кто-то уже проводил подобные исследования, и для него написанное мной не является секретом (и уж точно знали об этом разработчики Z80). Но мне такая информация нигде не встречалась, и я решил сделать её достоянием общественности.

Дополнение

К сожалению, изложенный выше алгоритм установки флага переноса оказался не вполне точным. Я узнал об этом, ознакомившись с [1] — наиболее полным, на мой взгляд, обзором недокументированных особенностей Z80. Там сказано, что флаг переноса при выполнении команды OUTD формируется по результату сложения выданного в порт числа и значения регистра L (после уменьшения HL). Т.е. если результат сложения оказывается больше 255, флаг переноса устанавливается, иначе — сбрасывается. Проверив эту информацию на реальном Z80, я убедился в её правильности.

Источники

  1. Sean Young. “The Undocumented Z80 Documented”.
    Этот документ доступен на сайте www.z80.info (полный адрес документа — http://www.z80.info/zip/z80-documented.pdf), а также на сайте его автора — www.msxnet.org (в разделе «MSX Technical» находятся pdf- и LATEX-версии документа).

Другие мои статьи о недокументированных особенностях процессора Z80:

Другие мои статьи о различных приёмах оптимизации при программировании на ассемблере Z80:

1. 

«По поводу релоцируемых программ». «ZX-Ревю» 5—6/1997.

2. 

«Z80: оптимизация загрузки констант в регистры». «Радиолюбитель. Ваш компьютер» 9/2000, 2/2001 (под псевдонимом BV_Creator).

3. 

«Ещё о программировании арифметических операций». «Радиолюбитель. Ваш компьютер» 12/2000, 1—4/2001.

4. 

«Оптимизация на примере intro „Start“». «Радиомир. Ваш компьютер» 7—10/2001.

5. 

«Менеджер вызова подпрограмм из различных банков памяти». «Радиомир. Ваш компьютер» 12/2001, 2/2002, 4/2002.

6. 

«Улучшение сжатия программ на ассемблере Z80». «Радиомир. Ваш компьютер» 4/2003.

7. 

«Процедура сравнения строк на ассемблере Z80». «Радиомир. Ваш компьютер» 6/2003.

Страница Ивана Рощина > Статьи >