#эмулятор #массивы #указатели #cpp
В общем, для чего всё это нужно: есть почти полностью реализованный эмулятор 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).
Ответы
Ответ 1
Попробуйте так: 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.
Комментариев нет:
Отправить комментарий