Zilog Z80/Система команд: различия между версиями
Panther (обсуждение | вклад) (Ошибка с чтением IFF2) |
Panther (обсуждение | вклад) |
||
Строка 1509: | Строка 1509: | ||
* '''PC''' — указатель текущей команды. '''PCH''' и '''PCL''' — старший и младший байты, соответственно; | * '''PC''' — указатель текущей команды. '''PCH''' и '''PCL''' — старший и младший байты, соответственно; | ||
* '''SP''' — указатель стека; | * '''SP''' — указатель стека; | ||
* '''F''' — Регистр флагов** '''S''': SIGN/Знак. Копия старшего бита результата операции. | * '''F''' — Регистр флагов | ||
** '''S''': SIGN/Знак. Копия старшего бита результата операции. | |||
** '''Z''': ZERO/Ноль. Равен 1, если результат равен 0. | ** '''Z''': ZERO/Ноль. Равен 1, если результат равен 0. | ||
** '''*F5''': Если не оговорено обратное, равен 5-му биту результата. | ** '''*F5''': Если не оговорено обратное, равен 5-му биту результата. |
Версия от 10:04, 20 февраля 2008
Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0. |
В этой статье и ее подстраницах представлены все необходимые данные для создания полноценного эмулятора процессора Z80, включая все недокументированные команды, флаги и особенности поведения в разных режимах (по крайнем мере те, что удалось найти). Статья написана на основе фирменной документации, а также большого количества материалов в Интернете, в основном, на английском языке.
Статья написана с точки зрения создателя эмулятора — максимум сведений по каждой команде приведен в общей таблице (за исключением тех случаев, когда это невозможно в силу объема), вместо словесных описаний большинства команд приводятся алгоритмы их работы. Команды перечислены в порядке, удобном для написания эффективного блока декодирования, поэтому принцип увеличения кодов сохраняется не везде.
Подразумевается, что читатель знаком с базовыми принципами и архитектурой микропроцессоров, поэтому объяснения многих понятий, без знания которых приступать к написанию эмулятора бессмысленно, опущены. Если вы считаете, что нечто важное не упомянуто зря, то дайте знать автору (или дополните сами ;).
Для удобства активной работы с большими таблицами все условные обозначения приведены после них. Часть объемных материалов, например, по эмуляции команды DAA, вынесено на подстраницы.
Список команд
Команды без префикса
Код | Данные | Команда | Действие | Флаги | Такты | Байты | Примечание | |
---|---|---|---|---|---|---|---|---|
2 | 16 | SZ5H3VNC | ||||||
Без префикса | ||||||||
Группа 00 | ||||||||
00 000 000 | 00 | NOP | -------- | 4 | 1 | |||
00 001 000 | 08 | EX AF, AF' | AF <-> AF' | ******** | 4 | 1 | ||
00 010 000 | 10 | d | DJNZ d | B <- B-1 Если B<>0 то PC <- PC+d |
-------- | 13/8 | 2 | PC равен адресу следующей за DJNZ команды |
00 011 000 | 18 | d | JR d | PC <- PC+d | -------- | 12 | 2 | PC равен адресу следующей команды |
00 1СС 000 | d | JR СС, d | Если СС то PC <- PC+d | -------- | 12/7 | 2 | PC равен адресу следующей команды СС включает первые 4 значения CCC | |
00 RP0 001 | nn | LD RP, nn | RP <- nn | -------- | 10 | 3 | ||
00 RP1 001 | ADD HL, RP | HL <- HL + RP | --***-0C | 11 | 1 | F5,H,F3 берутся по результатам сложения старших байтов | ||
00 0X0 010 | LD [X], A | [X] <- A | -------- | 7 | 1 | X=0 => BC, X=1 => DE | ||
00 0X1 010 | LD A, [X] | A <- [X] | -------- | 7 | 1 | X=0 => BC, X=1 => DE | ||
00 100 010 | 22 | nn | LD [nn], HL | [nn] <- HL | -------- | 16 | 3 | |
00 101 010 | 2A | nn | LD HL, [nn] | HL <- [nn] | -------- | 16 | 3 | |
00 110 010 | 32 | nn | LD [nn], A | [nn] <- A | -------- | 13 | 3 | |
00 111 010 | 3A | nn | LD A, [nn] | A <- [nn] | -------- | 13 | 3 | |
00 RP0 011 | INC RP | RP <- RP+1 | -------- | 6 | 1 | |||
00 RP1 011 | DEC RP | RP <- RP-1 | -------- | 6 | 1 | |||
00 SSS 100 | INC SSS | SSS <- SSS+1 | SZ5H3V0- | 4/11/19* | 1 | V=1, если SSS=7F до операции | ||
00 SSS 101 | DEC SSS | SSS <- SSS-1 | SZ5H3V1- | 4/11/19* | 1 | V=1, если SSS=80 до операции | ||
00 DDD 110 | d | LD DDD, d | DDD <- d | -------- | 7/7/15* | 2 | ||
00 000 111 | 07 | RLCA | Цикл. сдвиг A влево, CY<-A7 | --503-0C | 4 | 1 | См. #Команды сдвига | |
00 001 111 | 0F | RRCA | Цикл. сдвиг A вправо, CY<-A0 | --503-0C | 4 | 1 | См. #Команды сдвига | |
00 010 111 | 17 | RLA | Цикл. сдвиг A+CY влево | --503-0C | 4 | 1 | См. #Команды сдвига | |
00 011 111 | 1F | RRA | Цикл. сдвиг A+CY вправо | --503-0C | 4 | 1 | См. #Команды сдвига | |
00 100 111 | 27 | DAA | Десятичная коррекция | SZ5*3P-* | 4 | 1 | См. /DAA | |
00 101 111 | 2F | CPL | A <- NOT A | --*1*-1- | 4 | 1 | F3 и F5 из A | |
00 110 111 | 37 | SCF | CY = 1 | --*0*-01 | 4 | 1 | F3 и F5 из A | |
00 111 111 | 3F | CCF | CY <- NOT CY | --***-0C | 4 | 1 | H <- старый C, F3 и F5 из A | |
Группа 01 | ||||||||
01 110 110 | 76 | HALT | -------- | 4 | 1 | Повторяет циклы NOP до прерывания или сброса | ||
01 DDD 110 | LD DDD, [HL] | DDD <- [HL] | -------- | 7/15* | 1 | |||
01 110 SSS | LD [HL], SSS | [HL] <- SSS | -------- | 7/15* | 1 | |||
01 DDD SSS | LD DDD, SSS | DDD <- SSS | -------- | 4 | 1 | DDD и SSS не равны 110 | ||
Группа 10 | ||||||||
10 000 SSS | ADD A, SSS | A <- A+SSS | SZ5H3V0C | 4/7/15* | 1 | |||
10 001 SSS | ADC A, SSS | A <- A+SSS+CY | SZ5H3V0C | 4/7/15* | 1 | |||
10 010 SSS | SUB A, SSS | A <- A-SSS | SZ5H3V1C | 4/7/15* | 1 | |||
10 011 SSS | SBC A, SSS | A <- A-SSS-CY | SZ5H3V1C | 4/7/15* | 1 | |||
10 100 SSS | AND A, SSS | A <- A AND SSS | SZ513P00 | 4/7/15* | 1 | |||
10 101 SSS | XOR A, SSS | A <- A XOR SSS | SZ503P00 | 4/7/15* | 1 | |||
10 110 SSS | OR A, SSS | A <- A OR SSS | SZ503P00 | 4/7/15* | 1 | |||
10 111 SSS | CP SSS | A-SSS | SZ*H*V1C | 4/7/15* | 1 | F5 и F3 - копия SSS | ||
Группа 11 | ||||||||
11 CCC 000 | RET CCC | Если CCC то PCL <- [SP] PCH <- [SP+1] SP <- SP+2 |
-------- | 11/5 | 1 | |||
11 RP0 001 | POP RP | RPH <- [SP] RPL <- [SP+1] SP <- SP+2 |
-------- ******** |
10 | 1 | Если RP=3, то подразумевается AF, а не SP | ||
11 001 001 | C9 | RET | PCL <- [SP] PCH <- [SP+1] SP <- SP+2 |
-------- | 10 | 1 | ||
11 011 001 | D9 | EXX | BC,DE,HL <-> BC',DE',HL' | -------- | 4 | 1 | ||
11 101 001 | E9 | JP [HL] | PC <- HL | -------- | 4 | 1 | С префиксами становится JP [IX], а не JP [IX+d] | |
11 111 001 | F9 | LD SP,HL | SP <- HL | -------- | 6 | 1 | ||
11 CCC 010 | nn | JP CCC, [nn] | Если CCC то PC <- nn | -------- | 10 | 3 | ||
11 000 011 | C3 | nn | JP nn | PC <- nn | -------- | 10 | 3 | |
11 001 011 | CB | Префикс | ||||||
11 010 011 | D3 | d | OUT (d),A | [Ad] <- A | -------- | 11 | 2 | Номер порта в реальности 16-разрядный |
11 011 011 | DB | d | IN A, (d) | A <- [Ad] | -------- | 11 | 2 | Номер порта в реальности 16-разрядный |
11 100 011 | E3 | EX (SP),HL | [SP] <-> HL | -------- | 19 | 1 | ||
11 101 011 | EB | EX DE,HL | DE <-> HL | -------- | 4 | 1 | Префиксы игнорируются | |
11 110 011 | F3 | DI | IFF1 <- 0 IFF2 <- 0 | -------- | 4 | 1 | Запрет прерывания | |
11 111 011 | FB | EI | IFF1 <- 1 IFF2 <- 1 | -------- | 4 | 1 | Разрешение прерывания. До завершения следующей команды проверка на INT блокируется (как после NONI) | |
11 ССС 100 | nn | CALL ССС, [nn] | Если ССС то SP <- SP-2 [SP] <- PCL [SP+1] <- PCH PC <- nn |
-------- | 17/10 | 3 | ||
11 RP0 101 | PUSH RP | SP <- SP-2 [SP] <- RPL [SP+1] <- RPH |
-------- | 11 | 1 | Если RP=3, то подразумевается AF, а не SP | ||
11 001 101 | CD | nn | CALL [nn] | SP <- SP-2 [SP] <- PCL [SP+1] <- PCH PC <- nn |
-------- | 17 | 3 | |
11 011 101 | DD | Префикс | ||||||
11 101 101 | ED | Префикс | ||||||
11 111 101 | FD | Префикс | ||||||
11 000 110 | C6 | d | ADD A, d | A <- A+d+CY | SZ5H3V0C | 7 | 2 | |
11 001 110 | CE | d | ADC A, d | A <- A+d+CY | SZ5H3V0C | 7 | 2 | |
11 010 110 | D6 | d | SUB A, d | A <- A-d | SZ5H3V1C | 7 | 2 | |
11 011 110 | DE | d | SBC A, d | A <- A-d-CY | SZ5H3V1C | 7 | 2 | |
11 100 110 | E6 | d | AND A, d | A <- A AND d | SZ513P00 | 7 | 2 | |
11 101 110 | EE | d | XOR A, d | A <- A XOR d | SZ503P00 | 7 | 2 | |
11 110 110 | F6 | d | OR A, d | A <- A OR d | SZ503P00 | 7 | 2 | |
11 111 110 | FE | d | CP A, d | A-d | SZ*H*V1C | 7 | 2 | F5 и F3 - копия d |
11 NNN 111 | RST NNN | [SP-1] <- PCH [SP-2] <- PCL SP <- SP-2 PCH <- 0 PCL <- NNN*8 |
-------- | 11 | 1 |
Префикс CB
Код | Данные | Команда | Действие | Флаги | Такты | Байты | Примечание | |
---|---|---|---|---|---|---|---|---|
2 | 16 | SZ5H3VNC | ||||||
11 001 011 00 rot SSS |
CB xx |
rot SSS *SLL SSS |
Битовый сдвиг | SZ503P0C | 8/15* | 2 | rot=110 (SLL) - недок. | |
11 001 011 01 bit SSS |
CB xx |
BIT bit, SSS | SSS AND 2^bit | *Z513*0- | 8/12* | 2 | Установка флагов - см. /BIT | |
11 001 011 10 bit SSS |
CB xx |
RES bit, SSS | SSS <- SSS AND NOT(2^bit) | -------- | 8/15* | 2 | ||
11 001 011 11 bit SSS |
CB xx |
SET bit, SSS | SSS <- SSS OR 2^bit | -------- | 8/15* | 2 |
Префикс ED
Код | Данные | Команда | Действие | Флаги | Такты | Байты | Примечание | |
---|---|---|---|---|---|---|---|---|
2 | 16 | SZ5H3VNC | ||||||
Группа 00 | ||||||||
11 101 101 00 XXX XXX |
ED xx |
INVALID | NOP/NONI | -------- | 8 | 2 | R увеличивается на 2 (далее аналогично) | |
Группа 01 | ||||||||
11 101 101 01 110 000 |
ED 70 |
*IN F, [C] | IN[BC] | SZ503P0- | 12? | 2 | Меняются только флаги Номер порта в реальности 16-разрядный | |
11 101 101 01 DDD 000 |
ED xx |
IN DDD, [C] | DDD <- IN[BC] | SZ503P0- | 12 | 2 | DDD кроме 110 | |
11 101 101 01 110 001 |
ED 71 |
*OUT [C], 0 | OUT[BC] <- 0 | -------- | 12 | 2 | ||
11 101 101 01 SSS 001 |
ED xx |
OUT [C], SSS | OUT[BC] <- SSS | -------- | 12 | 2 | SSS кроме 110 Номер порта в реальности 16-разрядный | |
11 101 101 01 RP0 010 |
ED xx |
SBC HL, RP | HL <- HL-RP-C | SZ***V1C | 15 | 2 | См. ADD HL, RP | |
11 101 101 01 RP1 010 |
ED xx |
ADC HL, RP | HL <- HL+RP+C | SZ***V0C | 15 | 2 | См. ADD HL, RP | |
11 101 101 01 RP0 011 |
ED xx |
nn | LD [nn], RP | [nn] <- RP | -------- | 20 | 4 | |
11 101 101 01 RP1 011 |
ED xx |
nn | LD RP, [nn] | RP <- [nn] | -------- | 20 | 4 | |
11 101 101 01 XXX 100 |
ED 44 |
NEG/*NEG | A <- 0-A | SZ5H3V1C | 8 | 2 | XXX<>0 недок PV=1 если перед операцией A=80 С=1 если перед операцией A<>0 | |
11 101 101 01 001 101 |
ED 4D |
RETI | IFF1 <- IFF2 SP <- SP+2 PC <- [SP-2] |
-------- | 14 | 2 | Возврат из INT | |
11 101 101 01 XXX 101 |
ED xx |
RETN *RETN |
IFF1 <- IFF2 SP <- SP+2 PC <- [SP-2] |
-------- | 14 | 2 | Возврат из NMI XXX=1 => RETI XXX>1 недок. | |
11 101 101 01 X00 110 |
ED 46 |
IM 0/*IM 0 | IM <- 0 | -------- | 8 | 2 | X=1 недок | |
11 101 101 01 X01 110 |
ED 4E |
*IM 0/1 | IM <- 0/1? | -------- | 8 | 2 | Устанавливается один из режимов, какой - по одним источникам неизвестно, по другим IM 0 | |
11 101 101 01 X10 110 |
ED 56 |
IM 1/*IM 1 | IM <- 1 | -------- | 8 | 2 | X=1 недок | |
11 101 101 01 X11 110 |
ED 5E |
IM 2/*IM 2 | IM <- 2 | -------- | 8 | 2 | X=1 недок | |
11 101 101 01 000 111 |
ED 47 |
LD I, A | I <- A | -------- | 9 | 2 | ||
11 101 101 01 001 111 |
ED 4F |
LD R, A | R <- A | -------- | 9 | 2 | ||
11 101 101 01 010 111 |
ED 57 |
LD A, I | A <- I PV <- IFF2 |
SZ503*0- | 9 | 2 | Известная ошибка: если в момент выполнения команды получено прерывание, то в PV вместо 1 ошибочно попадает 0. Есть программы, которые строят на этом защиту от эмуляции. | |
11 101 101 01 011 111 |
ED 5F |
LD A, R | A <- R PV <- IFF2 |
SZ503*0- | 9 | 2 | См. LD A, I Значение в A равно R выполнения инструкции | |
11 101 101 01 100 111 |
ED 67 |
RRD | SZ503P0- | 18 | 2 | Флаги по результату в A | ||
11 101 101 01 101 111 |
ED 6F |
RLD | SZ503P0- | 18 | 2 | См. RRD | ||
11 101 101 01 11X 111 |
ED xx |
NOP | -------- | 8? | 2 | |||
Группа 10 | ||||||||
11 101 101 10 0XX XXX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 | ||
11 101 101 10 100 000 |
ED A0 |
LDI | [DE] <- [HL] DE <- DE+1 HL <- HL+1 BC <- BC-1 |
--*0**0- | 16 | 2 | PV=1 если после декремента BC<>0 F3=бит 3 операции переданный байт + A F5=бит 1 операции переданный байт + A R увеличивается на 2 (далее аналогично) | |
11 101 101 10 100 001 |
ED A1 |
CPI | A-[HL] HL <- HL+1 BC <- BC-1 |
SZ*H**1- | 16 | 2 | PV=1 если после декремента BC<>0 S,Z,HC из A-[HL] F3=бит 3 операции A-[HL]-HC, где HC взят из F после предыдущей операции F5=бит 1 операции A-[HL]-HC | |
11 101 101 10 100 010 |
ED A2 |
INI | [HL] <- IN [BC] HL <- HL+1 B <- B-1 |
SZ5*3*** | 16 | 2 | Адрес порта 16-битный из ВС Флаги см. /INI | |
11 101 101 10 100 011 |
ED A3 |
OUTI | OUT [BC] <- [HL] HL <- HL+1 B <- B-1 |
SZ5*3*** | 16 | 2 | См. INI | |
11 101 101 10 100 1XX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 | ||
11 101 101 10 101 000 |
ED A8 |
LDD | [DE] <- [HL] DE <- DE-1 HL <- HL-1 BC <- BC-1 |
--*0**0- | 16 | 2 | См. LDI | |
11 101 101 10 101 001 |
ED A9 |
CPD | A-[HL] HL <- HL-1 BC <- BC-1 |
SZ*H**1- | 16 | 2 | См. CPI | |
11 101 101 10 101 010 |
ED AA |
IND | [HL] <- IN [BC] HL <- HL-1 B <- B-1 |
SZ5*3*** | 16 | 2 | См. INI | |
11 101 101 10 101 011 |
ED AB |
OUTD | OUT [C], [HL] HL <- HL-1 B <- B-1 |
SZ5*3*** | 16 | 2 | См. INI | |
11 101 101 10 101 1XX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 | ||
11 101 101 10 110 000 |
ED B0 |
LDIR | Повторять LDI до BC=0, т.е.: Выполнить LDI Если BC<>0 то PC <- PC-2 |
--*0**0- | 21/16** | 2 | См. LDI R увеличивается на 2 каждый цикл? | |
11 101 101 10 110 001 |
ED B1 |
CPIR | Повторять CPI до BC=0 | SZ*H**1- | 21/16** | 2 | См. CPI | |
11 101 101 10 110 010 |
ED B2 |
INIR | Повторять INI до B=0 | SZ5*3*** | 21/16** | 2 | ||
11 101 101 10 110 011 |
ED B3 |
OTIR | Повторять OTI до B=0 | SZ5*3*** | 21/16** | 2 | ||
11 101 101 10 110 1XX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 | ||
11 101 101 10 111 000 |
ED B8 |
LDDR | Повторять LDD до BC=0 | --*0**0- | 21/16** | 2 | См. LDI | |
11 101 101 10 111 001 |
ED B9 |
CPDR | Повторять CPD до BC=0 | SZ*H**1- | 21/16** | 2 | См. CPI | |
11 101 101 10 111 010 |
ED BA |
INDR | Повторять IND до B=0 | SZ5*3*** | 21/16** | 2 | См. INI | |
11 101 101 10 111 011 |
ED BB |
OTDR | Повторять OTD до B=0 | SZ5*3*** | 21/16** | 2 | См. INI | |
11 101 101 10 111 1XX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 | ||
Группа 11 | ||||||||
11 101 101 11 XXX XXX |
ED xx |
*INVALID | NOP/NONI | -------- | 8 | 2 |
Префиксы DD и FD
- Для FD IX заменяется на IY
Код | Команда | Действие | Флаги | Такты | Байты | Примечание | |
---|---|---|---|---|---|---|---|
2 | 16 | SZ5H3VNC | |||||
11 011 101 11 011 101 |
DD DD |
NOP/NONI | -------- | 4 | 1 | Префикс игнорируется | |
11 011 101 11 101 101 |
DD ED |
NOP/NONI | -------- | 4 | 1 | Префикс игнорируется | |
11 011 101 11 111 101 |
DD FD |
NOP/NONI | -------- | 4 | 1 | Префикс игнорируется | |
11 011 101 11 001 011 |
DD CB |
Двойной префикс | См. #Префиксы DDCB и FDCB | ||||
11 011 101 xx xxx xxx |
DD xx |
Все однобайтовые команды, использующие HL | HL заменяется на IX | +4 | +1 | Исключение: EX DE, HL | |
11 011 101 xx xxx xxx |
DD xx |
*Все однобайтовые команды, использующие H | H заменяется на IXH | +4 | +1 | ||
11 011 101 xx xxx xxx |
DD xx |
*Все однобайтовые команды, использующие L | L заменяется на IXL | +4 | +1 | ||
11 011 101 xx xxx xxx dd ddd ddd |
DD xx dd |
Все однобайтовые команды, использующие [HL] | [HL] заменяется на [IX+d] | +8 | +2 | H и L без изменений, т.е. LD H, [HL] => LD H, [IX+d] Также JP [HL] => JP [IX], а не IX+d | |
Остальные команды | Без изменений | +4 | +1 | R увеличивается на 2, а не на 1 |
Префиксы DDCB и FDCB
- Для FDCB IX заменяется на IY
Код | Данные | Команда | Действие | Флаги | Такты | Байты | Примечание | |
---|---|---|---|---|---|---|---|---|
2 | 16 | SZ5H3VNC | ||||||
11 011 101 11 001 011 dd ddd ddd 00 rot 110 |
DD CB dd xx |
rot [IX+d] *SLL [IX+d] |
Битовый сдвиг байта в памяти | SZ503P0C | 23 | 4 | rot=110 (SLL) - недок. | |
11 011 101 11 001 011 dd ddd ddd 00 rot DDD |
DD CB dd xx |
*LD DDD, rot [IX+d] | Битовый сдвиг байта в памяти и запись результата в регистр | SZ503P0C | 23? | 4 | Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM) DDD кроме 110 | |
11 011 101 11 001 011 dd ddd ddd 01 bit XXX |
DD CB dd xx |
BIT bit, [IX+d] *BIT bit, [IX+d] |
*Z*1**0- | 20 | 4 | для XXX<>6 недок. P/V, Z и S как в BIT F5 и F3 копии соотв. битов старшего байта адреса IX+d | ||
11 011 101 11 001 011 dd ddd ddd 10 bit 110 |
DD CB dd xx |
RES bit, [IX+d] | Сброс бита [IX+d] <- [IX+d] AND NOT(2^bit) |
-------- | 23 | 4 | ||
11 011 101 11 001 011 dd ddd ddd 10 bit DDD |
DD CB dd xx |
*LD DDD, RES bit, [IX+d] | Сброс бита и запись результата в регистр | -------- | 23? | 4 | Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM) DDD кроме 110 | |
11 011 101 11 001 011 dd ddd ddd 11 bit 110 |
DD CB dd xx |
SET bit, [IX+d] | Установка бита [IX+d] <- [IX+d] OR 2^bit |
-------- | 23 | 4 | ||
11 011 101 11 001 011 dd ddd ddd 11 bit DDD |
DD CB dd xx |
*LD DDD, SET bit, [IX+d] | Установка бита и запись результата в регистр | -------- | 23? | 4 | Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM) DDD кроме 110 |
Внешние сигналы
Сигнал | Действие | Флаги | Такты | Примечание |
---|---|---|---|---|
NMI | IFF1 <- 0 SP <- SP-2 [SP] <- PC PC <- 0066 |
11 | Вход NMI работает по отрицательному фронту, который запоминается в триггере | |
INT | Если IFF1=1 IFF1 <- 0 IFF2 <- 0 Если IM=0 Чтение команды с шины данных, выполение Если IM=1 RST 38 Если IM=2 Чтение байта d с шины данных CALL [Id] |
IM0: 13 (RST) IM1: 13 IM2: 19 |
Вход INT работает по низкому уровню, для возврата к 1 требуется дополнительная логика (определение RETI на шине данных или программное переключение). Проверка INT происходит после выполнения инструкции. Id представляет собой комбинацию старшего байта из регистра I и младшего, полученного по шине. В PC передается значение, взятое из памяти по адресу Id. | |
RESET | PC <- 0 IFF1 <- 0 IFF2 <- 0 I <- 0 R <- 0 IM <- 0 |
Пояснения к таблицам
Общие принципы
- Недокументированные команды обозначены звездочкой;
- T=4/7/15* означает, что для регистров время исполнения команды 4 такта, для [HL] — 7, для [IX(IY)+d] — 15. При этом 15 НЕ включает 4 такта выборки префикса, которые должны быть учтены в момент его обработки;
- T=21/17** в блочных операциях означает, что команда выполняется 21 такт при повторении и 17 тактов в последний раз;
- T=17/10 у операторов условного перехода означает, что время исполнения 17 тактов при переходе и 10 без перехода;
- NONI обозначает псевдокоманду, эквивалентную NOP, но после которой не проверяется запрос на прерывание;
- В таблице подразумевается, что в момент исполнения операции PC равен адресу следующей по порядку команды;
- В операциях вида IX+d, d является числом со знаком, в диапазоне −128…+127.
Регистры и флаги
- A, B, C, D, E, H, L — 8-разрядные регистры;
- AF, ВС, DE, HL — регистровые пары;
- PC — указатель текущей команды. PCH и PCL — старший и младший байты, соответственно;
- SP — указатель стека;
- F — Регистр флагов
- S: SIGN/Знак. Копия старшего бита результата операции.
- Z: ZERO/Ноль. Равен 1, если результат равен 0.
- *F5: Если не оговорено обратное, равен 5-му биту результата.
- HC: HALF CARRY/Половинный перенос. Обозначает перенос в 4-й бит или заем из него. Используется командой DAA.
- *F3: Если не оговорено обратное, равен 3-му биту результата.
- P/V: PARITY/OVERFLOW/Четность/Переполнение. После одних команд — четность, после других — переполнение. Также копия IFF2 после команд LD A,R и LD A, I
- N: Тип предыдущей операции. 0 — сложение, 1 — вычитание. Используется командой DAA.
- CY: CARRY/Перенос. Обозначает перенос из старшего бита или заем в него.
- A`, F`, ВС`, DE`, HL` — второй набор регистров. Переключение между наборами производится командами EX, EXX. При этом установить, какой именно из наборов активен в настоящий момент, невозможно.
- IFF1: Флаг разрешения прерывания;
- IFF2: Флаг, копия IFF1 во время обработки NMI;
- R: Регистр регенерации памяти, 8 бит. Увеличивается на 1 после каждой выборки команды, но инкремент затрагивает только младшие 7 бит, старший бит не меняется и может быть использован в программах.
- При выборке команды с префиксом, R увеличивается еще на 1. В блочных командах R увеличивается на 2 в каждой итерации.
- Для правильной работы LD A, R и LD R, A увеличение R должно происходить до выполнения команды.
- Прием прерывания увеличивает R на единицу.
- Часто используется в программах как генератор случайных чисел.
- I: Старший байт адреса вектора прерывания в режиме IM 2;
- IM: Режим обработки прерываний. Устанавливается командами IM 0/1/2.
Расшифровка обозначений
DDD, SSS
Код2 | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
Код10 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Без префикса | B | C | D | E | H | L | [HL] | A |
Префикс DD | B | C | D | E | *IXH | *IXL | [IX+d] | A |
Префикс FD | B | C | D | E | *IYH | *IYL | [IY+d] | A |
CCC
Код2 | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
Код10 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Флаг | Z=0 | Z=1 | CY=0 | CY=1 | PV=0 | PV=1 | S=0 | S=1 |
Обозначение | NZ | Z | NC | C | PO | PE | P | M |
Значение | Не ноль | Ноль | Нет переноса | Перенос | Нечетный Нет переполнения |
Четный Переполнение |
Положителный | Отрицательный |
RP
Код2 | 00 | 01 | 10 | 11 |
---|---|---|---|---|
Код10 | 0 | 1 | 2 | 3 |
Без префикса | ВС | DE | HL | SP или AF |
Префикс DD | IX или IX+d | |||
Префикс FD | IY или IY+d |
rot
Код2 | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
Код10 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Команда | RLC | RRC | RL | RR | SLA | SRA | *SL1 | SRL |
Особенности выполнения команд
Префиксы
Назначение префикса — модификация поведения следующей за префиксом команды. В Z80 обработка префиксов имеет следующие особенности:
- Считывание префикса занимает 4 такта и добавляет к регистру R единицу. То есть, выполнение команды с префиксом увеличивает R на 2 вместо 1;
- Команды с префиксами CB, ED, DDCB, FDCB удобнее обрабатывать сразу, обратив внимание на поведение регистра R, указанное выше.
- При получении префиксов DD и FD нужно проверить следующий байт:
- Если это DD, FD или ED, то префикс нужно проигнорировать, выполнив команду NONI — 4 такта, прерывания не проверяются. Эффект такого поведения состоит в том, что при наличии длинной цепочки префиксов прерывание (даже NMI) сможет сработать только после ее завершения (точнее, после первой команды, следующей за цепочкой);
- Если следующий байт равен CB, то нужно обработать команду из категории DDCB/FDCB.
- Если предыдущий пункт пройден, префиксы DD и FD должны просто установить внутренний флаг замены HL на IX или IY для следующей команды;
- Если модифицированная команда использует адрес вида (IX+d) вместо (HL), то ее длина увеличивается на один дополнительный байт d, а время выполнения - на 8 тактов (плюс, конечно, 4 такта на префикс). Например:
- LD B,C имеет код «41» и занимает 1 байт и 4 такта;
- LD B,(HL) имеет код «46» и занимает 1 байт и 7 тактов;
- LD B,(IX+d) имеет код «DD 46 d» и занимает 3 байта и 19 тактов.(4префикс + 7команда + 8замена (HL)).
- Недопустимые команды с префиксом ED должны обрабатываться как NONI на 8 тактов с увеличением R на 2.
Далее приведена таблица команд, на которые влияют префиксы DD и FD (взято из [1]):
+-------------------------------------------------+ | 60 70 | | 21 61 71 E1 | | 22 62 72 | | 23 63 73 E3 | | 24 34 44 54 64 74 84 94 A4 B4 | | 25 35 45 55 65 75 85 95 A5 B5 E5 | | 26 36 46 56 66 86 96 A6 B6 | | 67 77 | | 68 | | 09 19 29 39 69 E9 F9 | | 2A 6A | | 2B 6B CB | | 2C 4C 5C 6C 7C 8C 9C AC BC | | 2D 4D 5D 6D 7D 8D 9D AD BD | | 2E 4E 5E 6E 7E 8E 9E AE BE | | 6F | +-------------------------------------------------+
Команды сдвига
Команды ввода-вывода
Хотя в официальной документации написано, что номера портов имеют 8 разрядов, в реальности Z80 формирует 16-разрядный номер порта, и в некоторых компьютерах это используется. Правило следующее:
- IN A, d / OUT d, A — старший байт номера порта берется из A, то есть полный номер — [Ad];
- IN r, C / OUT C, r — старший байт номера порта берется из B, то есть полный номер — [BC];
Прерывания
- Проверка на наличие запроса на прерывание производится процессором после выполнения инструкции;
- Немаскируемое прерывание NMI имеет более высокий приоритет по сравнению с INT;
- После обработки префиксов, некоторых команд (EI), а также недопустимых операций с префиксом ED, проверка запроса на прерывание блокируется, даже NMI. Это сделано для того, чтобы прерывание не отменило действие префикса на следующую команду. Что касается EI, то запрет проверки сделан для того, чтобы прерывание не сработало между командами EI и RETI, которыми обычно завершается обработчик, если низкий уровень на входе INT еще активен. Стандартная периферия Z80 может отслеживать прохождение команды RETI и снимать запрос на прерывание автоматически.
Ошибка с чтением IFF2
Известная проблема с получением значения IFF2 командами LD A,I и LD A,R состоит в том, что если в момент исполнения команды приходит прерывание, и прерывания разрешены, во флаг PV попадает 0 вместо 1. Учет этой особенности создателями программ имеет два направления:
- Обход ошибки. Команда LD A,I выполняется два раза подряд. Если хоть в одном случае получена 1, значит прерывания разрешены. Принцип этого трюка в том, что прерывания обычно приходят с определенной периодичностью, и вероятность их получения в двух командах, идущих подряд, равна нулю.
- Защита от эмуляции. Программа выполняет цикл из операций вида LD A, I в течение некоторого времени, гарантирующего приход хотя бы одного прерывания. Если ошибочное значение не было получено ни разу, программа делает вывод, что выполняется под эмулятором. Чтобы обмануть такую программу, нужно учитывать описанную особенность Z80.
Есть сведения, что в поздних вариантах Z80 эта ошибка была исправлена.
Расширенные материалы
- /DAA — подробное описание работы команды DAA;
- /BIT — особенности установки недокументированных флагов командой BIT;
- /INI — вычисление флагов в командах блочного ввода-вывода.
Ссылки
- Декодирование кодов команд (англ.)
- Таблица команд со временем исполнения (англ.)
- Алфавитный список команд с пояснениями (англ.)
- Действие команд на флаги (англ.)