2008-01-23

A skeleton of a typical CPU emulator in C

偶然看到这篇文章,觉得很有意思,于是坐下来仔细阅读....为了尊重作者,只给出URL并不把文章贴过来.
整个文章的中 心是下面这段伪代码,原文用蓝色,注释用50%Grey.
1
2 Counter = InterruptPeriod; // 循环计数(cycle counter)
3 PC = InitialPC; // 程序计数器(program counter),存放着目前执行指令所在的地址 - The PC contains the memory address from which our emulated CPU will read its next opcode
4
5 for(;;)
6 {
7 OpCode=Memory[PC++]; // read the next opcode, and modify the program counter
8
Counter-=Cycles[OpCode];
// Cycles数组存放的是每个操作码所需要的CPU周期 - The Cycles[] table should contain the number of CPU cycles for each opcode.
9
10 switch(OpCode)
11 {
12 case OpCode1:
13 case OpCode2:
14 ...
15 }
16
17 if(Counter<=0)
18 {
19 /* Check for interrupts and do other */
20 /* cyclic tasks here */
21 ...
22 Counter+=InterruptPeriod;
23 if(ExitRequired) break;
24 }
25 }
相 关概念
1. 程序计数器(program counter),存放着目前执行指令所在的地址
计算机执行一条机器指令的步骤为:
Fetch(取指令): 由Control Unit读取Program Counter的�容,根据Program Counter的数值去相对应的Memory取指令;
Decode(解码): 抓到的指令经Control Unit判读,�定要如何执行该指令
Execute(执行): 在ALU(Alrithmetic and Logic Unit)里执行该指令
Write(回写): 更改Program Counter的�容
2. 操作码(opcode) 机器指令包含两个部分:操作码(op-code)和操作数(operand)
作 者对代码做出的补充说明
Line 5: 这个for循环要是用while(1)代替的话会导致一些问题- some compilers will generate code checking whether 1 is true or not. You certainly don't want the compiler to do this unnecessary work on every pass of a loop.
Line 7: 这个方式有些问题- Note that while this is the simplest and fastest way to read from emulated memory, it is not always feasible. A more universal way to access memory is covered later in this document.
Line 8: 有些操作码所需的CPU周期会根据参数的不同而不同(比如跳转指令和子例程调用) - Beware that some opcodes (such as conditional jumps or subroutine calls) may take different number of cycles depending on their arguments. This can be adjusted later in the code though.
Line 10: switch这有个误区- It is a common misconception that the switch() construct is inefficient, as it compiles into a chain of if() ... else if() ... statements. While this is true for constructs with a small number of cases, the large constructs (100-200 and more cases) always appear to compile into a jump table, which makes them quite efficient.
我的问题
1. 按我理解 InterruptPeriod是一个根据Task来设置的动态值,它设置的 rule是什么呢?
2. PC是应该执行指令再increase呢还是想本文那样取完就increase?还是无所谓?

进一步的资料
看完还是对CPU simulator没感觉,还需要看一下文章作者写的Z80 CPU Simulator code。另外我记得Valgrind里面好像是有一个CPU Simulator实现,有时间可以看一下,另外<<Build your own RISC processor simulator>>有时间也需要读一下。