【问题标题】:Determining when an Interrupt Routine will end for Gameboy GB Emulation确定 Gameboy GB 仿真的中断例程何时结束
【发布时间】:2017-12-14 21:36:24
【问题描述】:

所以对于上下文,我想告诉你我到目前为止所理解的:

  • 在指令执行后调用中断处理并设置中断主机启用标志。

  • 中断处理由多个“中断例程”组成(对于 gameboy,它具有 Vblank、LCD stat、计时器、游戏手柄和串行)。

  • CPU 需要根据 IE 标志和 IF 标志上设置的值来处理每个中断。

  • 中断例程有优先级(与我的问题无关)。

  • 中断例程必须有开始和结束

因此,查看中断例程,它首先将在例程结束后应该保留的寄存器值推入堆栈指针。现在它总是有 reti 指令,我认为它总是中断例程的结束,它应该在处理中断之前弹出下一条指令的地址。

我想知道是否:

  • reti 指令应该在每个中断例程中仅出现 一次 并且在最后出现,这是否是一个“标准”?因为这是我可以确定是否会结束阅读进一步说明的唯一方法,

  • 它使用 reti 而不是 ret,因为我们想要断言 ime 标志仍处于启用状态,因此可以继续检查是否需要提供任何其他中断,

  • 在开始中断处理之前,我需要显式地将下一条指令的地址压入堆栈指针,因为没有汇编指令指示在中断处理开始之前将其压入。这是用于中断结束时的重新指令。

编辑:

因此,为了提供有关我的问题的更多背景信息,我决定发布我的指令周期代码。

在 CPU.c 中

#include "InteruptHandler.c"
void main(){
    while(){ //No proper argument yet. for fetch-decode-execute cycle
    opcode = fetchInstruction();
    decodeandExecuteInstruction(opcode); //Lets say an instruction is executed and it enabled the IME_flag. that is IME_flag = ENABLED

    //Check if ime_flag is enabled. processInterupt if true.
    isInteruptEnabled() ? processInterupts(): 0; //This would fall true.
    }
}

在 InteruptHandler.c 中

processInterupts(){

    opcode;
    bitmask = 0x01;

    //Check each bit for interupt. Bitmask will go 0x00 if the value 0x80 is shifted by 1
    for(; bitmask ; bitmask = bitmask << 1){

        //CHeck if IE and IF flag for corresponding interupt is set. process interupt if set
        IE_flag & bitmask ? (IF_flag & bitmask ? determineInterupt(bitmask) : 0) : 0; 
    }
}

determineInterupt(bitmask){

    //push the next instruction address to stack pointer
    push(PC);

    //Set PC into corresponding interupt address

//code below is my problem. I stumbled upon how would I end this function and I came up to determining when an interupt routine ends. 
//I came up with the reti function. 
//But after realizing that I already set the PC somewhere above this code, I just need to discard this code and let the main function do its instruction cycling. 
//Thanks to @duskwuff for pointing that out. 
//I just added some code to end the bitmask checking when it sees 1 interupt request and is most priotiry. 
//Also thanks to @Ped7g for giving me more information about the complexity of interupt handling. I'm not yet seeing where I should implement those. There are still so many thing to implement and yet to know when this excatly can happen.
//My question has been answered nevertheless, which is to end a function code blocks that I discarded at the end :)

//process the corresponding interupt
    do{
        opcode = fetchInstruction();
        decodeandexecuteInstruction(opcode);
    }while (opcode != RETI)
}

【问题讨论】:

    标签: c assembly emulation gameboy


    【解决方案1】:
    • 中断例程必须有开始和结束

    这不是真的。您不应该对内存中的代码布局做出任何假设——只需运行您遇到的指令即可。

    在某些情况下,中断服务例程可以在返回之前重新启用中断以允许同时服务另一个中断。您的设计应该考虑到这一点。

    它使用 reti 而不是 ret,因为我们想要断言 ime 标志仍然处于启用状态,因此可以继续检查是否需要提供任何其他中断,

    没有。 RETI 指令在返回时重新启用中断——它实际上是 EI 和 RET 的组合。不涉及断言。

    【讨论】:

    • > 这不是真的。您不应该对内存中的代码布局做出任何假设——只需运行您遇到的指令即可。 - 假设有多个中断请求 - 也就是说,设置了相应的 IF 标志 - 如果 cpu 不知道当前中断何时完成,它将如何处理其他请求?我相信 reti 指令的目的是通知 CPU 中断已经完成,并将 PC 寄存器设置为指向最后一条指令。但是cpu不会让下一条指令被执行,因为还有剩余的中断需要处理。
    • @butchtiki 与 真正的 CPU 做同样的事情:使用中断标志确定 CPU 是否处于中断模式(由 从中断返回 指令)并在每条指令之前检查挂起的中断条件,除非 CPU 处于中断模式。
    • > (通过中断指令的返回清除 - 您是指 ime 标志。但我不确定,因为您刚刚说过从中断指令的返回可以清除。但是我理解但在中断例程之后,它通过 reti 指令重新启用 ime 标志。CPU 将检查这是否是处理的最后一个中断。如果为真,我 - 作为 CPU - 将显式禁用 ime 标志而无需读取汇编指令。这将阻止我-cpu-在正常模式下每隔一次执行后续指令处理中断(而不是处理中断)。
    • @butchtiki GB 实际上对中断进行排队吗?我以为他们只是迷路了,以防在提出中断请求时中断被禁用。 (这只是纯粹的猜测,我没有真正研究过 GB 蓝图/文档,我只是从 ZX 的经验中猜测,因为它具有类似的 CPU,而且我不知道 Z80 在任何地方存储任何复杂的状态(除了影子寄存器在那个时代实际上是相当复杂的存储......而那些在 GB 修改的 CPU 上不存在)。
    • @Ped7g 一旦 ime 标志被禁用,它就不会排队中断。但是一旦启用了ime标志,只要启用了IE寄存器中相应的标志,就应该处理当时的所有中断请求(即IF寄存器)。至少到目前为止我的理解是这样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多