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

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 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券