Установка прерывания на TI-84 Plus CE

Я пытаюсь установить прерывание, чтобы поймать нажатие кнопки ON.

Это мой код до сих пор:

SetInterrupt:
 di
  ; copy the 4 bytes from InterruptVectorTable to cursorImage
  ; (I chose cursorImage because it's on a 512-byte boundary, 0E30800h)
 ld   hl, InterruptVectorTable
 ld   de, cursorImage
 ld   bc, 4
 ldir
  ; clone the same 4 bytes into the rest of the 256-byte interrupt vector table
 ld   hl, cursorImage
 ld   de, cursorImage + 4
 ld   bc, 252
 ldir
  ; load the address of the new interrupt vector in the i register
  ;  and set interrupt mode to 2
 ld   hl, cursorImage >> 8 & 0ffffh
 ld   i, hl
 im   2
 ei
 ret
FillScreen:
  ; fills the screen with black pixels
 ld a, 0
 ld hl, vRam
 ld bc, 320*240*2
 call _MemSet
 ret
InterruptVectorTable:
  ; try to call FillScreen whenever there's an interrupt
 .db 00, FillScreen & 0ffh, FillScreen >> 8 & 0ffh, FillScreen >> 16 & 0ffh

Однако это просто зависает мой калькулятор (поскольку я не могу использовать какие-либо клавиши, чтобы остановить программу).

Я считаю, что проблема в InterruptVectorTable. Я не очень понимаю, как таблица должна быть отформатирована. В примечаниях по применению ez80, на которые я ссылаюсь ниже, говорится: «Каждый вектор представляет собой 4-байтовый адрес, указывающий на сегмент __vectptr», но ez80 использует 24-битные адреса, поэтому я не уверен, как структурировать каждый вектор.

Любая помощь приветствуется.


Ссылки, которые я читал/пытался прочитать:


person Benjy Wiener    schedule 27.08.2018    source источник
comment
Можете ли вы использовать отладчик или симулятор? Обычно это чрезвычайно полезно для asm.   -  person Peter Cordes    schedule 27.08.2018
comment
@PeterCordes По этой причине я пытался использовать CEmu, но программа просто разбила калькулятор, как только я попытался установить прерывание.   -  person Benjy Wiener    schedule 27.08.2018
comment
Эмулятор слетел? Или виртуальный калькулятор внутри эмулятора разбился? Если это только последнее, то есть ли у него встроенный отладчик, который позволяет вам исследовать память / регистры на этом этапе? Смысл использования эмулятора в том, что он позволяет выполнять отладку и пошаговое выполнение даже с отключенными прерываниями, совершенно незаметно для гостя.   -  person Peter Cordes    schedule 27.08.2018
comment
@PeterCordes Виртуальный калькулятор. Я начал смотреть на инструменты отладки, но как только я увидел, что программа дает сбой на эмуляторе (во время работы на моем реальном устройстве), я отказался от эмулятора. Когда у меня будет возможность, я попытаюсь проверить, есть ли в CEmu возможность ломать и отлаживать при сбоях.   -  person Benjy Wiener    schedule 27.08.2018
comment
Подождите, разве вы не говорили, что он блокируется и на реальном оборудовании? Я не знаю TI-84 или z80, просто общий принцип заключается в том, что точный эмулятор/симулятор со встроенным отладчиком может быть очень полезен для отладки ОС/ядра. такие действия, как управление прерываниями, которые просто падают без какого-либо намека на что было не так, если вы делаете какие-либо ошибки. Если вы уверены, что CEmu не точно эмулирует то, как он работает на реальном оборудовании, тогда да, это может быть бесполезно.   -  person Peter Cordes    schedule 27.08.2018
comment
@PeterCordes Мое устройство зависло, потому что все нажатия клавиш используют прерывания. Однако на CEmu это вызвало сброс ОЗУ.   -  person Benjy Wiener    schedule 27.08.2018
comment
мне кажется, у вас неправильное содержимое IVT, неиспользуемые 24-31 бит адреса 32b - это последний четвертый байт (с прямым порядком байтов), то есть .db FillScreen & 0ffh, FillScreen >> 8 & 0ffh, FillScreen >> 16 & 0ffh, 00 (или у него нет какой-то директивы для определения 32 бита, как ожидалось бы .dd FillScreen исходящий из мира x86) - на основе чтения PDF-документа «Настройка прерываний», стр. 13 (10 на бумаге), главы «Отображение местоположения ISR в таблице векторов прерываний». Также у вашего устройства действительно есть процессор eZ80F91? (только тот, у которого 16-битный регистр I).   -  person Ped7g    schedule 27.08.2018
comment
@ Ped7g Что касается порядка байтов, я на самом деле пробовал оба способа, но безуспешно. Я также пробовал оба способа с нулевым байтом до и затем снова с нулевым байтом после адреса. Есть директива .dl для 3 байта LE (которую я тоже пробовал), но для 4 байт ничего не нашел. Согласно [wiki.tiplanet.org/TI-84_Plus_CE], процессор eZ80F91- нравится.   -  person Benjy Wiener    schedule 27.08.2018
comment
В ранних аппаратных версиях прерывания были разрешены. Сейчас они отключены. Похоже, ваш настоящий калькулятор - один из оригиналов. Источник: cemetech.net/forum/viewtopic.php?t=13966&start= 0   -  person Zeda    schedule 28.08.2018
comment
@Zeda Интересно, спасибо! Вы случайно не знаете, как программы отключают/отлавливают клавишу ON без im 2? (Кроме того, в сообщении упоминалось об удалении прерываний из цепочки инструментов CE, возможно, я пройдусь по ревизиям и попытаюсь увидеть, что именно было удалено, может быть полезно.)   -  person Benjy Wiener    schedule 28.08.2018
comment
@Zeda Я провел небольшое исследование (просмотрел кучу ассемблерных программ, которые, казалось, отключали клавишу ON), и кажется, что хитрость заключается в том, чтобы продолжать вызывать _GetCSC (вообще без прерываний). Я также могу поймать нажатие клавиши ON, просто проверив, есть ли ожидание прерывания ON, а затем сбросив флаг. Это подойдет для моих целей, и я постараюсь не забыть написать ответ завтра. Спасибо еще раз!   -  person Benjy Wiener    schedule 28.08.2018
comment
Ооо, вы пытаетесь предотвратить это из программы сборки? Тогда это определенно осуществимо. Просто не забудьте res onInterrupt,(iy+onFlags), чтобы пользователь не получил ошибку Err: Break при выходе.   -  person Zeda    schedule 29.08.2018


Ответы (1)


Любая помощь приветствуется.

Таким образом, публикуя эту болтовню в качестве ответа, потому что раздел комментариев раздражает меня ограничением длины плюс форматированием, а ваш «вопрос» выше делает такой «ответ» законным.

Согласно PDF-документу «Настройка прерываний» на странице 13, 32-битный формат адреса ясен, в случае адреса 0x123456 память должна содержать байты 56 34 12 00 (не уверен, что последние 00 могут быть мусором или должны быть нулевыми, Я предполагаю, что для будущей совместимости лучше использовать ноль, хотя я предполагаю, что eZ80F91 будет использовать только 24 бита, игнорируя последние 8).

Таким образом, определение в вашем исходном вопросе, скорее всего, неверно, 00 должно быть после 3 байтов, а не впереди.

Трех байтов .dl должно быть достаточно с дополнительным дополнительным мусорным байтом на .db (чтобы избежать ручного разложения метки на байты).

Я знаком только с классическим Z80, поэтому не имею точного представления, что не так с вашим кодом, но общие принципы и вещи, которые, вероятно, стоит проверить:

  • проверьте, действительно ли устройство имеет eZ80F91 («-подобный» ??? кто еще производит какой-либо его клон? Я думаю, он либо оригинален от Zilog, либо нет, «-подобный» невозможен), потому что любой другой вариант eZ80 имеет только 8 бит I, и требуется другая настройка таблицы прерываний и обработка прерываний (возможно, попробуйте ld hl,0x1234 ld i,hl ld hl,0 ld hl,i и проверьте значение в hl, если оно возвращается к 0x1234).

  • проверьте созданный двоичный файл или в отладчике, пока код инициализирует векторную таблицу, что память содержит ожидаемые значения

  • проверьте описание устройства (если доступно), какие прерывания запускаются и когда, почему вы на самом деле ожидаете, что кнопка «вкл» вызовет прерывание? (например, ZX Spectrum — машина Z80, с которой я знаком — не имеет прерывания клавиатуры, клавиатура должна опрашиваться кодом, единственное прерывание срабатывало при начале вертикального обратного хода луча дисплея, т.е. на частоте ~50 Гц с PAL/SECAM Модели ZX и около 60 Гц с вариантами NTSC для США, в результате чего игры работают немного быстрее на клонах ZX в США ... IIRC калькуляторы TI имеют прерывание по таймеру, например, 100 Гц, но я никогда не изучал их подробно, так что это может совершенно неверная информация)

  • убедитесь, что вы находитесь в режиме «ADL», а не в режиме совместимости «Z80».

  • ваша подпрограмма «FillScreen» пытается вернуться, но, похоже, у нее нет надлежащего пролога/эпилога, подобного прерыванию, поэтому, где бы она ни возвращалась, она повредила содержимое регистров и не возвращается через reti.

  • вы также возвращаетесь из подпрограммы SetInterrupt во что-то... что выполняется тем временем, пока ваше прерывание установлено?

Сначала вы можете попробовать «пустой» обработчик прерывания, например

FillScreen:
    ei        ; not sure if there's implicit DI - if yes, EI needed
    reti

чтобы убедиться, что код, работающий в основном потоке, в порядке (и работает ли ваш обработчик прерываний). Имейте в виду, что если работает обычный обработчик калькулятора, и для его жизни требуется собственный обработчик прерывания, то просто установка пустого прерывания уже будет препятствовать функциональности ... возможно, вам никогда не следует возвращаться из вашего кода (основной поток, например, где вызывается setInterrupt) и сделайте свой собственный бесконечный основной цикл).

