_ Ошибка Z80 пофиксена _ перевод (C) 1999 Viper оригинал (C) 1995 Zilog Inc., Z80 Microprocessor Family Product Specifications Databook В журнале Deja Vu #8, а также где-то еще (по-моему в Voyager #3) была опубли- кована статья Ивана Рощина об ошибке процессора Z80 при определении состояния прерываний. Затем в Born Dead'е была заметка о том, что на Западе уже лет пять знают об этой ошибке и обходят ее программным способом. VTS, купив в Санкт-Петербурге фирмен- ную книгу по Z80, обнаружил, что фирма- производитель не только знает об этой неприятной особенности, но и приняла ме- ры к ее устранению. Современные процес- соры (CMOS) выпускаются уже в исправлен- ном виде. Таким образом, определение реального процессора или эмулятора даст неверный результат на этих Z80. Такие процессоры, например, использует Nemo в своих компьютерах KAY. Вашему вниманию предлагается перевод из этой книги... --cut----------------------------------- Вопрос: Я не могу определить состояние прерываний по LD A,I и LD A,R при чтении состояния IFF2. Почему? Как обойти дан- ную проблему? Ответ: В CMOS варианте процессора Z80 мы устранили эту проблему. В NMOS вариа- нте Z80 в определенных случаях IFF2 неп- равильно отражает текущий статус преры- ваний. Две операции LD A,R и LD A,I ко- пируют состояние триггера разрешения прерываний в бит P/V и изменяют содержи- мое аккумулятора. Возможно определить статус прерываний во время исполнения команды. Если прерывание производится процессором во время выполнения команды (подразумевается, что прерывания разре- шены), то флаг P/V будет очищен, что приведет к неправильному выводу о запре- щенных прерываниях во время выполнения команды. Этот парадокс может быть решен внешней трассировкой процессора. Проблема заклю- чается в том, что триггер IFF2 очищается до того, как будет перенесен во флаг P/V. Состояние триггера не копируется во флаг четности до прекращения прерывания, происходящего при выполнении команды. Во время приема прерывания автоматиче- ски очищается триггер разрешения преры- ваний, равно как и флаг четности, несмо- тря на то, были ли прерывания разрешены или запрещены в начале выполнения коман- ды. Изящное решение данной аномалии осно- вано на том факте, что старое значение PC сохраняется на стеке во время приема прерывания. Следующая точка входа на стеке (слово ниже адреса содержащегося в указателе стека) может быть очищена пе- ред выполнением LD A,I или LD A,R. Если это нулевое значение изменилось во время выполнения следующей команды, то произо- шло прерывание. Это означет, что преры- вания были разрешены, даже если состоя- ние флага четности указывает на обрат- ное. Естественно, если флаг четности ус- тановлен после выполнения LD A,I или LD A,R - нет необходимости в проверке вер- шины стека. Прерывания действительно ра- зрешены, если флаг четности находится в этом состоянии. Здесь приведено две подпрограммы. Обе возвращают сброшенный флаг Carry, если прерывания разрешены и, соответственно, наоборот: установленный при запрещенных прерываниях. Обе портят аккумулятор (он не содержит I или R на выходе). Состоя- ние всех флагов кроме переноса на выходе неопределено. Первая процедура может быть расположе- на где угодно в памяти, исключая нулевой блок (#0000 -#00FF). Это небольшое ог- раничение вытекает из того факта, что подпрограмма проверяет только значимый байт следующего входа стека. Этот байт будет не равен 0, если подпрограмма рас- положена не в нулевом блоке памяти. Вто- рая процедура проверяет оба байта из стека и, таким образом, обходит это ог- раничение. Viper> В действительности для большинст- ва применений в системе ZX Spectrum это ограничение не играет роли. Внимание, эти подпрограммы предполага- ют, что процедура обслуживания для любо- го прерывания включает прерывания перед ее завершением. Они могут вернуть невер- ный результат, если подпрограмма обрабо- тки прерываний (ISR), которая не вклю- чает прерывания, начинает работать после выполнения LD A,I или LD A,R. Listing 1. Эта процедура не должна на- ходиться в 0-ом блоке памяти (#0-#00FF) GETIFF: XOR A ;C flag, acc=0 PUSH AF ;Stack bottom=#00xx POP AF ;Restore SP LD A,I ;P flag=IFF2 RET PE ;Exit if enabled DEC SP ;May be disabled DEC SP ;Has stack bottom been POP AF ;overwritten? OR A ;If not #00xx, INT's RET NZ ;were actually enabled. SCF ;Otherwise, they really RET ;are disabled. Listing 2. Процедура может распола- гаться где угодно в памяти. GETIFF: PUSH HL ;Save HL contents XOR A ;C flag, acc=0 LD H,A ;HL=#0 LD L,A ; PUSH HL ;Stack bottom=#0000 POP HL ;Restore SP LD A,I ;P flag=IFF2 JP PE,G1 ;Exit if isn't enabled. DEC SP ;May be disabled. DEC SP ;Let's see if stack POP HL ;bottom is still #0000 LD A,H ;Are any bits set in H OR L ;or in L? POP HL ;Restore old contents RET NZ ;HL <> 0 isn't enabled SCF ;Otherwise, they really RET ;are disabled. G1 POP HL ;Exit when P flag is RET ;set by LD A,I --cut-----------------------------------