Z80 кажется более сложным, чем 6502, но не слишком сложным. Во всяком случае, менее сложный, чем 8086 (примечание: в конце исходный код был длиннее моего ядра 8086, по крайней мере, если мы сравним javascript с Rust).
В любом случае, это сложно.
Мои предыдущие эмуляторы (кроме 8086, который я переписывал пару раз) имели большой оператор switch для выполнения опкодов. С Z80 это возможно, но такой подход приводит к большому количеству дублированного кода и подвержен ошибкам.
На этот раз я буду использовать массивы функций кода операции с основными чертами каждого кода операции (циклы, если он недокументирован и т. д.) и функцией, которая будет реализовывать код операции при вызове. Эти массивы также будут содержать декодированные инструкции для отладчика.
Через пару дней отладчик заработал, и ядро Z80 начинает выполнять инструкции:
Как вы можете заметить, невыполненные инструкции отображаются как «UNK». Я использую тестовую прошивку размером 32 КБ, поэтому пока нам не следует связываться с банковскими операциями и тому подобным. А, и на скриншоте видно фантастическое название, которое я придумал для этой программы: Zenga, эмулятор SMS.
Вы легко понимаете, с кем это связано.
(Хорошо, объяснение для не итальянца и не родившегося в 80-х: Вальтер Зенга был вратарем итальянской футбольной команды, и он сделал кучу телевизионных роликов для СМС и Мегадрайва — см., например, здесь — извините, это на итальянском)
К сожалению, эта часть кода самая скучная, так как приходится реализовывать все опкоды (речь идёт как минимум о сотнях опкодов, прежде чем вы увидите что-то осмысленное на экране). Хорошо, это 00.24. Давайте реализуем последний опкод дня (0x20, то есть jr NZ,d).