Zilog Z80/Система команд: различия между версиями

Материал из Emuverse
(Заготовка)
 
 
(не показано 55 промежуточных версий 2 участников)
Строка 1: Строка 1:
{{Emuverse}}
{{Emuverse}}
<small>{{TOCright}}</small>
В этой статье и ее подстраницах представлены все необходимые данные для создания полноценного эмулятора процессора [[Zilog Z80|Z80]], включая все недокументированные команды, флаги и особенности поведения в разных режимах (по крайнем мере те, что удалось найти). Статья написана на основе фирменной документации, а также большого количества материалов в Интернете, в основном, на английском языке.
Статья написана с точки зрения создателя эмулятора — максимум сведений по каждой команде приведен в общей таблице (за исключением тех случаев, когда это невозможно в силу объема), вместо словесных описаний большинства команд приводятся алгоритмы их работы. Команды перечислены в порядке, удобном для написания эффективного блока декодирования, поэтому принцип увеличения кодов сохраняется не везде.
Подразумевается, что читатель знаком с базовыми принципами и архитектурой микропроцессоров, поэтому объяснения многих понятий, без знания которых приступать к написанию эмулятора бессмысленно, опущены. Если вы считаете, что нечто важное не упомянуто зря, то дайте знать автору (или дополните сами ;).
Для удобства активной работы с большими таблицами все условные обозначения приведены после них. Часть объемных материалов, например, по эмуляции команды DAA, вынесено на подстраницы.
<br clear=both>
== Список команд ==
=== Команды без префикса ===
{| class=fixed
! colspan=2 | Код
! Данные
! Команда
! Действие
! Флаги
! Такты
! Байты
! Примечание
|-
! 2
! 16
!
!
!
! SZ5H3VNC
!
!
!
|-
! colspan=9 | Без префикса
|-
! colspan=9 | Группа 00
|-
| nowrap | 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<br>Если 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 равен адресу следующей команды<br>СС включает первые 4 значения [[#CCC|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
| nowrap | Цикл. сдвиг 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
|-
! colspan=9 | Группа 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
|-
! colspan=9 | Группа 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
|-
! colspan=9 | Группа 11
|-
| 11 CCC 000
|
|
| RET CCC
| Если CCC то<br>&nbsp;&nbsp;&nbsp;&nbsp;PCL <- [SP]<br>&nbsp;&nbsp;&nbsp;&nbsp;PCH <- [SP+1]<br>&nbsp;&nbsp;&nbsp;&nbsp;SP <- SP+2
| --------
| 11/5
| 1
|
|-
| 11 RP0 001
|
|
| POP RP
| RPH <- [SP]<br>RPL <- [SP+1]<br>SP <- SP+2
| --------<br>********
| 10
| 1
| Если RP=3, то подразумевается AF, а не SP
|-
| 11 001 001
| C9
|
| RET
| PCL <- [SP]<br>PCH <- [SP+1]<br>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], <br>а не 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
| nowrap | CALL ССС, [nn]
| Если ССС то<br>&nbsp;&nbsp;&nbsp;&nbsp;SP <- SP-2<br>&nbsp;&nbsp;&nbsp;&nbsp;[SP] <- PCL<br>&nbsp;&nbsp;&nbsp;&nbsp;[SP+1] <- PCH<br>&nbsp;&nbsp;&nbsp;&nbsp;PC <- nn
| --------
| 17/10
| 3
|
|-
| 11 RP0 101
|
|
| PUSH RP
| SP <- SP-2<br>[SP] <- RPL<br>[SP+1] <- RPH
| --------
| 11
| 1
| Если RP=3, то подразумевается AF, а не SP
|-
| 11 001 101
| CD
| nn
| CALL [nn]
| SP <- SP-2<br>[SP] <- PCL<br>[SP+1] <- PCH<br>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<br>[SP-2] <- PCL<br>SP <- SP-2<br>PCH <- 0<br>PCL <- NNN*8
| --------
| 11
| 1
|
|}
=== Префикс CB ===
{| class=fixed
! colspan=2 | Код
! Данные
! Команда
! Действие
! Флаги
! Такты
! Байты
! Примечание
|-
! 2
! 16
!
!
!
! SZ5H3VNC
!
!
!
|-
| nowrap | 11 001 011<br>00 rot SSS
| CB<br>xx
|
| [[#rot|rot]] SSS<br>*SLL SSS
| Битовый сдвиг
| SZ503P0C
| 8/15*
| 2
| [[#rot|rot]]=110 (SLL) - недок.
|-
| 11 001 011<br>01 bit SSS
| CB<br>xx
|
| nowrap | BIT bit, SSS
| SSS AND 2^bit
| *Z513*0-
| 8/12*
| 2
| Установка флагов - см. [[/BIT]]
|-
| 11 001 011<br>10 bit SSS
| CB<br>xx
|
| RES bit, SSS
| nowrap | SSS <- SSS AND NOT(2^bit)
| --------
| 8/15*
| 2
|
|-
| 11 001 011<br>11 bit SSS
| CB<br>xx
|
| SET bit, SSS
| SSS <- SSS OR 2^bit
| --------
| 8/15*
| 2
|
|}
=== Префикс ED ===
{| class=fixed
! colspan=2 | Код
! Данные
! Команда
! Действие
! Флаги
! Такты
! Байты
! Примечание
|-
! 2
! 16
!
!
!
! SZ5H3VNC
!
!
!
|-
! colspan=9 | Группа 00
|-
| nowrap | 11 101 101<br>00 XXX XXX
| ED<br>xx
|
| INVALID
| NOP/NONI
| --------
| 8
| 2
| R увеличивается на 2 (далее аналогично)
|-
! colspan=9 | Группа 01
|-
| 11 101 101<br>01 110 000
| ED<br>70
|
| *IN F, [C]
| IN[BC]
| SZ503P0-
| 12?
| 2
| Меняются только флаги<br>Номер порта в реальности 16-разрядный
|-
| 11 101 101<br>01 DDD 000
| ED<br>xx
|
| IN DDD, [C]
| DDD <- IN[BC]
| SZ503P0-
| 12
| 2
| DDD кроме 110
|-
| 11 101 101<br>01 110 001
| ED<br>71
|
| *OUT [C], 0
| OUT[BC] <- 0
| --------
| 12
| 2
|
|-
| 11 101 101<br>01 SSS 001
| ED<br>xx
|
| nowrap | OUT [C], SSS
| OUT[BC] <- SSS
| --------
| 12
| 2
| SSS кроме 110<br>Номер порта в реальности 16-разрядный
|-
| 11 101 101<br>01 RP0 010
| ED<br>xx
|
| SBC HL, RP
| HL <- HL-RP-C
| SZ***V1C
| 15
| 2
| См. ADD HL, RP
|-
| 11 101 101<br>01 RP1 010
| ED<br>xx
|
| ADC HL, RP
| HL <- HL+RP+C
| SZ***V0C
| 15
| 2
| См. ADD HL, RP
|-
| 11 101 101<br>01 RP0 011
| ED<br>xx
| nn
| LD [nn], RP
| [nn] <- RP
| --------
| 20
| 4
|
|-
| 11 101 101<br>01 RP1 011
| ED<br>xx
| nn
| LD RP, [nn]
| RP <- [nn]
| --------
| 20
| 4
|
|-
| 11 101 101<br>01 XXX 100
| ED<br>44
|
| NEG/*NEG
| A <- 0-A
| SZ5H3V1C
| 8
| 2
| XXX<>0 недок<br>PV=1 если перед операцией A=80<br>С=1 если перед операцией A<>0
|-
| 11 101 101<br>01 001 101
| ED<br>4D
|
| RETI
| IFF1 <- IFF2<br>SP <- SP+2<br>PC <- [SP-2]
| --------
| 14
| 2
| Возврат из INT
|-
| 11 101 101<br>01 XXX 101
| ED<br>xx
|
| RETN<br>*RETN
| IFF1 <- IFF2<br>SP <- SP+2<br>PC <- [SP-2]
| --------
| 14
| 2
| Возврат из NMI<br>XXX=1 => RETI<br>XXX>1 недок.
|-
| 11 101 101<br>01 X00 110
| ED<br>46
|
| IM 0/*IM 0
| IM <- 0
| --------
| 8
| 2
| X=1 недок
|-
| 11 101 101<br>01 X01 110
| ED<br>4E
|
| *IM 0/1
| IM <- 0/1?
| --------
| 8
| 2
| Устанавливается один из режимов, какой - по одним источникам неизвестно, по другим IM 0
|-
| 11 101 101<br>01 X10 110
| ED<br>56
|
| IM 1/*IM 1
| IM <- 1
| --------
| 8
| 2
| X=1 недок
|-
| 11 101 101<br>01 X11 110
| ED<br>5E
|
| IM 2/*IM 2
| IM <- 2
| --------
| 8
| 2
| X=1 недок
|-
| 11 101 101<br>01 000 111
| ED<br>47
|
| LD I, A
| I <- A
| --------
| 9
| 2
|
|-
| 11 101 101<br>01 001 111
| ED<br>4F
|
| LD R, A
| R <- A
| --------
| 9
| 2
|
|-
| 11 101 101<br>01 010 111
| ED<br>57
|
| LD A, I
| A <- I<br>PV <- IFF2
| SZ503*0-
| 9
| 2
| Известная ошибка: если в момент выполнения команды получено прерывание, то в PV вместо 1 ошибочно попадает 0. Есть программы, которые строят на этом защиту от эмуляции.
|-
| 11 101 101<br>01 011 111
| ED<br>5F
|
| LD A, R
| A <- R<br>PV <- IFF2
| SZ503*0-
| 9
| 2
| См. LD A, I<br>Значение в A равно R выполнения инструкции
|-
| 11 101 101<br>01 100 111
| ED<br>67
|
| RRD
|
| SZ503P0-
| 18
| 2
| Флаги по результату в A
|-
| 11 101 101<br>01 101 111
| ED<br>6F
|
| RLD
|
| SZ503P0-
| 18
| 2
| См. RRD
|-
| 11 101 101<br>01 11X 111
| ED<br>xx
|
| NOP
|
| --------
| 8?
| 2
|
|-
! colspan=9 | Группа 10
|-
| 11 101 101<br>10 0XX XXX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|-
| 11 101 101<br>10 100 000
| ED<br>A0
|
| LDI
| [DE] <- [HL]<br>DE <- DE+1<br>HL <- HL+1<br>BC <- BC-1
| --*0**0-
| 16
| 2
| PV=1 если после декремента BC<>0<br>F3=бит 3 операции переданный байт + A<br>F5=бит 1 операции переданный байт + A<br>R увеличивается на 2 (далее аналогично)
|-
| 11 101 101<br>10 100 001
| ED<br>A1
|
| CPI
| A-[HL]<br>HL <- HL+1<br>BC <- BC-1
| SZ*H**1-
| 16
| 2
| PV=1 если после декремента BC<>0<br>S,Z,HC из A-[HL]<br>F3=бит 3 операции A-[HL]-HC, где HC взят из F после предыдущей операции<br>F5=бит 1 операции A-[HL]-HC
|-
| 11 101 101<br>10 100 010
| ED<br>A2
|
| INI
| [HL] <- IN [BC]<br>HL <- HL+1<br>B <- B-1
| SZ5*3***
| 16
| 2
| Адрес порта 16-битный из ВС<br>Флаги см. [[/INI]]
|-
| 11 101 101<br>10 100 011
| ED<br>A3
|
| OUTI
| OUT [BC] <- [HL]<br>HL <- HL+1<br>B <- B-1
| SZ5*3***
| 16
| 2
| См. INI
|-
| 11 101 101<br>10 100 1XX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|-
| 11 101 101<br>10 101 000
| ED<br>A8
|
| LDD
| [DE] <- [HL]<br>DE <- DE-1<br>HL <- HL-1<br>BC <- BC-1
| --*0**0-
| 16
| 2
| См. LDI
|-
| 11 101 101<br>10 101 001
| ED<br>A9
|
| CPD
| A-[HL]<br>HL <- HL-1<br>BC <- BC-1
| SZ*H**1-
| 16
| 2
| См. CPI
|-
| 11 101 101<br>10 101 010
| ED<br>AA
|
| IND
| [HL] <- IN [BC]<br>HL <- HL-1<br>B <- B-1
| SZ5*3***
| 16
| 2
| См. INI
|-
| 11 101 101<br>10 101 011
| ED<br>AB
|
| OUTD
| OUT [C], [HL]<br>HL <- HL-1<br>B <- B-1
| SZ5*3***
| 16
| 2
| См. INI
|-
| 11 101 101<br>10 101 1XX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|-
| 11 101 101<br>10 110 000
| ED<br>B0
|
| LDIR
| nowrap | Повторять LDI до BC=0, т.е.:<br>&nbsp;&nbsp;&nbsp;&nbsp;Выполнить LDI<br>&nbsp;&nbsp;&nbsp;&nbsp;Если BC<>0 то PC <- PC-2
| --*0**0-
| 21/16**
| 2
| См. LDI<br>R увеличивается на 2 каждый цикл?
|-
| 11 101 101<br>10 110 001
| ED<br>B1
|
| CPIR
| Повторять CPI до BC=0
| SZ*H**1-
| 21/16**
| 2
| См. CPI
|-
| 11 101 101<br>10 110 010
| ED<br>B2
|
| INIR
| Повторять INI до B=0
| SZ5*3***
| 21/16**
| 2
|
|-
| 11 101 101<br>10 110 011
| ED<br>B3
|
| OTIR
| Повторять OTI до B=0
| SZ5*3***
| 21/16**
| 2
|
|-
| 11 101 101<br>10 110 1XX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|-
| 11 101 101<br>10 111 000
| ED<br>B8
|
| LDDR
| Повторять LDD до BC=0
| --*0**0-
| 21/16**
| 2
| См. LDI
|-
| 11 101 101<br>10 111 001
| ED<br>B9
|
| CPDR
| Повторять CPD до BC=0
| SZ*H**1-
| 21/16**
| 2
| См. CPI
|-
| 11 101 101<br>10 111 010
| ED<br>BA
|
| INDR
| Повторять IND до B=0
| SZ5*3***
| 21/16**
| 2
| См. INI
|-
| 11 101 101<br>10 111 011
| ED<br>BB
|
| OTDR
| Повторять OTD до B=0
| SZ5*3***
| 21/16**
| 2
| См. INI
|-
| 11 101 101<br>10 111 1XX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|-
! colspan=9 | Группа 11
|-
| 11 101 101<br>11 XXX XXX
| ED<br>xx
|
| *INVALID
| NOP/NONI
| --------
| 8
| 2
|
|}
=== Префиксы DD и FD ===
* Для FD IX заменяется на IY
{| class=fixed
! colspan=2 | Код
! Команда
! Действие
! Флаги
! Такты
! Байты
! Примечание
|-
! 2
! 16
!
!
! SZ5H3VNC
!
!
!
|-
| nowrap | 11 011 101<br>11 011 101
| DD<br>DD
|
| NOP/NONI
| --------
| 4
| 1
| Префикс игнорируется
|-
| 11 011 101<br>11 101 101
| DD<br>ED
|
| NOP/NONI
| --------
| 4
| 1
| Префикс игнорируется
|-
| 11 011 101<br>11 111 101
| DD<br>FD
|
| NOP/NONI
| --------
| 4
| 1
| Префикс игнорируется
|-
| 11 011 101<br>11 001 011
| DD<br>CB
|
| Двойной префикс
|
|
|
| См. [[#Префиксы DDCB и FDCB]]
|-
| 11 011 101<br>xx xxx xxx
| DD<br>xx
| Все однобайтовые команды, использующие HL
| HL заменяется на IX
|
| +4
| +1
| Исключение: EX DE, HL
|-
| 11 011 101<br>xx xxx xxx
| DD<br>xx
| *Все однобайтовые команды, использующие H
| H заменяется на IXH
|
| +4
| +1
|
|-
| 11 011 101<br>xx xxx xxx
| DD<br>xx
| *Все однобайтовые команды, использующие L
| L заменяется на IXL
|
| +4
| +1
|
|-
| 11 011 101<br>xx xxx xxx<br>dd ddd ddd
| DD<br>xx<br>dd
| Все однобайтовые команды, использующие [HL]
| nowrap | [HL] заменяется на [IX+d]
|
| +8
| +2
| nowrap | H и L без изменений, т.е. <br>LD H, [HL] => LD H, [IX+d]<br>Также<br>JP [HL] => JP [IX], а не IX+d
|-
|
|
| Остальные команды
| Без изменений
|
| +4
| +1
| R увеличивается на 2, а не на 1
|}
=== Префиксы DDCB и FDCB ===
* Для FDCB IX заменяется на IY
{| class=fixed
! colspan=2 | Код
! Данные
! Команда
! Действие
! Флаги
! Такты
! Байты
! Примечание
|-
! 2
! 16
!
!
!
! SZ5H3VNC
!
!
!
|-
| nowrap | 11 011 101<br>11 001 011<br>dd ddd ddd<br>00 rot 110
| DD<br>CB<br>dd<br>xx
|
| rot [IX+d]<br>*SLL [IX+d]
| Битовый сдвиг байта в памяти
| SZ503P0C
| 23
| 4
| rot=110 (SLL) - недок.
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>00 rot DDD
| DD<br>CB<br>dd<br>xx
|
| *LD DDD, rot [IX+d]
| Битовый сдвиг байта в памяти и запись результата в регистр
| SZ503P0C
| 23?
| 4
| Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM)<br>DDD кроме 110
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>01 bit XXX
| DD<br>CB<br>dd<br>xx
|
| BIT bit, [IX+d]<br>*BIT bit, [IX+d]
|
| *Z*1**0-
| 20
| 4
| для XXX<>6 недок.<br>P/V, Z и S как в BIT<br>F5 и F3 копии соотв. битов старшего байта адреса IX+d
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>10 bit 110
| DD<br>CB<br>dd<br>xx
|
| RES bit, [IX+d]
| nowrap | Сброс бита<br>[IX+d] <- [IX+d] AND NOT(2^bit)
| --------
| 23
| 4
|
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>10 bit DDD
| DD<br>CB<br>dd<br>xx
|
| nowrap | *LD DDD, RES bit, [IX+d]
| Сброс бита и запись результата в регистр
| --------
| 23?
| 4
| Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM)<br>DDD кроме 110
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>11 bit 110
| DD<br>CB<br>dd<br>xx
|
| SET bit, [IX+d]
| Установка бита<br>[IX+d] <- [IX+d] OR 2^bit
| --------
| 23
| 4
|
|-
| 11 011 101<br>11 001 011<br>dd ddd ddd<br>11 bit DDD
| DD<br>CB<br>dd<br>xx
|
| *LD DDD, SET bit, [IX+d]
| Установка бита и запись результата в регистр
| --------
| 23?
| 4
| Результат попадает в регистр даже если он не был записан в память (например, адрес попал на ROM)<br>DDD кроме 110
|}
=== Внешние сигналы ===
{| class=fixed
! Сигнал
! Действие
! Флаги
! Такты
! Примечание
|-
| NMI
| IFF1 <- 0<br>SP <- SP-2<br>[SP] <- PC<br>PC <- 0066
|
| 11
| Вход NMI работает по отрицательному фронту, который запоминается в триггере
|-
| INT
| nowrap | Если IFF1=1<br>&nbsp;&nbsp;&nbsp;&nbsp;IFF1 <- 0<br>&nbsp;&nbsp;&nbsp;&nbsp;IFF2 <- 0<br>&nbsp;&nbsp;&nbsp;&nbsp;Если IM=0<br>&nbsp;&nbsp;&nbsp;&nbsp;    Чтение команды с <br>&nbsp;&nbsp;&nbsp;&nbsp;    шины данных, <br>&nbsp;&nbsp;&nbsp;&nbsp;    выполение<br>&nbsp;&nbsp;&nbsp;&nbsp;Если IM=1<br>&nbsp;&nbsp;&nbsp;&nbsp;    RST 38<br>&nbsp;&nbsp;&nbsp;&nbsp;Если IM=2<br>&nbsp;&nbsp;&nbsp;&nbsp;    Чтение байта d с<br>&nbsp;&nbsp;&nbsp;&nbsp;    шины данных<br>&nbsp;&nbsp;&nbsp;&nbsp;    CALL [Id]
|
| nowrap | IM0: 13<br>(RST)<br>IM1: 13<br>IM2: 19
| Вход INT работает по низкому уровню, для возврата к 1 требуется дополнительная логика (определение RETI на шине данных или программное переключение).<br>Проверка INT происходит после выполнения инструкции.<br>Id представляет собой комбинацию старшего байта из регистра I и младшего, полученного по шине. В PC передается значение, взятое из памяти по адресу Id.
|-
| RESET
| PC <- 0<br>IFF1 <- 0<br>IFF2 <- 0<br>I <- 0<br>R <- 0<br>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|DAA]].
** '''*F3''': Если не оговорено обратное, равен 3-му биту результата.
** '''P/V''': PARITY/OVERFLOW/Четность/Переполнение. После одних команд — четность, после других — переполнение. Также копия IFF2 после команд LD A,R и LD A, I
** '''N''': Тип предыдущей операции. 0 — сложение, 1 — вычитание. Используется командой [[/DAA|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 ====
{| class = border style="text-align: center;"
! Код<sub>2</sub>
! 000 || 001 || 010 || 011 || 100 || 101 || 110 || 111
|-
! Код<sub>10</sub>
! 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7
|-
| Без префикса || rowspan=3 | B || rowspan=3 | C || rowspan=3 | D || rowspan=3 | E || H || L || [HL] || rowspan=3 | A
|-
| Префикс DD || *IXH || *IXL || [IX+d]
|-
| Префикс FD || *IYH || *IYL || [IY+d]
|}
==== CCC ====
{| class = border style="text-align: center;"
!  width=11% | Код<sub>2</sub>
!  width=11% | 000 || width=11% |  001 || width=11% |  010 || width=11% |  011 || width=11% |  100 || width=11% |  101 || width=11% |  110 || width=11% |  111
|-
! Код<sub>10</sub>
! 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
|-
| Значение || Не ноль || Ноль || Нет переноса || Перенос || Нечетный <br>Нет переполнения || Четный<br>Переполнение || Положителный || Отрицательный
|}
==== RP ====
{| class = border style="text-align: center;"
! Код<sub>2</sub>
! 00 || 01 || 10 || 11
|-
! Код<sub>10</sub>
! 0 || 1 || 2 || 3
|-
| Без префикса || width=20% rowspan=3 | ВС || width=20% rowspan=3 | DE || width=20% | HL || width=20% rowspan=3 | SP или AF
|-
| Префикс DD || IX или IX+d
|-
| Префикс FD || IY или IY+d
|}
==== rot ====
{| class = border style="text-align: center;"
! Код<sub>2</sub>
! 000 || 001 || 010 || 011 || 100 || 101 || 110 || 111
|-
! Код<sub>10</sub>
! 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 такта на префикс). Например:
** <tt>LD B,C</tt> имеет код «41» и занимает 1 байт и 4 такта;
** <tt>LD B,(HL)</tt> имеет код «46» и занимает 1 байт и 7 тактов;
** <tt>LD B,(IX+d)</tt> имеет код «DD 46 d» и занимает 3 байта и 19 тактов.(4<sub>префикс</sub>&nbsp;+&nbsp;7<sub>команда</sub>&nbsp;+&nbsp;8<sub>замена&nbsp;(HL)</sub>).
* Недопустимые команды с префиксом ED должны обрабатываться как NONI на 8 тактов с увеличением R на 2.
Далее приведена таблица команд, на которые влияют префиксы DD и FD (взято из [http://homepage.ntlworld.com/cyborgsystems/CS_Main/Z80/z80.c]):


Матрица команд, на которые влияют префиксы DD и FD<ref>[http://homepage.ntlworld.com/cyborgsystems/CS_Main/Z80/z80.c Z80.c module Copyright (c) 2006, BlueChip of Cyborg Systems]</ref>
<pre>
<pre>
+-------------------------------------------------+
+-------------------------------------------------+
Строка 23: Строка 1627:
</pre>
</pre>


== Примечания ==
=== Команды сдвига ===
<references/>
{| align=center
|[[Изображение:Z80_rlc.png‎|frame|<center>RLC</center>]]
|[[Изображение:Z80_rrc.png‎|frame|<center>RRC</center>]]
|-
|[[Изображение:Z80_rl.png‎|frame|<center>RL</center>]]
|[[Изображение:Z80_rr.png‎|frame|<center>RR</center>]]
|-
|[[Изображение:Z80_sla.png‎|frame|<center>SLA</center>]]
|[[Изображение:Z80_sra.png‎|frame|<center>SRA</center>]]
|-
|[[Изображение:Z80_sl1.png‎|frame|<center>*SL1, SLL (недок.)</center>]]
|[[Изображение:Z80_srl.png‎|frame|<center>SRL</center>]]
|-
|[[Изображение:Z80_rld.png‎|frame|<center>RLD</center>]]
|[[Изображение:Z80_rrd.png‎|frame|<center>RRD</center>]]
|}
 
=== Команды ввода-вывода ===
Хотя в официальной документации написано, что номера портов имеют 8 разрядов, в реальности Z80 формирует 16-разрядный номер порта, и в некоторых компьютерах ([[ZX Spectrum]], например) это используется. Правило  следующее:
* 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 командами <tt>LD A,I</tt> и <tt>LD A,R</tt> состоит в том, что если в момент исполнения команды приходит прерывание, и прерывания разрешены, во флаг PV попадает 0 вместо 1. Учет этой особенности создателями программ имеет два направления:
# Обход ошибки. Команда <tt>LD A,I</tt> выполняется два раза подряд. Если хоть в одном случае получена 1, значит прерывания разрешены. Принцип этого трюка в том, что прерывания обычно приходят с определенной периодичностью, и вероятность их получения в двух командах, идущих подряд, равна нулю.
# Защита от эмуляции. Программа выполняет цикл из операций вида <tt>LD A, I</tt> в течение некоторого времени, гарантирующего приход хотя бы одного прерывания. Если ошибочное значение не было получено ни разу, программа делает вывод, что выполняется под эмулятором. Чтобы обмануть такую программу, нужно учитывать описанную особенность Z80.
 
Есть сведения, что в поздних вариантах Z80 эта ошибка была исправлена.
 
=== Расширенные материалы ===
* [[/DAA]] — подробное описание работы команды DAA;
* [[/BIT]] — особенности установки недокументированных флагов командой BIT;
* [[/INI]] — вычисление флагов в командах блочного ввода-вывода.
 
 


== Ссылки ==
== Ссылки ==
* [http://www.z80.info/decoding.htm Декодирование кодов команд] {{ref-en}}
* {{pdf||Z80 Family CPU User Manual|datasheets/processors/Z80/um0080.pdf}} {{ref-en}}
* [http://www.z80.info/z80sean.txt Таблица команд со временем исполнения] {{ref-en}}
* {{www}} [http://www.z80.info/decoding.htm Декодирование кодов команд] {{ref-en}}
* [http://www.z80.info/z80inst.txt Алфавитный список команд с пояснениями] {{ref-en}}
* {{www}} [http://www.z80.info/z80sean.txt Таблица команд со временем исполнения] {{ref-en}}
* [http://www.z80.info/z80sflag.htm Действие команд на флаги] {{ref-en}}
* {{www}} [http://www.z80.info/z80inst.txt Алфавитный список команд с пояснениями] {{ref-en}}
* {{www}} [http://www.z80.info/z80sflag.htm Действие команд на флаги] {{ref-en}}
* {{www}} [http://www.zophar.net/tech/files/z80undoc.html Недокументированные команды] {{ref-en}}


[[Категория:Zilog Z80]]
[[Категория:Zilog Z80]]

Текущая версия от 11:56, 21 сентября 2023

Этот документ создан для 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 *IXH *IXL [IX+d]
Префикс FD *IYH *IYL [IY+d]

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                            |
+-------------------------------------------------+

Команды сдвига

RLC
RRC
RL
RR
SLA
SRA
*SL1, SLL (недок.)
SRL
RLD
RRD

Команды ввода-вывода

Хотя в официальной документации написано, что номера портов имеют 8 разрядов, в реальности Z80 формирует 16-разрядный номер порта, и в некоторых компьютерах (ZX Spectrum, например) это используется. Правило следующее:

  • 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. Учет этой особенности создателями программ имеет два направления:

  1. Обход ошибки. Команда LD A,I выполняется два раза подряд. Если хоть в одном случае получена 1, значит прерывания разрешены. Принцип этого трюка в том, что прерывания обычно приходят с определенной периодичностью, и вероятность их получения в двух командах, идущих подряд, равна нулю.
  2. Защита от эмуляции. Программа выполняет цикл из операций вида LD A, I в течение некоторого времени, гарантирующего приход хотя бы одного прерывания. Если ошибочное значение не было получено ни разу, программа делает вывод, что выполняется под эмулятором. Чтобы обмануть такую программу, нужно учитывать описанную особенность Z80.

Есть сведения, что в поздних вариантах Z80 эта ошибка была исправлена.

Расширенные материалы

  • /DAA — подробное описание работы команды DAA;
  • /BIT — особенности установки недокументированных флагов командой BIT;
  • /INI — вычисление флагов в командах блочного ввода-вывода.


Ссылки