Понимание кодов операций в эмуляторе Z80 - PullRequest
0 голосов
/ 10 мая 2019

В настоящее время я работаю с эмулятором процессора Z80, для новичка я нашел пример со значениями, присвоенными памяти, чтобы показать «Hello World!».

1. 0x21, 0x0C, 0X00,// ld hl, 0008
2. 0x06, 0x0F, // ld b,0f
3. 0x7e, // ld a,(hl)
4. 0x23, // inc hl
5. 0xD3, 0x00, // out (00), a
6. 0x10, 0xFA, // djnz
7. 0x76, // halt
8. 0x48, 0x65, 0x6C, 0x6C, 0x6F, // Hello
9. 0x2D, 0x77, 0x6F, 0x72, 0x6C, //  Worl  
10. 0x64, 0x21, 0x20, 0x21//d! !  

У меня есть несколько вопросово значениях в памяти:

  1. В первой строке для команды 0x21 определяется инструкция LD HL,XX, поэтому в ассемблере будет LD HL,0CH, что это такое 0x00 делаешь там?Я думал, что LD HL,xx является 16-битной инструкцией, поэтому дополняет 0C восемью нулями, но я думаю, что это неправильно.

  2. В строке № 5, что такое OUT (00),A точно делает?В ходе некоторых исследований я обнаружил, что OUT передает данные с накопителя на выходной порт, но мне не совсем понятно, что конкретно происходит с этим 0x00.

Я быочень благодарен за любые подсказки или помощь с моими вопросами, заранее спасибо, что нашли время прочитать их.

1 Ответ

3 голосов
/ 12 мая 2019

Отвечая на ваши вопросы:

  1. 0x21 - это код операции для трехбайтовой инструкции LD HL, nn. Часть nn является 16-разрядным непосредственным операндом. В Z80 все 16-битные immedidates кодируются в порядке байтов с прямым порядком байтов, означая, что байт, который содержит младшие значащие биты (LSB), идет первым и сопровождается байтом, который содержит старшие значащие биты (MSB) значения , В вашем примере это байты 0x0c, 0x00. Таким образом, результирующее 16-битное значение равно 0x000c, а инструкция - ld hl, 0x000c, хотя в комментарии упоминается другое значение.

  2. out (n), a - это инструкция Z80, которая выводит значение регистра a в порт. Несмотря на то, что порты Z80 имеют 16-битные адреса (как и адреса памяти), операнд n, который указывает порт, является 8-битным непосредственным. Этот немедленный переход к младшему байту полного адреса порта, тогда как старший байт адреса является значением регистра a. Вот как это выглядит в моем эмуляторе:

    void on_out_n_a(fast_u8 n) {
        fast_u8 a = self().on_get_a();
        self().on_output_cycle(make16(a, n), a);
        self().on_set_wz(make16(a, inc8(n)));
    }

OUT (n), A

Что происходит на аппаратном уровне, процессор устанавливает свои сигнальные линии, такие как ~ IORQ, ~ RD, ~ WR и выводы адресной шины, в определенное состояние, чтобы периферийные устройства, подключенные к процессору, могли распознавать выходной сигнал. цикл и "посмотреть", какое значение и в какой порт записывается Более подробную информацию о том, что происходит во время цикла вывода, можно найти в руководстве пользователя Z80, раздел «Циклы ввода или вывода».

Z80 Руководство пользователя

Чтобы ваш эмулятор мог фактически выводить значения на периферийные устройства, вам необходимо, чтобы эти устройства, будь то действительные или эмулированные, были подтверждены на выходе и снабжены адресом порта и выходным значением, чтобы они могли вычислить если они должны реагировать и как конкретно они должны это делать. Например, в ZX Spectrum три младших бита выходного порта 0xfe (десятичный 254) определяют цвет границы экрана. Таким образом, эмулятор Spectrum будет перехватывать записи в этот порт, извлекать код цвета из значения и обновлять экран, чтобы показать границу нового цвета.

...