Если вы хотите сделать больше в своем прерывании, вы должны сохранить значения регистров для кода в основном потоке, например, если вы знаете, что основной поток НЕ использует альтернативные регистры, вы можете быстро переключать регистры с помощью

interruptHandler:
    di        ; disable interrupts until done
    ; (especially if you know your interrupt may take longer to run)

    ; preserve current register values (by switching to alternate ones)
    ex   af,af
    exx
    ; do your stuff here (destroying alternate register values)
    ; which is OK, if your interrupt handler is the only code using them
    ...
    ; restore the register values back (by switching to original ones)
    exx
    ex   af,af
    ; return from interrupt
    ei
    reti

Или, если вы знаете, что в стеке всегда достаточно места, вы используете push/pop для сохранения исходных значений регистров.

Или, если пространство стека может быть слишком напряженным, но у вас есть отдельный блок памяти, который можно использовать в качестве стека обработчика прерываний, вы можете сначала переключиться на него:

interruptHandler:
    di
    ; preserve current stack pointer (self-modify code)
    ld   (interruptHandler_SP+1),sp
    ld   sp,top_of_interrupt_stack
    ; preserve registers as needed (AF with flags being a MUST)
    push ...
    ; do your stuff here
    ...
    ; restore registers as needed
    pop ...
    ; restore stack pointer
