Assembly 在TI-84 Plus CE上设置中断
我正试图设置一个中断来捕捉按下ON按钮的动作 这是我目前的代码:Assembly 在TI-84 Plus CE上设置中断,assembly,interrupt,interrupt-handling,texas-instruments,z80,Assembly,Interrupt,Interrupt Handling,Texas Instruments,Z80,我正试图设置一个中断来捕捉按下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
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
然而,这只是冻结了我的计算器(因为我不能使用任何键来停止程序)
我相信这个问题是可以中断的。我真的不明白这个表应该如何格式化。我在下面链接的ez80应用程序说明中说,“每个向量都是指向_vectptr段的4字节地址”,但ez80使用24位地址,因此我不确定如何构造每个向量
非常感谢您的帮助
我已阅读/试图阅读的参考资料:
- [注:这是针对z80的 TI-84+CE运行ez80]
56 34 12 00
(不确定最后一个00
是否可以是垃圾,或者必须是零,我想对于未来的兼容性,零更好,尽管我想eZ80F91将只使用24位,忽略最后8位)
因此,您原始问题中的定义很可能是错误的,00
应该在3个字节之后,而不是前面
三个字节的.dl
应该足够了,还可以通过.db
添加额外的垃圾字节(以避免手动标签分解为字节)
我只熟悉经典的Z80,所以我不知道你的代码到底出了什么问题,但是一般的原则和东西可能值得一看:
- 检查设备是否真的有eZ80F91(“-like”?还有谁在制造它的克隆?我猜它要么是Zilog的原创,要么不是,不可能是“-like”),因为任何其他eZ80变体只有8位
寄存器,需要不同的中断表设置和中断处理(可以尝试I
ld i,hlld hl,0x1234
ld hl,0
并检查ld hl,i
中的值是否返回到hl
)0x1234
- 在代码初始化向量表时,检查调试器中生成的二进制文件或内存是否包含预期值
- 检查设备描述(如果可用),触发哪种中断,以及何时触发,为什么您实际希望按钮“开”触发中断?(例如,ZX频谱-我熟悉的Z80机器-没有键盘中断,键盘必须通过代码进行轮询,唯一的中断是在显示光束的垂直回程开始时触发的,即PAL/SECAM ZX型号为~50Hz,而美国NTSC型号为~60Hz,导致游戏在美国ZX克隆上运行稍微快一点…IIRCTI计算器有定时器中断,比如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”作出反应通过清除vram进行标记。处理程序中不应有任何严重的“biz”逻辑,只将即将出现的状态/数据(如串行总线I/O上的数据)收集到一些标志/缓冲区中,并让中断之外的主代码以完整逻辑处理这些标志/缓冲区
也许你会考虑尝试一些经典的Z80,除非你真的很想要EZ80F91。经典的Z80有很多可用的材料,不同的机器和仿真器,因为它是非常流行的CPU(例如我是Z80的一个)专家。“由于ZX频谱计算机,我在1991年至1996年期间为它做了一些演示和游戏。.就是这样