Signetics 2650 & 2636 编程/中断
中断是一种机制,允许外部事件向微处理器发出信号,使其停止正在执行的操作并处理该事件的需求。在这些控制台中,只有 PVI 能够做到这一点。导致中断的事件是
- 每次垂直复位的前沿
- 对象的视频生成完成。
PVI 的中断在垂直复位信号的后沿被复位。
PVI 在其 INTREQ 引脚上向处理器发出中断请求信号。如果处理器程序状态字上部的中断禁止位没有设置,则以下事件将发生
- 处理器完成正在执行的指令
- 处理器将指令地址寄存器压入返回地址栈
- 处理器设置中断禁止位
- 处理器在 INTACK 信号上发出它接受请求的信号
- 处理器开始执行一个 ZBSR(分支到相对于位置零的子程序)
- PVI 在数据总线上输出 $03,它内置的中断向量和 ZBSR 指令的第二个字节
- 处理器通过从地址 $0003 开始执行来完成 ZBSR 指令
注意,处理器自动保存的唯一信息是返回地址。由程序员来保存状态寄存器和中断服务例程可能使用的任何通用寄存器(见下文)。
处理器可以通过检查寄存器 $1FCA 的对象完成位和寄存器 $1FCB 的 VRLE 位来确定 PVI 请求中断的原因。请注意,这些寄存器的所有位在读取时被清除,并在 VRST 的后沿被清除。
中断服务例程通过一个从子程序返回指令来终止,通常是一个 RETE,它会再次启用中断,或者可以使用 RETC 指令,如果不需要启用中断。
在任何中断服务结束时,必须将寄存器恢复到中断发生时的相同状态。对于寄存器 r1、r2 和 r3,这通常通过在中断服务例程期间切换到第二个寄存器组来实现。
寄存器 r0 和程序状态字下部更麻烦。问题在于,在 2650A 上,程序状态字只能转移到 r0,而不能直接转移到内存。在 2650B 上,通过添加 LDPL 和 STPL 指令解决了这个问题。
这不起作用
stra,r0 STORER0 ;save r0 in memory spsl ;r0 = PSL stra,r0 STOREPSL ;save PSL in memory ...... ..the rest of the interrupt service routine goes here ...... loda,r0 STOREPSL lpsl ;restore PSL loda,r0 STORER0 ;restore r0 rete,un
这里的问题是最后一个 loda 指令会影响恢复的 PSL 中的条件码位。
一个巧妙的解决方案如下
start_interrupt: stra,r0 PRESERVER0 ;PRESERVER0 = r0 ppsl $10 ;bank 1 spsl stra,r0 PRESERVEPSL ;save PSL with bank 1 already selected! .......... end_interrupt: loda,r0 PRESERVEPSL ; strz r4 ;put a copy of PSL in r4 lpsl ;restores psl (but with bank 1 still selected) loda,r0 PRESERVER0 ;restore r0 (but probably changes the condition code) andi,r4 $C0 ;this restores the condition code! cpsl $10 ;switch to bank 0 rete,un ;
如果还不清楚那个 AND 操作是如何工作的,那是因为条件码位于 PSL 的位 7 和 6 中。它们的二进制值(00=零,01=正,10=负)对应于 AND $C0 操作的结果
- 00000000 为零
- 01000000 是一个正数
- 10000000 是一个负数
本教程的程序 执行与 同步到对象完成 中相同的任务,但它不是不断检查 VRST 的状态或轮询 PVI 来查看对象 1 的视频生成是否已完成,而是依赖于 PVI 的中断来使处理器停止正在执行的操作并处理发生的任何事件。
一旦发生中断,并且寄存器 0 和 PSL 被保存,中断服务例程会检查中断是否由垂直复位引起。它通过测试 “碰撞” 寄存器 $1FCB 中的 VRLE 位来做到这一点。如果是,则子程序 Object1A 会负责设置对象的初始状态。然后退出中断例程,处理器在这种情况下去等待下一个中断。当下一个中断到来时,它一定是由于对象 1 的完成引起的。然而,此时有必要确定是主对象、它的第一个副本还是它的第二个副本引起了中断。PVI 无法直接告诉我们这一点,因此使用了变量 Obj1dup 来做到这一点。如果变量为 1,则执行子程序 Object1B;这会设置第一个副本并将变量设置为 2。在下一个中断时,执行 Object1C,这会设置第二个副本并将变量设置为 0。
这是一个非常简单的程序,只有一个对象引起中断,而且只需要确定是哪个副本引起了中断。当使用更多对象时,中断服务例程还必须确定哪个对象正在引起中断。这是通过读取 $1FCA 的 objectstatus 来完成的。位 0-3 根据哪个对象已完成进行设置。
在使用此寄存器时需要小心,因为它在读取时会被复位,而且它还包含对象/背景碰撞标志。这意味着所有设置的位都需要立即处理,或者保存在变量中以便以后使用。