interruptHandler_SP:
    ld   sp,0x123456     ; this will be overwritten at start of handler
    ; return from interrupt
    ei
    reti

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

Кроме того, заполнение экрана - немного неудачный выбор (так как это займет очень много времени, и его трудно увидеть дважды).

Возможно, в качестве быстрого теста сделайте что-то вроде:

testInterrupt:
  di
  push   af
  ; increment first byte of video ram to make some visible "noise"
  ld     a,(vRam)
  inc    a
  ld     (vRam),a
  ; restore flags, enable interrupts, return back to main code
  pop    af
  ei
  reti

И, как правило, обработчики прерываний должны быть очень быстрыми и крошечными, выполнение таких задач, как очистка vram, должно быть оставлено основному коду, прерывание, вероятно, должно просто устанавливать какой-то глобальный флаг, что требуется очистка vram (чтобы завершить в течение нескольких T циклов), а затем основной код может в цикле тестировать различные флаги событий и реагировать на флаг «clear vram», очищая vram. В обработчиках не должно быть какой-либо серьезной логики «бизнеса», они собирают только состояние/данные, которые неизбежны (например, данные о вводе-выводе последовательной шины), в некоторые флаги/буферы и позволяют основному коду вне прерывания обрабатывать такие флаги/буферы с полной логикой.


Может быть, даже подумайте о том, чтобы сначала попробовать какой-нибудь классический Z80, если вы действительно не хотите eZ80F91. Классический Z80 имеет массу доступных материалов с различными машинами и эмуляторами, поскольку это был очень популярный процессор (например, я своего рода «эксперт» по Z80 благодаря компьютеру ZX Spectrum, я написал несколько демо и игр для него). 1991-1996 годы). Так что с этим будет легче помочь (кажется, этот вопрос оставался без ответа достаточно долго, чтобы догадаться, что не так много людей кодируют для eZ80F91).

person Ped7g    schedule 27.08.2018
comment
Спасибо. У меня еще не было возможности просмотреть все, что вы написали, но я смог подтвердить, что у меня 16 бит (используя ld hl, $4162, ld i, hl, ld hl, 0, ld hl, i, ld (pixelShadow), hl, ld hl, pixelShadow, call _PutS). - person Benjy Wiener; 27.08.2018