ZX Doze
#01
27 апреля 1997 |
|
Hardware - хитрости процессора Z80.
О 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). При вводе аналогично.
Другие статьи номера:
Похожие статьи:
В этот день... 3 декабря