VM技术(二)从CHIP8入手CPU的模拟(二)

原创
2019/07/31 15:54
阅读数 161

CHIP指令表

CHIP-8有35个指令,都为两字节长,以大端方式存储。指令表的指令格式规定如下:

NNN 地址
NN 8位常量
N 4位常量
V 寄存器
X和Y 4位,标识寄存器
PC 程序计数器
I 16位索引地址寄存器
序号 操作码 类型 功能描述
1 0NNN 调用 执行地址NNN的子程序
2 00E0 显示 清屏
3 00EE 跳转 从子程序返回
4 1NNN 跳转 跳转到地址NNN
5 2NNN 跳转 调用子程序NNN
6 3XNN 条件 如果VX等于NN则跳过下一条指令(通常时跳过一条跳转指令)
7 4XNN 条件 如果VX不等于NN则跳过下一条指令(同上)
8 5XY0 条件 如果VX的值等于VY则跳过下一条指令(同上)
9 6XNN 赋值 VX = NN
10 7XNN 赋值 VX += NN,进位标记不会改变
11 8XY0 赋值 VX = VY
12 8XY1 按位或 VX = VX
13 8XY2 按位与 VX = VX & VY
14 8XY3 按位异或 VX = VX ^ VY
15 8XY4 运算 VX += VY,VX有进位(大于255)时VF为1,否则VF为0
16 8XY5 运算 VX -= VY,VX负数时VF为0,否则VF为1
17 8XY6 右移 VX >>= 1,VX最低位存入VF中
18 8XY7 运算 VX = VY - VX,VX负数时VF为0,否则VF为1
19 8XYE 左移 VX <<= 1,VX最高位存入VF中
20 9XY0 条件 如果VX不等于VY则跳过下一条指令(通常时跳过一条跳转指令)
21 ANNN 地址 将I设置为NNN
22 BNNN 跳转 跳转到地址V0+NNN,PC=V0+NNN
23 CXNN 随机数 VX = rand() & NN
24 DXYN 显示 在(VX,VY)绘制一个宽8像素、高N像素的精灵。每8个像素从I寄存器中的地址逐步读出一字节(8位),在执行该语句时I内的值不可以改变,如果像素反转为0则碰撞检测将VF置为1
25 EX9E 按键 跳过下一条指令,如果存储在VX的键值所应的键被按下
26 EXA1 按键 跳过下一条指令,如果存储在VX的键值所应的键没有被按下
27 FX07 定时器 获取延时寄存器的值
28 FX0A 按键 等待按键,将按键的值存入VX(阻塞指令,所有指令将等待该指令执行完
29 FX15 定时器 将VX的值存入延时寄存器
30 FX18 定时器 将VX的值存入声音寄存器
31 FX1E 地址 I += VX
32 FX29 地址 将VX中的精灵地址赋值给I,字符0-F由4X5字体表示
33 FX33 BCD 将VX中值的BCD码存入I中的地址内,百位在I,十位在I+1,个位在I+2
34 FX55 地址 将V0到VX的值存入I中地址为起始的内存空间
35 FX65 地址 将I中地址为起始的内容依次存入V0-VX

对每一个OPcode的实现

0NNN

//no action

00E0

    memset(gfx, 0, sizeof(gfx));
    drawFlag = true;
    pc += 2;

00EE

    pc = stack[--sp] + 2;

1NNN

    pc = opcode & 0x0FFF;

2NNN

    stack[sp++] = pc;
    pc = opcode & 0x0FFF;

3XNN

    pc += (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF)) ? 4 : 2;

4XNN

    pc += (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF)) ? 4 : 2;

5XY0

    pc += (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4]) ? 4 : 2;

6XNN

    V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
    pc += 2;

7XNN

    V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
    pc += 2;

8XY0

    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY1

    V[(opcode & 0x0F00) >> 8] |  = V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY2

    V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY3

    V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY4

    V[0xF] = V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode &0x0F00) >> 8]);
    V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY5

    V[0xF] = !(V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8]);
    V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
    pc += 2;

8XY6

    V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
    V[(opcode & 0x0F00) >> 8] >>= 1;
    pc += 2;

8XY7

    V[0xF] = !(V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]);
    V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
    pc += 2;

8XYE

    V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
    V[(opcode & 0x0F00) >> 8] <<= 1;
    pc += 2;

9XY0

    pc += (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4]) ? 4 : 2;

ANNN

    I = opcode & 0x0FFF;
    pc += 2;

BNNN

    pc = (opcode & 0x0FFF) + V[0];

CXNN

    V[(opcode & 0x0F00) >> 8] = (rand   % 0xFF) & (opcode & 0x00FF);
    pc += 2;

DXYN

    unsigned short x = V[(opcode & 0x0F00) >> 8];
    unsigned short y = V[(opcode & 0x00F0) >> 4];
    unsigned short height = opcode & 0x000F;
    unsigned short pixel = 0;
    V[0xF] = 0;
    for(int yline = 0; yline < height; ++yline) {
        pixel = memory[I+yline];
        for(int xline = 0; xline < 8; ++xline) {
            if((pixel & (0x80 >> xline)) != 0)
            {
                if(gfx[(x + xline + ((y + yline) * 64))] == 1)
                {
                    V[0xF] = 1;
                }
                gfx[x + xline + ((y + yline) * 64)] ^= 1;
            }
        }
    }
    drawFlag = true;
    pc += 2;

EX9E

    pc += (key[V[(opcode & 0x0F00) >> 8]]) ? 4 : 2;

EXA1

    pc += (key[V[(opcode & 0x0F00) >> 8]]) ? 2 : 4;

FX07

    V[(opcode & 0x0F00) >> 8] = delay_timer;
    pc += 2;

FX0A

    bool keyPress = false;

    for(int i = 0; i < 16; ++i)
    {
        if(key[i] != 0)
        {
            V[(opcode & 0x0F00) >> 8] = i;
            keyPress = true;
        }
    }

    if(!keyPress) {
        return;
    }
    pc += 2;

FX15

    delay_timer = V[(opcode & 0x0F00) >> 8];
    pc += 2;

FX18

    sound_timer = V[(opcode & 0x0F00) >> 8];
    pc += 2;

FX1E

    V[0xF] = (I + V[(opcode & 0x0F00) >> 8]) > 0xFFF;
    I += V[(opcode & 0x0F00) >> 8];
    pc += 2;

FX29

    I = V[(opcode & 0x0F00) >> 8] * 5;
    pc += 2;

FX33

    unsigned short vx = V[(opcode & 0x0F00) >> 8];
    memory[I] = vx / 100;
    memory[I+1] = vx / 10 % 10;
    memory[I+2] = vx % 10;
    pc += 2;

FX55

    unsigned short vx = V[(opcode & 0x0F00) >> 8];
    for(int i = 0; i <= vx; ++i) {
        memory[I+i] = V[i];
    }
    I += ((opcode & 0x0F00) >> 8) + 1;
    pc += 2;

FX65

    unsigned short vx = V[(opcode & 0x0F00) >> 8];
    for(int i = 0; i <= vx; ++i) {
        V[i] = memory[I+i];
    }
    I += ((opcode & 0x0F00) >> 8) + 1;
    pc += 2;
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部