2013-07-03 2 views
1

В настоящее время я работаю над эмулятором NES, и я работаю над ядром процессора. Я искал по всему Интернету, но я не могу найти правильные ключевые слова, чтобы найти ответ на мой вопрос, поэтому я подумал, что попрошу его здесь. У меня есть семь булевых элементов, которые действуют как флаги статуса процессора. Текущий код операции, над которым я работаю, хочет, чтобы я ввел флаги состояния процессора в стек. Мой стек имеет тип данных unsigned char. Я думал, что я мог бы разбить булевы вместе, как это:Ввод mutiple булевых в символ без знака?

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

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

Это не сработало, так как я могу идти о вводе всех моих логических флагов состояния процессора в неподписанные символ типа данных, так что я могу нажать флаги в мой стек?

+5

Рассматривали ли вы с помощью битовых полей в некотором роде? – Bathsheba

ответ

2

Пробег: std::bitset. http://en.cppreference.com/w/cpp/utility/bitset Я не мог найти способ построить его с помощью списков инициализаторов, но вы всегда можете использовать operator[] или set() для установки каждого бита и использовать 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; 
} 
+0

Я дал эту попытку, и со всеми настройками boolean я получаю 97 в качестве вывода, когда мне нужно получить 127. –

+0

Тогда вы, вероятно, сделали что-то не так. Я запускал эту программу со всеми переменными, установленными в true, а выход был равен 0x7f, что равно 127 (с компилятором g ++ 4.7.2). – petersohn

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) 
+0

Это то, что я собираюсь использовать, я думаю. Я не могу поверить, что сам не думал об этом. –

+0

По какой-то причине это не работает. Я тестирую это в отдельной программе с примером cout << (int) << endl; и выход - какой бы ни был последний бит, который был включен. Например, если установлен N, то выход равен 1. Если задано только C, то выход равен 128. –

+0

имеет смысл. байт (или битовая маска) 10000000 (равный только C установлен) совпадает с десятичным значением 128. –

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; 
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); 
    } 
} 

Этот код должен сравнить первый бит символа, а затем перенести его и т.д. и т.п.

Это может быть сделано без массивов но для простоты я использовал массивы.

Edit: рабочий пример: http://ideone.com/hQ47nn

+0

Это отлично работает. Выходной массив выходит в обратном порядке для меня, но это не проблема. Спасибо! –

+0

Есть способы обойти эту обратную проблему, но если она работает в обратном направлении, нет необходимости накладывать дополнительные накладные расходы, изменяя порядок массива. –

1

Допустим int status ваш регистр состояния процессора. Вы можете создать некоторые предопределенные подобные этим:

#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 

, а затем установить/снять флаги indipendently друг от друга с помощью побитового бинарные операторы & и |

example1: установка ZERO флаг

status |= CPU_REG_STATUS_Z; 

example2: проверка значения ZERO флага:

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

однако, существует множество процессорных ядер исходных кодов там, особенно для 6502 (Commodore C64, Nintendo NES и многие другие), поэтому вам нужно беспокоиться только с эмуляцией консоли.

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

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

Это работает, потому что только один бит установлен в каждой константе. Чтобы определить, установлен ли флаг, используйте (flags & FLAGNAME), например (flags & C), чтобы определить, установлен ли он. Будьте осторожны, чтобы не получить побитового AND (&), который я использовал в путанице с логическим логическим И (& &). Оператор & & не будет работать вместо оператора &. Чтобы установить флаг, используйте (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); 
+2

За исключением того, что в C++ это должны быть встроенные функции (возможно, с двумя параметрами). –

+0

Возможно, хотя лично я предпочел бы макросы в этом случае. Знаки CPU постоянно изменяются, поэтому я бы предположил, что регистр флагов и связанные с ним значения являются глобальными, если они не находятся в классе. В любом случае необходимо только один параметр функции. Встроенная функция будет иметь преимущество проверки типов, но не должно быть причин для проверки типов, поскольку в любом случае необходимо использовать константы флага. –

Смежные вопросы