Я хочу сначала предварить свой вопрос, сказав, что я довольно опытный программист, особенно с Java, который используется в течение 8 лет.
Чтобы улучшить свое понимание работы оборудования и операционной системы, я решил запрограммировать простой эмулятор Gameboy. Запрограммировав основные функции всего за несколько дней, я протестировал эмулятор и обнаружил, что на экране ничего не рисуется. Пройдя несколько сотен кодов операций в моем эмуляторе по одному и сравнив его со значениями, найденными в эмуляторе BGB, я понял, что рассматриваемые тайлы и спрайты загружались в память, а не рисовались. Из этого я понял, что проблема должна быть в одной или нескольких реализациях моего кода операции, из-за чего программа в какой-то момент демонстрирует неправильное поведение. Из-за этого я решил использовать тестовые ромы процессора Blargg (http://gbdev.gg8.se/files/roms/blargg-gb-tests/), чтобы помочь мне выявить проблему. Однако при запуске первого тестового диска выдается следующее сообщение об ошибке:
01-special
36E1FE30
DAA
Failed #6
Я несколько раз проверял работу DAA, и мне кажется, что она правильно реализована. Приведенный код ошибки («36E1FE30») совершенно бесполезен, поскольку я не могу понять, что это значит. Для меня это означает, что либо DAA реализован неправильно, и я просто не вижу своей ошибки, либо одна из операций, используемых для проверки правильности DAA, неверна. Если я запускаю какие-либо другие тесты, они зацикливаются на неопределенный срок.
03-op sp,hl
03-op sp,hl
03-op sp,hl
03-op sp,hl
Для справки, моя реализация DAA находится на github (https://github.com/qkmaxware/GBemu/blob/master/src/gameboy/cpu/Opcodes.java) или можно увидеть ниже следующим образом:
Op DAA = new Op(0x27, "DAA", map, () -> {
int a = reg.a();
if(!reg.subtract()){
if(reg.halfcarry() || (a & 0xF) > 9)
a += 0x06;
if(reg.carry() || a > 0x9F)
a += 0x60;
}else{
if(reg.halfcarry())
a = (a - 0x6) & 0xFF;
if(reg.carry())
a = (a - 0x60) & 0xFF;
}
reg.a(a);
reg.zero(isZero(a));
reg.carry((a & 0x100) == 0x100);
reg.halfcarry(false);
clock.m(1);
clock.t(4);
});
Там, где такие вызовы, как reg.a(), означают чтение из регистра a, reg.a(value) означает запись в регистр a (маскируется до 8 или 16 бит в зависимости от регистра). Точно так же флаги Z,N,H,C можно получить или установить/сбросить с помощью функций нуля, вычитания, половинного переноса и переноса объекта 'reg'.
Итак, мой вопрос состоит из трех частей: неправильно ли я реализовал операцию DAA, чтобы она не прошла тесты Бларгга, знает ли кто-нибудь, что означает код ошибки, который у меня есть, или у кого-нибудь есть идеи, как я могу сосредоточить свой поиск на неправильной операции.