确定 Gameboy GB 仿真的中断例程何时结束
Determining when an Interrupt Routine will end for Gameboy GB Emulation
所以对于上下文,我想让你知道我到目前为止的理解:
指令执行后调用中断处理并设置中断主机启用标志。
Interupt Handling 由几个 "interrupt routines" 组成(对于 gameboy,它有 Vblank、LCD stat、timer、joypad 和 serial)。
CPU 需要根据 IE 标志和 IF 标志上设置的值来处理每个中断。
中断例程有优先级(与我的问题无关)。
中断例程必须有开始和结束
所以查看中断例程,首先是将例程结束后应保留的寄存器值压入堆栈指针。现在它总是有 reti 指令,我认为它是 always 中断例程的结尾,它应该在处理中断之前弹出下一条指令的地址。
我想知道是否:
reti指令是否"standard"每个中断例程只出现一次并且出现只 在末尾?因为这是我确定是否会结束阅读进一步说明的唯一方法,
它使用 reti 而不是 ret 因为我们想断言 ime 标志仍然启用,因此可以继续检查是否需要提供任何其他中断,
在中断处理开始之前,我需要明确地将下一条指令的地址压入堆栈指针,因为在中断处理开始之前没有汇编指令指示压入它.这是为了在中断结束时重新引入 btw。
编辑:
因此,为了提供有关我的问题的更多背景信息,我决定 post 我的指令周期代码。
在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)
}
- Interrupt routines must have start and end
这不是真的。您不应该对内存中的代码布局做出任何假设 - 只是 运行 您遇到的指令。
在某些情况下,中断服务例程可以在返回之前重新启用中断,以允许同时处理另一个中断。您的设计应该考虑到这一点。
it uses reti instead of ret because we want to assert that ime flag is still enabled and thus can continue checking if any other interupt needs to be served,
没有。 RETI 指令在返回时重新启用中断——它实际上是 EI 和 RET 的组合。没有涉及断言。
所以对于上下文,我想让你知道我到目前为止的理解:
指令执行后调用中断处理并设置中断主机启用标志。
Interupt Handling 由几个 "interrupt routines" 组成(对于 gameboy,它有 Vblank、LCD stat、timer、joypad 和 serial)。
CPU 需要根据 IE 标志和 IF 标志上设置的值来处理每个中断。
中断例程有优先级(与我的问题无关)。
中断例程必须有开始和结束
所以查看中断例程,首先是将例程结束后应保留的寄存器值压入堆栈指针。现在它总是有 reti 指令,我认为它是 always 中断例程的结尾,它应该在处理中断之前弹出下一条指令的地址。
我想知道是否:
reti指令是否"standard"每个中断例程只出现一次并且出现只 在末尾?因为这是我确定是否会结束阅读进一步说明的唯一方法,
它使用 reti 而不是 ret 因为我们想断言 ime 标志仍然启用,因此可以继续检查是否需要提供任何其他中断,
在中断处理开始之前,我需要明确地将下一条指令的地址压入堆栈指针,因为在中断处理开始之前没有汇编指令指示压入它.这是为了在中断结束时重新引入 btw。
编辑:
因此,为了提供有关我的问题的更多背景信息,我决定 post 我的指令周期代码。
在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)
}
- Interrupt routines must have start and end
这不是真的。您不应该对内存中的代码布局做出任何假设 - 只是 运行 您遇到的指令。
在某些情况下,中断服务例程可以在返回之前重新启用中断,以允许同时处理另一个中断。您的设计应该考虑到这一点。
it uses reti instead of ret because we want to assert that ime flag is still enabled and thus can continue checking if any other interupt needs to be served,
没有。 RETI 指令在返回时重新启用中断——它实际上是 EI 和 RET 的组合。没有涉及断言。