<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://emuverse.ru/w/index.php?action=history&amp;feed=atom&amp;title=Z80%2F%D0%9D%D0%B5%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B</id>
	<title>Z80/Недокументированные команды - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://emuverse.ru/w/index.php?action=history&amp;feed=atom&amp;title=Z80%2F%D0%9D%D0%B5%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B"/>
	<link rel="alternate" type="text/html" href="https://emuverse.ru/w/index.php?title=Z80/%D0%9D%D0%B5%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B&amp;action=history"/>
	<updated>2026-05-04T20:37:50Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://emuverse.ru/w/index.php?title=Z80/%D0%9D%D0%B5%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B&amp;diff=580&amp;oldid=prev</id>
		<title>Panther: Новая: {{ДИ|Автор=(с) Г. А. Лунтер (G.A.Lunter), Нидерланды, 1994; (с) Перевод с английского и техническое редактирование...</title>
		<link rel="alternate" type="text/html" href="https://emuverse.ru/w/index.php?title=Z80/%D0%9D%D0%B5%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B&amp;diff=580&amp;oldid=prev"/>
		<updated>2007-12-19T14:57:25Z</updated>

		<summary type="html">&lt;p&gt;Новая: {{ДИ|Автор=(с) Г. А. Лунтер (G.A.Lunter), Нидерланды, 1994; (с) Перевод с английского и техническое редактирование...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{ДИ|Автор=(с) Г. А. Лунтер (G.A.Lunter), Нидерланды, 1994; (с) Перевод с английского и техническое редактирование «Инфорком-Пресс», Москва, 1995.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Большинство операционных кодов процессора Z80 имеют в длину один байт (если не считать операндов). Но есть команды, в которых перед операционным кодом ставится префикс CB, DD, ED или FD, который изменяет значение следующего за ним операционного кода.&lt;br /&gt;
&lt;br /&gt;
Всего существует 248 операционных кодов с префиксом СВ. Целый блок таких команд от CB 30 до CB 37 выпал из официального списка. Это инструкции, которые можно обозначить мнемоникой SLL - Shift Left Logical - логический сдвиг операнда влево, при котором нулевой бит всегда становится равным единице. Такие программы как Bounder и Enduro Racer используют эти команды. Мой монитор, входящий в SamRam, дисассемблирует эту операцию и дает ей мнемонику SLL. Эта группа команд используется очень широко.&lt;br /&gt;
&lt;br /&gt;
Операционные коды DD и FD предшествуют инструкциям, использующим регистры IX и IY. Если вы посмотрите на инструкции внимательно, то увидите, как они работают:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   2A nn      LD HL,(nn)&lt;br /&gt;
DD 2A nn      LD IX,(nn)&lt;br /&gt;
&lt;br /&gt;
   7E         LD A,(HL)&lt;br /&gt;
DD 7E d       LD A,(IX+d) &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Префикс DD просто меняет значение HL в соответствующей инструкции&lt;br /&gt;
&lt;br /&gt;
Если к какому-то байту в памяти проходит косвенная адресация через HL, как показано во втором примере, то добавляется еще байт смещения. В прочих случаях инструкция просто относится к регистру IX, а не к регистру HL. (Кстати, по поводу широкораспространенной путаницы в записи команд, обратите внимание, что JP (HL) - не является косвенной адресацией и путает как программистов, так и авторов ассемблеров и дисассемблеров. Правильно было бы писать JP HL).&lt;br /&gt;
&lt;br /&gt;
Если же код DD поставить перед командой, которая не использует регистр HL, то команда будет исполняться как обычно. Однако, есть исключение для тех команд, которые работают отдельно с регистрами H и L. Если перед ними поставить префикс DD, то они начинают работать с половинками регистровой пары IX, которым нет имен и потому их называют так: IXh - старшая половинка; IXl - младшая половинка. Пример операции:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    44        LD B,H&lt;br /&gt;
    DD 44     LD B,IXh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Совершенно аналогично все происходит и с префиксом FD, только теперь все команды относятся не к IX, а к IY. Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    44        LD B,H&lt;br /&gt;
    FD 44     LD B,IYh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Недокументированные команды этого типа встречаются в очень многих программах. Кстати, иногда применяют длинную последовательность DD или FD для имитации NOP. Такая последовательность не делает ничего, кроме как поочередно перещелкивает флаг &amp;quot;восприятия HL в качестве IX&amp;quot; и тратит на каждом шаге по 4 такта. Но зато попробуйте продисассемблировать такой кусок с помощью MONS&amp;#039;а!&lt;br /&gt;
&lt;br /&gt;
Операции с двойным префиксом DD CB и DD ED ведут себя иначе. Если DD (или FD) стоит перед инструкцией, начинающейся с ED, то DD или FD игнорируются, поскольку операции начинающиеся с ED никогда не работают с регистрами IX и IY. Операция исполняется нормально (без префикса). С инструкциями, начинающимися с префикса CB дело иное, здесь ситуация более интересна и ее мы рассмотрим подробнее.&lt;br /&gt;
&lt;br /&gt;
Прежде всего, обратите внимание на то, что все инструкции, начинающиеся с CB, можно разбить на блоки по 8 инструкций в каждом. Эти 8 инструкций блока относятся к A, B, C, D, E, H, L, (HL). И тогда общее правило поведения инструкции, перед которой стоит двойной префикс DD CB (или FD CB) будет таким:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Внутри блока из 8-ми инструкций действие каждой команды DD CB ... эквивалентно действию документированной команды CB ..., за исключением того, что параллельно происходит копирование результата в заказанный регистр, кроме тех случаев, когда он (HL)&amp;quot;. Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    CB CE         SET 0,(HL)&lt;br /&gt;
    DD CB nn CE   SET 0,(IX+nn) - нет копирования, поскольку имели дело с (HL).&lt;br /&gt;
&lt;br /&gt;
    CB C0         SET 0,B&lt;br /&gt;
    DD CB nn C0   SET 0,(IX+nn) - результат копируется и в регистр B тоже. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Есть немало недокументированных инструкций, начинающихся с префикса ED, но полезность их непонятна. В диапазонах 00...3F и 80...FF команды с префиксом ED вообще ничего не делают (конечно кроме команд, связанных с обработкой блоков). Но они во-первых занимают по 8 тактов и, во-вторых, увеличивают регистр R на 2. Может быть это и можно где-то использовать.&lt;br /&gt;
&lt;br /&gt;
Больший эффект эти команды имеют в диапазоне 40...7F. Здесь мы приводим их список. Знаком * помечены недокументированные команды.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ED40	IN B,(C)	ED60	IN H,(C)&lt;br /&gt;
ED41	OUT (C),B	ED61	OUT (C),H&lt;br /&gt;
ED42	SBC HL,BC	ED62	SBC HL,HL&lt;br /&gt;
ED43	LD (nn),BC	ED63 *	LD (nn),HL&lt;br /&gt;
ED44	NEG	ED64 *	NEG&lt;br /&gt;
ED45	RETN	ED65 *	RET&lt;br /&gt;
ED46	IM 0	ED66 *	IM 0&lt;br /&gt;
ED47	LD I,A	ED67	RRD&lt;br /&gt;
ED48	IN C,(C)	ED68	IN L,(C)&lt;br /&gt;
ED49	OUT (C),C	ED69	OUT (C),L&lt;br /&gt;
ED4A	ADC HL,BC	ED6A	ADC HL,HL&lt;br /&gt;
ED4B	LD BC,(nn)	ED6B *	LD HL,(nn)&lt;br /&gt;
ED4C *	NEG	ED6C *	NEG&lt;br /&gt;
ED4D	RETI	ED6D *	RET&lt;br /&gt;
ED4E *	IM 0	ED6E *	IM 0&lt;br /&gt;
ED4F	LD R,A	ED6F	RLD&lt;br /&gt;
ED50	IN D,(C)	ED70 *	IN (C)&lt;br /&gt;
ED51	OUT (C),D	ED71 *	OUT (C),0&lt;br /&gt;
ED52	SBC HL,DE	ED72	SBC HL,SP&lt;br /&gt;
ED53	LD (nn),DE	ED73	LD (nn),SP&lt;br /&gt;
ED54 *	NEG	ED74 *	NEG&lt;br /&gt;
ED55 *	RET	ED75 *	RET&lt;br /&gt;
ED56	IM 1	ED76 *	IM 1&lt;br /&gt;
ED57	LD A,I	ED77 *	NOP&lt;br /&gt;
ED58	IN E,(C)	ED78	IN A,(C)&lt;br /&gt;
ED59	OUT (C),E	ED79	OUT (C),A&lt;br /&gt;
ED5A	ADC HL,DE	ED7A	ADC HL,SP&lt;br /&gt;
ED5B	LD DE,(nn)	ED7B	LD SP,(nn)&lt;br /&gt;
ED5C *	NEG	ED7C *	NEG&lt;br /&gt;
ED5D *	RET	ED7D *	RET&lt;br /&gt;
ED5E	IM 2	ED7E *	IM 2&lt;br /&gt;
ED5F	LD A,R	ED7F *	NOP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Инструкция ED 70 читает данные из порта, номер которого установлен в регистре С так же, как и другие аналогичные инструкции, но результат... выбрасывает. Единственное, что от ее работы остается - измененные флаги.&lt;br /&gt;
&lt;br /&gt;
Интересна инструкция ED 71 - она выставляет на внешний порт нуль.&lt;br /&gt;
&lt;br /&gt;
Можно догадаться, что в этих двух инструкциях (если учесть регулярность набора системы команд процессора) должны были бы быть команды IN (HL),(C) и OUT (HL),(C). Но процессор Z80 в одной команде дважды к памяти обращаться не может. А внешний порт для то же, что и память. Поэтому такие команды и отсутствуют. Кстати, насчет того, чтобы дважды обращаться в память... - обратите внимание на то, что существуют команды LD A,A; LD B,B, но отсутствует LD (HL),(HL) и вместо нее стоит HALT.&lt;br /&gt;
&lt;br /&gt;
Инструкции ED 4E и ED 6E - эквиваленты команде IM0. Когда в момент прихода прерываний на шине данных стоит FF, Спектрум продолжает нормально работать, но если на шине стоит EF (RST #28), то он сбрасывается - все точно так же, как и в документированном режиме IM0. В режиме IM 1 Z80 исполняет только RST #38 (код FF), независимо от того, что стоит на шине.&lt;br /&gt;
&lt;br /&gt;
Команда RETI - функционально эквивалентна команде RET. Она используется только для того, чтобы дать понять внешнему устройству о том, что исполнение процедуры, обрабатывающей прерывания, закончилось. В то же время, команда RETN - отличается от RET тем, что она устанавливает триггер прерываний IFF1 в текущее значение триггера IFF2. Обычно IFF1 и IFF2 равны между собой (они выравниваются после DI и EI и после приема маскируемого прерывания). Они становятся разными только если происходит немаскируемое прерывание, когда прерывания разрешены. В этом случае IFF1 выключен, а IFF2, сохраняющий предыдущее состояние триггера прерываний, включен и это обозначает, что к моменту прихода немаскируемого прерывания, прерывания были разрешены. Поскольку состояние IFF2 может быть прочитано с помощью LD A,R и LD A,I, то инструкция RETN не используется в ПЗУ Спектрума и бесполезна в обычном программном обеспечении. Другими словами, я и не пытался устанавливать, являются ли неофициальные RET&amp;#039;ы командами RETI или RETN.&lt;br /&gt;
&lt;br /&gt;
Теперь о регистре R. Его нельзя назвать недокументированной особенностью, но подробного описания его я пока тоже нигде не встречал. Фактически это счетчик, который изменяется после исполнения каждой команды. Причем префиксы DD, FD, ED ,CB с его точки зрения рассматриваются как самостоятельные команды, поэтому инструкции с этими префиксами увеличивают регистр R на 2. Интересно, что если команде предшествует двойной префикс DD CB или FDCB, то она тоже увеличивает регистр R на 2. LDIR увеличивает регистр R на 2, умноженное на содержимое BC, то же LDDR и им подобные команды. Последовательность команд LD R,A / LD A,R увеличивает аккумулятор на 2. Старший бит регистра R никогда не меняется (кроме, конечно, команды LD R,A). Это происходит потому, что в старинные времена использовались микросхемы памяти на 16 килобит. Внутри микросхемы биты группировались в матрицу 128 Х 128 и для регенерации памяти достаточно было 7-разрядного цикла. Поэтому фирма ZILOG и решила, что им хватит для регенерации 7-ми битов от регистра R. Если эмуляция регистра R включена, то он ведет себя точно так же, как на Спектруме. Если же она выключена, то регистр R ведет себя как генератор случайных чисел (за исключением старшего байта).&lt;br /&gt;
&lt;br /&gt;
Вы можете легко убедиться в том, насколько важен регистр R для регенерации памяти. ассемблируйте следующую программу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    ORG 32768&lt;br /&gt;
    DI&lt;br /&gt;
    LD B,0 L1  XOR A&lt;br /&gt;
    LD R,A&lt;br /&gt;
    DEC HL&lt;br /&gt;
    LD A,H&lt;br /&gt;
    OR L&lt;br /&gt;
    JR NZ,L1&lt;br /&gt;
    DJNZ L1&lt;br /&gt;
    EI&lt;br /&gt;
    RET&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она будет работать примерно три минуты. После этого загляните в верхние 32К памяти, например в область символов UDG. Вы увидите, что они порушены. Только несколько первых байтов внутри каждого 256-байтного блока будут все еще содержать нули, поскольку они регенерировались во время исполнения цикла. С нижними 16К ОЗУ все будет в порядке, поскольку их регенерацией занимается ULA.&lt;br /&gt;
&lt;br /&gt;
Есть еще один неосвещенный участок в процессоре Z80, который оказывает свое влияние на некоторые программы, например Sabre Wulf, Ghosts&amp;#039;n Goblins и Speedlock. Это недокументированные флаги!&lt;br /&gt;
&lt;br /&gt;
Биты 3 и 5 флагового регистра F не используются. Но они могут содержать информацию и она может быть использована, поскольку существуют такие очевидные команды, как PUSH AF и POP AF. Но, тем не менее, иногда все-таки содержимое этих флагов изменяется. Я нашел следующее эмпирическое правило:&lt;br /&gt;
&lt;br /&gt;
Значения битов 7,5,3 повторяют значения соответствующих битов последнего 8-битного результата инструкции, которая меняла обычные флаги.&lt;br /&gt;
&lt;br /&gt;
Например, после команды ADD A,B эти биты будут идентичны битам в регистре A. Бит 7 регистра F - это знаковый бит и он, естественно, по определению всегда следует этому правилу. исключением является команда CP x (где x - регистр или (HL) или прямой аргумент). В этом случае биты копируются не с результата, а с аргумента.&lt;br /&gt;
&lt;br /&gt;
Для инструкций, которые оперируют с двухбайтными операндами, 8 битов, подпадающие под выведенное правило - это старшие 8 битов из 16-битного результата. Этого и следовало ожидать, поскольку здесь знаковым является старший 15-ый бит.&lt;br /&gt;
&lt;br /&gt;
Ghosts&amp;#039;n Goblins используют недокументированные флаги вследствие ошибки программиста. В программе Sabre Wulf неестественно ведет себя носорог, который иногда бегает малыми кругами в углах, если знаковый бит по команде BIT вычисляется неправильно. Я процитирую:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    AD86    DD CB 06 7E	BIT 7,(IX+6)&lt;br /&gt;
    AD8A    F2 8F AD	JP P,#AD8F&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Удивительный образец кода! А что же касается &amp;quot;Спидлока&amp;quot;, то он выделывает такое количество непонятных и головоломных трюков, что для того, чтобы он работал, в эмуляторе все должно точнехонько соответствовать реальному Спектруму.&lt;br /&gt;
&lt;br /&gt;
Ну и, наконец, в 128-ом ПЗУ тоже есть необычное использование регистра AF - там он использован для временного хранения адреса перехода к подпрограмме.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Zilog Z80]]&lt;/div&gt;</summary>
		<author><name>Panther</name></author>
	</entry>
</feed>