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

本文详细介绍了CHIP-8虚拟机的35个指令,包括调用子程序、跳转、条件判断、显示操作等,并提供了每个指令的具体实现代码,是理解和实现CHIP-8虚拟机的宝贵资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CHIP指令表

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

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

转载于:https://my.oschina.net/VenusV/blog/3081647

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值