ZX Doze #01
27 апреля 1997

                   О Z80 - О НОВОМ И О СТАРОМ


        В  регистре  I  содержится  старший  байт адреса таблицы
векторов  прерываний.  В  режиме  IM2 по сигналам -IORQ & -M1 из
схемы, вызвавшей прерывание, считывается младший байт адреса (не
верь  тем,  кто пишет об игнорировании младшего бита). Теперь по
полученному  адресу  из  памяти  считываются  два  байта  адреса
перехода  на подпрограмму обработки прерываний (в формате Intel:
младший  байт  первый, старший в следующем адресе). В компьютере
Спектрум  теоретически  с шины всегда должен считываться младший
байт  вектора  равен  FFh.  Но  в реальной жизни некоторые порты
расширения (в том числе фирменные) не проверяют значение сигнала
-RD  и  "отзываются"  на  такой  запрос;  вследствие этого может
считаться любое значение, что заставляет держать в памяти полную
таблицу  векторов  переходов  длиной 257 байт, в которой старшие
байты равны младшим.
        А 257 одинаковых байт ставят по следующей причине. На ZX
Spectrum  при чтении младшего байта адреса вектора прерывания на
шине  данных  должен быть #FF. Тогда сам вектор прерывания будет
выбираться  по  адресу  (I*100h)+FF.  Но на некоторых машинах, у
которых  перегружена  шина данных, при выборке младшего байта на
шине  находится  не  #FF.  Поэтому,  чтобы  передать  управление
обработчику  прерываний,  его  (обработчик)  помещают по адресу,
младший  байт  которого  равен стаpшиму, и этим байтом заполняют
область  от  (I*100h)+00 до (I*100h)+100h включительно. То есть,
например если обработчик начинается с адреса #D9D9, а в регистре
I  -  #F8,  то  область  памяти  с  #F800  по #F900 включительно
заполняется  кодом  #D9.  Тогда,  если при чтении младшего байта
адреса  вектора  будет  прочитан код XX, то вектор выбирается по
адресу (I*100h)+XX=#F8XX. A по адресу #F8XX лежит слово #D9D9 то
есть правильный адрес обработчика прерываний.

        Регистр  R  содержит  полный байт (8 бит), но изменяются
при  счете только младшие 7 бит (этого хватало для выпускавшихся
в  то  время  динамических ОЗУ). А считает он циклы регенерации,
которые  следуют по одному за каждым циклом M1 (выборка префикса
или  кода  операции), подтверждаемым сигналами -MRQ & -M1 & -RD.
Стоит  отметить,  что в некоторых компьютерах (в том числе каких
то из Spectrum+) циклы выборки M1 затягиваются на один такт (для
синхронизации  с  видеопамятью  и  более  надежного считывания).
Старший  бит  некоторые  "умельцы"  приспосабливают  под  флажок
состояния.
        Что  касается  регистра  R  -  он  связан с регенерацией
динамической памяти. На спектруме регенерация выполняется схемой
видеоконтроллера при выборке из видеопамяти. Но вообще Z80 может
сам  регенерировать  память.  Для этого во время декодирования и
выполнения  комманды  внутри  процессора  на  7 младших бит шины
адреса  подается  содержимое  регистра  R, активизируется сигнал
/RFSH  и  по  сигналу  /RAS  в  мелкосхеме  динамической  памяти
произойдет  регенерация  запоминающих  элементов  строки,  адрес
которой  установлен  на  шине  адреса (7 младших бит). Регистр R
инкрементируется   после  каждого  цикла  М1,  но  при  этом  не
затрагивается   старший  бит.  Так  что  сам  Z80,  IMHO,  может
perheputb  память  до 128*(число элементов памяти в одной строке
мелкосхемы  динамической памяти). Для PYS это число равно 256 (8
адресных  ног),  для  РУ7  -  512  (9 адресных ног). Если шинами
управляет  не процессор, а другое устройство в цикле BUSRQ, либо
процессор  находится  в  тактах  ожидания  (WAIT),  то процессор
регенерацию не выполняет.
        Если /WAIT пассивен, то:
    цикл M1                               - 4 такта;
    чтение/запись в память                - 3 такта;
    ввода/вывода                          - 4 такта;
    предоставление доступа к шине         - 3 такта;
    подтверждение маскируемого прерывания - 6 тактов;
    подтверждение NMI                     - 5 тактов;
    HALT                                  - 4 такта.
        Цикл  ввода/вывода содержит всегда 1 такт ожидания, цикл
