Насколько уместно использовать объединение для имитации регистров процессора в эмуляторе? - PullRequest
0 голосов
/ 27 октября 2018

Итак, я уже говорил, что использовать союзы таким образом - плохая идея.Я знаю, что это технически неопределенное поведение.Однако, если я использую C ++ 11 (и для этого только компиляторы новой версии), то честно насколько плохим может быть следующий код?Это действительно может взорвать меня?Можно ли его улучшить?

union registers_t
{
    struct [[packed]]
    {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        uint8_t F, A, C, B, E, D, L, H, R, I;
#else
        uint8_t A, F, B, C, D, E, H, L, I, R;
#endif
        uint16_t SP, PC;
    };
    struct [[packed]]
    {
        uint16_t AF, BC, DE, HL;
    };
};

Как я уже сказал, я знаю, что это UB в C ++, поэтому нет причин указывать на это.Мой вопрос имеет ли это значение в этом случае?

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Если я правильно понимаю, это только для эмулятора, поэтому вам не нужно, чтобы ваши 8- и 16-битные значения занимали одно и то же хранилище, вам просто нужен разный доступ к одним и тем же данным.

Мое предложение будет заключаться в инкапсуляции ваших регистров в класс (например, класс register_t, который хранит одно значение 16/32/64, к которому вы затем можете обращаться как 8/16/32 бит). В зависимости от ваших потребностей вы можете даже вернуть прокси-объект в качестве своего рода ссылки, которая позволяет вам назначить часть вашего регистра (например, чтобы иметь возможность reg.l() += 1).

Простой пример может выглядеть следующим образом: 16 бит register_t с прокси-ссылкой на составляющие байты (другие операторы, битовая ширина и const правильность оставлены в качестве упражнения для читателя). Еще одно преимущество такой работы (помимо того, что она не является UB) заключается в том, что вам не нужно заботиться о порядке байтов.

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

0 голосов
/ 27 октября 2018

Поведение не определено, если вы пишете члену объединения, а затем получаете доступ к тем же данным, что и другой член объединения, , если только один из типов не является типом символа .

Так что этот код вроде бы в порядке.Если вы попробовали то же самое с 32-битными регистрами (что было бы неправильно, если вы пытаетесь симулировать регистры x86, но это не вопрос), тогда запись в 16-битный элемент и чтение обратно в виде 32-битного элемента будет неопределенным поведением,

Кстати.memcpy, memset и memmove обращаются к данным в байтах.Официально.

...