1

目前我正在开发 NES 模拟器,并且正在开发 CPU 内核。我在互联网上搜索过,但我找不到正确的关键字找到我的问题的答案,所以我想我会在这里问它。我有七个布尔值,它们充当我的处理器状态标志。我正在处理的当前操作码希望我将处理器状态标志推送到堆栈。我的堆栈是 unsigned char 数据类型。我以为我可以像这样将布尔值粉碎在一起:

bool C, Z, I, D, B, V, N;
unsigned char example;

example = {C, Z, I, D, B, V, N, 0};

那没有用,那么我该如何将所有布尔处理器状态标志放入 unsigned char 数据类型,以便我可以将标志推送到我的堆栈中?

4

6 回答 6

3
enum { C=0x01, Z=0x02, I=0x04, D=0x08,
       B=0x10, V=0x20, N=0x40 };
unsigned char flags = 0;

这是有效的,因为在每个常量中只设置了一位。要确定标志是否已设置,请使用(flags & FLAGNAME)like(flags & C)确定是否已设置。注意不要让我使用的按位与 (&) 与布尔/逻辑与 (&&) 混淆。&& 运算符不能代替 & 运算符。要设置标志,请使用(flags |= FLAGNAME);要取消设置,请使用flags &= ~FLAGNAME;. 将常量调整为正确的顺序,以便 NES 指令可以正确检查标志。毕竟,如果它们的顺序不正确,可能会使用错误的标志值,这显然是个问题。

另外,不要忘记括号。位运算符的优先级很低,因此表达式周围的括号是必不可少的。

如果您不了解按位运算符,则值得一读。

编辑

一组方便的宏:

#define FLAG_ISSET(x) (flags & (x))
#define FLAG_SET(x) (flags |= (x))
#define FLAG_CLEAR(x) (flags &= ~(x))

...
if (FLAG_ISSET(C))
  ...

FLAG_SET(V);
FLAG_CLEAR(Z);
于 2013-07-03T07:58:31.040 回答
2

试试std::bitsethttp://en.cppreference.com/w/cpp/utility/bitset我找不到使用初始化列表构造它的方法,但是您始终可以使用operator[]orset()设置每个位,并使用to_ulong()将其转换为数字(然后您可以轻松地将 unsigned long 转换为 unsigned char)。

#include <stdio.h>
#include <bitset>
using namespace std;

int main()
{
   bitset<7> reg;
   bool C = true, Z = false, I = false, D = false, B = true, V = true, N = false;

   reg[6] = C;
   reg[5] = Z;
   reg[4] = I;
   reg[3] = D;
   reg[2] = B;
   reg[1] = V;
   reg[0] = N;

   unsigned char example = static_cast<unsigned char>(reg.to_ulong());
   printf("0x%x\n", example);
   return 0;
}
于 2013-07-03T07:27:33.473 回答
1

放入模拟器可能有点繁重,但为什么不将每个布尔值转换为字符中的位,然后在需要将字符从堆栈中拉出时解码字符。

unsigned char encodeBits(bool bools[8]) {
    unsigned char retval = 0;
    for(int i = 0; i < 8; i++) {
        retval += (bools[i] ? 1 : 0);
        retval = (i < 7 ? retval << 1 : retval);
    }

    return retval;
}

这段代码基本上只是将布尔值转换为一个字符。

然后解码,通过引用传递一个空数组,

void decodeBits(bool (&bools)[8], unsigned char input) {
    for(int i = 0; i < 8; i++) {
        bools[i] = (input & 0x00000001 ? true : false);
        input = (i < 7 ? input >> 1 : input);
    }
}

此代码应比较字符的第一位,然后将其移位等等。

这可以在没有数组的情况下完成,但为了简单起见,我使用了数组。

编辑:一个工作示例:http: //ideone.com/hQ47nn

于 2013-07-03T07:42:50.583 回答
1

尝试这个:

bool C, Z, I, D, B, V, N;
unsigned char example = 0;

if(C)
   example |= (1 << 7)
if(Z)
   example |= (1 << 6)
if(I)
   example |= (1 << 5)
if(D)
   example |= (1 << 4)
if(B)
   example |= (1 << 3)
if(V)
   example |= (1 << 2)
if(N)
   example |= (1 << 1)
于 2013-07-03T07:27:59.817 回答
1

假设int status是您的 CPU 状态寄存器。您可以创建一些像这样的定义:

#define CPU_REG_STATUS_C 0x00000040
#define CPU_REG_STATUS_Z 0x00000020
#define CPU_REG_STATUS_I 0x00000010
#define CPU_REG_STATUS_D 0x00000008
#define CPU_REG_STATUS_B 0x00000004
#define CPU_REG_STATUS_V 0x00000002
#define CPU_REG_STATUS_N 0x00000001

然后使用按位二元运算符 & 和 | 相互独立地设置/取消设置标志

示例 1:设置零标志

status |= CPU_REG_STATUS_Z;

示例 2:检查零标志的值:

if(status & CPU_REG_STATUS_Z)
{
   //zero flag is set
}
else
{
   //zero flag is unset
}

然而,那里有大量的 CPU 核心源代码,特别是对于 6502 CPU(Commodore C64、Nintendo NES 和许多其他 CPU),因此您只需关心控制台的仿真即可。

http://www.6502.org/tools/emu/

于 2013-07-03T07:56:47.903 回答
0

这应该是您正在寻找的:

bool C, Z, I, D, B, V, N;
unsigned char example = 0;
const unsigned char mask = 0x01;

if(N)
   example |= mask << 1;
if(V)
   example |= mask << 2;
//...   
if(C)
   example |= mask << 7;
于 2013-07-03T07:29:16.393 回答