подтверждения  маскируемого  прерывания  -  2.  Это  сделано для
облегчения работы с внешними устройствами.

        В   процессоре  Z80  есть  два  триггера  IFF1  и  IFF2,
используемые   в  логике  обработки  прерываний.  Значение  IFF1
используется    при    определении   допустимости   маскируемого
прерывания,  а  IFF2 считывается на место флага P/V командами LD
A,I и LD A,R. Логика их работы следующая:

    ситуация    │ IFF1 │ IFF2 │           примечание
────────────────┼──────┼──────┼─────────────────────────────────
сигнал -RESET   │  0   │  0   │ устанавливается режим IMO
────────────────┼──────┼──────┼─────────────────────────────────
команда DI      │  0   │  0   │ запрещает прерывания
────────────────┼──────┼──────┼─────────────────────────────────
команда EI      │  1   │  1   │ разрешает прерывания
────────────────┼──────┼──────┼─────────────────────────────────
сигнал -INT     │  0   │  0   │ если сбросился IFF1 - обработка
                │      │      │    маскируемого прерывания
────────────────┼──────┼──────┼─────────────────────────────────
команда RETI    │ IFF2 │ IFF2 │ возврат из маскируемого
                │  ?   │      │    прерывания
────────────────┼──────┼──────┼─────────────────────────────────
сигнал -NMI     │  0   │ IFF1 │ немаскируемое прерывание
────────────────┼──────┼──────┼─────────────────────────────────
команда  RETN   │ IFF2 │ IFF2 │ возврат из немаскируемого
                │      │      │    прерывания
────────────────┼──────┼──────┼─────────────────────────────────
команды  LD A,I │ IFF1 │ IFF2 │   P/V <= IFF2
         LD A,R │      │      │
────────────────┴──────┴──────┴─────────────────────────────────

        Я  не  уверен, что IFF1 восстанавливается командой RETI,
но  это  не  имеет  особого значения - различия будут только при
обработке  немаскируемого  прерывания,  а  там  всегда на выходе
используется  RETI.  Вообще команда RETI отличается от RET кроме
длины только тем, что распознается другими схемами семейства Z80
как   признак   окончания   обработки  прерывания.  Поскольку  в
доступных  нам  компьютерах  таких  чипов  нет  - эту команду не
используют (ставят простой RET).
        Алгоритм   анализа   прерываний  довольно  прост,  перед
выборкой  первого  цикла очередной команды проверяется состояние
сигнала  -RESET,  затем  в  порядке  приоритетов  -NMI,  а  если
установлен  IFF1 и -INT с соответствующей реакцией. Команда HALT
не  меняет  этот алгоритм, а просто запрещает изменение счетчика
команд  до  начала  выхода из этого состояния (сигналами -RESET,
-NMI а при разрешенных прерываниях и -INT).

        Байт флагов F содержит следующие биты:
    7: S    - знак
    6: Z    - нуль
    5:
    4: H    - вспомогательный перенос
    3:
    2: P/V  - четность/переполнение
    1: N    - вычитание
    0: C    - перенос
        Недокументированные  биты также могут использоваться для
