Re: 从零开始的红白机模拟 - [07]流程指令 - Dust Loong的文章 - 知乎 https://zhuanlan.zhihu.com/p/44102262
Dust Loong
兴趣:人机交互 https://github.com/dustpg
1 人赞了该文章
本文github备份地址
同样, '流程指令'是指为了和上节分开而自己随便取的名字.
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 绝对 | JMP Oper | 4C | 3 | 3 |
| 间接 | JMP (Oper) | 6C | 3 | 5 |
无条件跳转, 影响FLAG: (无), 伪C代码:
PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BEQ Oper | F0 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
当然, 如果没有实行跳转则花费2周期, 下同.
如果标志位Z(ero) = 1[即相同]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (ZFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BMI Oper | D0 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位Z(ero) = 0[即不相同]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (!ZFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BCS Oper | B0 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位C(arry) = 1[即进位了]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (CFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BCC Oper | 90 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位C(arry) = 0[即没进位]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (!CFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BMI Oper | 30 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位S(ign) = 1[即负数]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (SFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BPL Oper | 10 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位S(ign) = 1[即正数]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (!SFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BVS Oper | 70 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位(o)V(erflow) = 1[即溢出]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (VFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 相对 | BVC Oper | 50 | 2 | 2* |
* +1s 跳转同一页面 * +2s 跳转不同页面
如果标志位(o)V(erflow) = 0[即没有溢出]则跳转,否则继续, 影响FLAG: (无). 伪C代码:
if (!VFLAG) PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 绝对 | JSR Oper | 20 | 3 | 6 |
跳转至子程序, 记录该条指令最后的地址(即当前PC-1, 或者说JSR代码\$20所在地址+2), 影响FLAG: (无), 伪C代码:
--PC;
PUSH(PC >> 8);
PUSH(PC & 0xFF);
PC = address;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 隐含 | RTS | 60 | 1 | 6 |
JSR逆操作, 从子程序返回. 返回之前记录的位置+1(话说为什么不直接存+1的地址), 影响FLAG: (无), 伪C代码:
PC = POP();
PC |= POP() << 8;
++PC;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 隐含 | NOP | EA | 1 | 2 |
啥都不干, 居然两个周期, 太丢NOP的脸了, 褪裙吧.
助记符号: PUSH (PC+1); PUSH (P); I = 1; PC = IRQ;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 隐含 | BRK | 00 | 1 | 7 |
详细指令周期:
强制中断, 记录当前PC+1作为返回地址, 以及PS. 跳转到IRQ地址
由于大部分游戏都没有使用该指令, 所以有些模拟器的实现可能有些问题.
BRK虽然是单字节指令, 但是会让PC + 2, 所以干脆认为是双字节指令也不错.
影响FLAG: I(nterrupt), 伪C代码:
++PC;
PUSH(PC>>8);
PUSH(PC & 0xFF);
PUSH(P | FLAG_R | FLAG_B);
IF = 1;
PC = READ(IRQ);
PC |= READ(IRQ + 1) << 8;
| 寻址模式| 汇编格式| OP代码 |指令字节|指令周期|
|--------|-----------|----|---------|----------|
| 隐含 | RTI | 4D | 1 | 6 |
从中断返回, 影响FLAG: 是的, 伪C代码:
P = POP();
// 无视BIT4 BIT5
RF = 1;
BF = 0;
PC = POP();
PC |= POP() << 8;