【问题标题】:Setting an interrupt on the TI-84 Plus CE在 TI-84 Plus CE 上设置中断
【发布时间】:2018-08-27 03:34:10
【问题描述】:

我正在尝试设置中断以捕捉按下 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 应用说明说“每个向量是一个指向 __vectptr 段的 4 字节地址”,但 ez80 使用 24 位地址,所以我不确定如何构造每个向量。

非常感谢任何帮助。


我已阅读/尝试阅读的参考文献:

【问题讨论】:

  • 你可以使用调试器或模拟器吗?这通常对 asm 非常有帮助。
  • @PeterCordes 出于这个原因我尝试使用 CEmu,但是当我尝试设置中断时,程序就让计算器崩溃了。
  • @PeterCordes 它冻结了我的设备,因为所有按键输入都使用中断。但是,在 CEmu 上,它会导致 RAM 重置。
  • @Zeda 我做了一些研究(查看了一堆似乎禁用 ON 键的 asm 程序),似乎诀窍是继续调用 _GetCSC (根本没有中断)。我也可以通过检查是否有 ON 中断等待然后重置标志来捕捉 ON 按键。这将适合我的目的,我会尽量记住明天写一个答案。再次感谢!
  • 哦,你是想在汇编程序中阻止它吗?那这绝对是可行的。请记住 res onInterrupt,(iy+onFlags) 以防止用户收到 Err: Break on exit。

标签: assembly interrupt interrupt-handling texas-instruments z80


【解决方案1】:

非常感谢任何帮助。

因此发布此闲聊作为答案,因为评论部分因长度限制和格式而让我烦恼,而您上面的“问题”使这种“答案”变得合法。

根据“设置中断”PDF文档,第13页,地址的32位格式是明确的,在地址0x123456的情况下,内存应该包含字节56 34 12 00(不确定最后一个00是否可以是任何垃圾,或者必须为零,我想对于未来的兼容性,零更好,虽然我猜 eZ80F91 将只使用 24 位,忽略最后 8)。

所以你原来问题中的定义很可能是错误的,00 应该在 3 个字节之后,而不是在前面。

.dl 的三个字节应该足够了,.db 也有额外的额外垃圾字节(以避免手动标签分解成字节)。

我只熟悉经典 Z80,所以我不知道你的代码有什么问题,但一般原则和可能值得检查的事情:

  • 检查设备是否具有真正的 eZ80F91(“-like”???还有谁在制造它的一些克隆?我猜它要么是 Zilog 的原创,要么没有“-like”可能),因为任何其他 eZ80 变体只有 8 位 I 寄存器,需要不同的中断表设置和中断处理(可以尝试 ld hl,0x1234 ld i,hl ld hl,0 ld hl,i 并检查 hl 中的值是否返回到 @ 987654332@)。

  • 在代码初始化向量表时检查生成的二进制文件或调试器中的二进制文件,确保内存中包含预期的值

  • 检查设备描述(如果可用),触发哪种中断以及何时触发,为什么您实际上期望按钮“打开”触发中断? (例如 ZX Spectrum - 我熟悉的 Z80 机器 - 没有键盘中断,必须通过代码轮询键盘,唯一的中断是在显示光束的垂直回扫开始时触发的,即在 ~50Hz 时使用 PAL/SECAM ZX 型号,美国 NTSC 变体约 60Hz,导致游戏在美国 ZX 克隆上运行得更快...... IIRC TI 计算器有定时器中断,如 100Hz 的,但我从未深入研究过它们,所以这可能是完全错误的信息)

  • 确保您处于“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 周期内完成) ,然后主代码可以循环测试各种事件标志,并通过清除 vram 对“clear vram”标志做出反应。处理程序中不应该有任何严重的“商务”逻辑,只将即将发生的状态/数据(如串行总线 I/O 上的数据)收集到一些标志/缓冲区中,并让中断之外的主要代码进行处理具有完整逻辑的此类标志/缓冲区。


甚至可以考虑先尝试一些经典的 Z80,除非你真的非常想要 eZ80F91。经典的 Z80 有大量可用的材料,具有不同的机器和仿真器,因为它是非常流行的 CPU(例如,由于 ZX Spectrum 计算机,我是 Z80 的“专家”,我确实为它编写了几个演示和游戏代码1991-1996 年)。所以帮助解决这个问题会更容易(似乎这个问题没有得到足够长的时间回答,以至于猜测没有那么多人为 eZ80F91 编码)。

【讨论】:

  • 谢谢。我还没有机会浏览你写的所有东西,但我能够确认我是 16 位(使用 ld hl, $4162ld i, hlld hl, 0ld hl, ild (pixelShadow), hl , @987654345 @ , call _PutS)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多