хранения  состояний  или  изменяться  отдельными  командами, что
вполне   может   использоваться   в   защитах.  Чтобы  правильно
устанавливать   этот   байт  необходимо  специально  исследовать
поведение   этого   регистра  во  всех  командах  (в  том  числе
недокументированных).   Часть   документированных  команд  также
неописанным  образом  изменяет  флаги H или P/V и S, а некоторые
команды  работы  с  портами  сразу  флаги  C,  P/V,  S  и H. Мне
встречались   утверждения,   что   неописанные  флаги  принимают
состояния соответствующих бит регистра A, возможны варианты...

        Для    анализа    недокументированных    команд   удобно
пользоваться  таблицами декодирования 16*16 клеток. Это убережет
от  соблазна исследовать явно недопустимые мнемоники команд. Так
в таблице префикса CBh (битовые операции и сдвиги) видна "дырка"
с  кодами  30h...37h.  В  ней  расположены варианты команды SLI,
которая  отличается  от  SLA установкой младшего бита операнда в
единицу.  Если применить одновременно префиксы индексной команды
и битовой операции можно получить команды типа: DDh,CBh,nn,36h [
SLI (IX+nn) ].
        В  таблицах  индексных  команд  с  префиксами  DDh и FDh
возможны  операции  с  младшей  или старшей половиной индексного
регистра  (обозначаются:  LX,  HX, LY и HY). Команды строятся по
аналогии с операциями над регистрами HL, например:

             коды    │  ассемблирование  │  мнемоника
         ────────────┼───────────────────┼─────────────
         DDh,24h     │   DEFB #DD        │  INC HX
                     │   INC  H          │
         ────────────┼───────────────────┼─────────────
         FDh,2Dh     │   DEFB #FD        │  DEC LY
                     │   DEC  L          │
         ────────────┼───────────────────┼─────────────
         DDh,ЧCh     │   DEFB #DD        │  LD  C,HX
                     │   LD   C,H        │
         ────────────┼───────────────────┼─────────────
         DDh,26h,nn  │   DEFB #DD        │  LD  HX,nn
                     │   LD   H,nn       │
         ────────────┼───────────────────┼─────────────
         DDh,8Ch     │   DEFB #DD        │  ADC A,HX
                     │   ADC  A,H        │
         ────────────┴───────────────────┴─────────────

        Ясно,  что  невозможна  одновременная  работа  с разными
индексными  регистрами  [ LD HX,HY ] или с целым регистром и его
половиной  [  LD  LX,(IX+nn)  ].  Что-то я слыхал о трудностях в
командах типа LD LX,HX, надо специально проверить.
        Интересно  применение  префиксов  DDh  и  FDh в командах
сдвига и сброса/установки бита, например:

         коды      │     мнемоника     │ стандартные команды
   ────────────────┼───────────────────┼─────────────────────
    DDh,CBh,nn,1Ah │   RR  (IX+nn),D   │    RR  (IX+nn)
                   │                   │    LD  D,(IX+nn)
    FDh,CBh,nn,EOh │  SET 4,(IY+nn),B  │    SET 4,(IY+nn)
                   │                   │    LD  B,(IY+nn)
   ────────────────┴───────────────────┴─────────────────────

        Понятно,  что  такие короткие и быстрые команды не могли
не заинтересовать "всяких там Гилбертов из Гремлинсов".

        С  портами  проще:  доступ  ко ВСЕМ портам процессор Z80
получает с помощью 16-разрядных адресов. В командах образца 8080
в   старшем  байте  устанавливается  значение  из  аккумулятора,
остальные  команды работы с портами выставляют в качестве адреса
порта текущее содержимое регистров BC. На на деле все проще:
        у 8080 при out 36 выводился A в 3636;
        у  Z80A  при out (36), a выводится A в A*100h+36 при out
(c), a выводится A в (BC).
        При вводе аналогично.



Other articles:


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

Similar articles:
Announcement - Eternity Industry.
Credits - the authors of the paper.
Editor - Ochepednoy nome.p newspaper I postapalsya do more paznoobpaznym than usual.

В этот день...   21 November