В общем, для чего всё это нужно: есть почти полностью реализованный эмулятор CHIP8. Оперативная память у него состоит из ячеек, размером в 1 байт, и предоставляет диапазон адресов от 000h до FFFh. Я её объявил как:
unsigned char memory[0x1000];
Видеопамять же находится в той же оперативной памяти с некоторым смещением, и занимает диапазон от F00h до FFFh.
Если к оперативной памяти удобно обращаться как к одномерному массиву, то к видеопамяти удобнее обращаться как к двумерному массиву типа bool[][] (потому, что дисплей монохромный, и его пиксели имеют два состояния — "чёрный" и "белый").
Как правильно и безопасно получить указатель на двумерный массив [32][64] из указателя на одномерный? Одномерный же массив получить легко:
bool *videomem = (bool *)memory + 0xF00;
А вот двумерный массив уже не получается:
bool *video_mem[64] = (bool *[64])memory + 0xF00;
Можно, конечно, создавать для видеопамяти отдельный массив (и многие программы адекватно работают), но это снижает точность эмуляции (некоторые программы могут писать напрямую в видеопамять CHIP8).
Ответ
Попробуйте так:
unsigned char memory[0x1000];
const size_t video_mem_row_size = 64; // или 0x40, раз уж всё в hex
const size_t video_mem_offset = 0xF00;
typedef unsigned char video_mem_row[video_mem_row_size];
video_mem_row* video_mem = (video_mem_row*)(memory + video_mem_offset);
Проверка: http://ideone.com/mpflzb
Если у вас 64 — это размер в битах, и вы оперируете битами, вам, судя по всему, понадобится немного другой код.
unsigned char memory[0x1000] = {}; // обязательно инициализируйте!
const size_t bits_in_byte = 8;
const size_t video_mem_offset = 0xF00;
const size_t video_mem_row_bitsize = 0x40;
const size_t video_mem_row_stride =
(video_mem_row_bitsize + (bits_in_byte - 1)) / bits_in_byte;
typedef unsigned char video_mem_row[video_mem_row_stride];
video_mem_row* video_mem = (video_mem_row*)(memory + video_mem_offset);
const size_t video_mem_number_of_rows = 0x20;
bool get_video_bit(size_t row, size_t col)
{
if (row >= video_mem_number_of_rows || col >= video_mem_row_bitsize)
throw std::invalid_argument("index");
unsigned char* p = &video_mem[row][col / bits_in_byte];
unsigned char mask = ((unsigned char)1) << col % bits_in_byte;
return *p & mask;
}
void set_video_bit(size_t row, size_t col, bool value)
{
if (row >= video_mem_number_of_rows || col >= video_mem_row_bitsize)
throw std::invalid_argument("index");
unsigned char* p = &video_mem[row][col / bits_in_byte];
unsigned char mask = ((unsigned char)1) << col % bits_in_byte;
if (value)
*p |= mask;
else
*p &= ~mask;
}
Проверка: http://ideone.com/2BBcM1
Я бы посоветовал обернуть это в класс. Если хотите, можно написать индексаторы в духе std::vector
Комментариев нет:
Отправить комментарий