Итак, мне удалось дойти до этого момента, и эмулятор начинает писать в неправильную область PPU, что конечно же портит всё выполнение.

С цветами я ещё не разобрался, так что стоит всего одна палитра на весь экран. Сейчас самое главное найти баг и в этой статье я опишу как его искал, но прежде хочу объяснить как я распределил память.
    uint8_t ctrl[0x100];
    uint8_t stack[0x300];
    uint8_t ram[RAM_MAX];
    uint8_t oam[0x800];
    uint8_t ppu[0x10000];
    uint8_t mem[0x8000];
    uint8_t chr[0x2000];Как видно здесь много избыточного места, особенно для ppu. Всё дело в том, что мой эмулятор записывал в разные отличные от 0x2000-0x4000 области памяти и я поначалу думал, что всё нормально, хотя ясно же сказано было в документации, что у ppu для видео за экран отвечает область памяти от 0x2000 до 0x4000. Но этот баг я нашел за часов 6. Всё дело в неправильном понимании документации. У меня бывает с этим проблемы, я не так понимаю сказанное, а тут ещё и на английском.
Вот что было в документации.
operand is zeropage address; effective address is word in (LL, LL + 1) incremented by Y with carry: C.w($00LL) + Y
И вот carry я расценивал как CARRY FLAG, и добавлял единицу, если флаг был таков. Эта проблема стоила всех предыдущих дней, но мне нравилось искать в чем же баг, а такой баг очень сложно было искать. Вроде бы читает, пишет по адресу, но в чём дело? Почему не отображается экран?
Ладно, его я нашел. Теперь нужно найти ещё один подобный баг. Теперь, когда мы доходим до этого экрана, то эмулятор пытается записать в ppu по адресу 0x0908 байт 0xa0. Также выводиться отладочный код с регистрами перед завершением программы.
write to ppu 0908 = a0
	exit debug: A: a0 X: 03 Y: 03 P: c5 S: 01f4 PC: c8cb;Наученный на этих багах, я решил найти сначала откуда читает байты и что показывает нам эмулятор fceux, но как на fceux выйти на нужный байт считывания, если функции могут запускаться в цикле и ошибка может возникать на 200 цикле.
Я открыл radare и перешел по этому смещению.
b100           lda (0x00),yПеред тем как сохраниться в PPU_DATA, он считывает из адреса какое-то значение, в моём случае оно 0xa0. Я решил вывести дамп памяти перед падением и посмотреть что там находиться.

Очень странно, но у нас Y равно 0x03, а по смещению 0x03 нет ничего, но есть по смещению нулевому. LDA имеет 0xb1 опкод, смотрим в моем файле op_name.h и ищем опкод.

Пока всё совпадает, может я ошибся в коде, нужно глянуть.

Это пока ни о чём не говорит, надо смотреть макрос и сам indirect_y, вдруг там что-то.

Здесь два места на что стоит обратить внимание. get_addr это наш indirect_y, а read_from_address это уже читаем байт из памяти. Сначала исследуем indirect_y.

Кода мало, надо убедиться, и вроде бы всё хорошо, я решил проверить какой адрес выдает здесь и написал printf.
Извиняюсь за введение в заблуждение! Оказывается дамп памяти я приводил из другой области, не из ram. Вот что в ram находится.

Как мы видим, по нулевому адресу есть адрес 0x0591 + 0x03, который даёт нам по всей видимости неправильные данные. Посмотрим что там.
Нашел байты. По адресам 0x591 и 0x592 видимо наш адрес в PPU, который должен записаться.

Что же делать, распыляться? У нас есть две позиции в дампе, которые можно проверить. По всей видимости, что весьма вероятно, что 0xa0 байт правильный, а вот 0x908 надо проверить. Я поставил выход с дампом, если запись по адресу 0x591 будет иметь 0x09, посмотрим откуда это.
Отловил. Оказалось, что он берёт с zeropage по смещению 0x01, но мне кажется, что надо точно проверить всё ли я правильно прописал в функциях, поэтому для начала, перед тем как исследовать дальше, решил пройтись по всем функциям и убедиться, что названия функций указаны верно.

Я нашел места, где не было добавлена проверка на то, куда записываются данные, в область ram или в область кода. Я боялся, что сейчас ещё больше набагую код, но надо было везде всё исправить.
Исправил, но баг остался. Всё-таки где-то что-то не так, возможно я где-то сделал неправильную команду сложения, ведь у меня нет тестов :).
Когда он записывает 09 в область памяти, то мы видим, что до этого он читает байт из адреса 0x01, что ж, пойдём по следу бага.
a501           lda 0x01Я поставил выход из программы, когда произведется запись по смещени 0x01 со значением 0x09.
Я нашел место в коде и видимо оно вызывается, когда начинается игра компьютера, нужно остледить что регистры все верны, поэтому я поставил breakpoint в fceux и тоже самое сделал в своем эмуляторе.
Я увидел интересную картину. Была запись такая.
lda #$00
ldx 00
sta ($74), xИ вместо того, чтобы sta записывать ноль, она записывала X, это случилось, потому что в коде стоял cpu->X.

Наконец-то я его нашел. Поиск был интересным и увлекательным. Я чувствовал, что я иду по следу и всё равно найду этот баг. Вот результат на видео того что получилось.
На этом статья закончена, впереди ещё много свершений. Нужно сделать цвета фона по тайлам, также сделать анимацию в самой игре, так как на видео видно, что персонажи стоят на месте.
Комментарии (2)
 - FirstEgo28.01.2025 14:10- Статья замечательная. Правда, когда я стал её читать, у меня появилось стойкое ощущение, что я сел на движущийся поезд... 
 
           
 
bodyawm
Вы - молодец