Сборка Z80 (1 МГц) CP/M: Как получить правильный физический ввод с помощью кнопок

Я новичок, изучающий информатику. В области компьютерной инженерии мы работаем над 8-битным микропроцессором Zilog Z80 (1 МГц) и набором компонентов, которые необходимо подключать вручную с помощью макета и кабелей.

Соединительная часть меня не беспокоит, но у меня есть вопросы, касающиеся программы сборки, которую мне нужно написать, чтобы заставить мою программу работать (светодиодный индикатор, с ручным вводом для поведения и частоты).

Я уже прочитал руководство и знаю набор инструкций, которые можно использовать (только самое необходимое). Для начала, я не пытаюсь получить самый чистый, самый красивый код; но не волнуйтесь, я сделаю это позже, так как мне нравится чистый и эффективный код.

На данный момент программа, кажется, хорошо работает в симуляторе, поэтому синтаксис, кажется, в порядке. Тем не менее, я не уверен, как прогрессировать с определенными логическими проблемами.

Упражнение имеет следующие характеристики:

  1. Начальный адрес RAM: E000h
  2. Входной порт 1: 03ч
  3. Выходной порт 1: 05h
  4. Отображение ввода / вывода для портов
  5. Цепи автоматически разомкнуты (1), поэтому светодиоды НИЗКО активны (0)
  6. Вход 2,3,4 изменяет поведение движения светодиодов
  7. Вход 5,6 изменяет частоту мигания светодиода

Я установил начальный адрес с помощью ORG E000h и инициализировал указатель стека, используя MOV SP,FFFFh, Для входа (три разных типа мигания / бега, а также две разные частоты, всего пять кнопок) я создал разные метки.

Моя проблема на данный момент заключается в том, что я не совсем уверен, как правильно настроить физический ввод - IIRC, мне нужно указать битовую комбинацию, используя XOR, где все равно 1, но желаемый вход, чтобы я мог использовать информацию в моей программе.

Но даже хотя я знаю, как это должно работать (по крайней мере, я думаю, что знаю), я не могу полностью обдумать реализацию программного обеспечения. Кроме того, у меня есть проблемы с условиями: нажатие одного переключателя изменяет частоту мигания на 1/4 Гц, а нажатие другого переключает на 4 Гц. На языках более высокого уровня я бы просто использовал IF/ELSE здесь, но я не знаю, как это сделать в этом случае - к сожалению, руководство включает только основные операции, поэтому я в растерянности.

Поэтому я решил попытать счастья и попросить сообщество помочь.

Для интересующихся выложу свой код. Как я уже упоминал, это очень просто, но мне просто нужно, чтобы работа была выполнена на данный момент. Поскольку я не фанат огромных кусков неуклюже отформатированного кода, я разместил файл здесь. Файл представляет собой *.txt, размещенный через GoogleDrive.

Спасибо за ваше время и хорошего дня!

[РЕДАКТИРОВАТЬ] добавил конкретный код в пост, в соответствии с введением пользователя Ruud Helderman

[РЕДАКТИРОВАТЬ] обновленный код в *.txt-файле - теперь проще и эффективнее

[EDIT] использовал HTML-форматирование, чтобы выделить директивы в посте

Фрагмент конкретного кода:

blink:       ;function: all LED blinking, activated via input[2]
MOV A,FFh
OUT 05h,A     ;all LED out
CALL pause1   ;frequency 1/4Hz, activated via input[5]
MOV A,00h
OUT 05h,A     ;all LED on
CALL pause1
JP blink      ;jump back to begin of function

Вышеуказанная функция изменяет поведение светодиода (в данном случае: мигание), а также частоту, используя различные конкретные физические переключатели на плате входных переключателей с общим количеством переключателей восемь (от 1 до 8, состояние неактивности = 1; используются переключатели от 2 до 6). Я знаю, что получение ввода должно быть простым делом - это просто вопрос использования XOR с битовой комбинацией 0 и ровно 1.

Пытаясь найти решение для моей проблемы, я наткнулся на различные подходы в Интернете, такие как использование TEST проверить биты в определенных местах. Тем не менее, в моей инструкции по эксплуатации нет упоминаний о таких директивах, и само назначение не упоминает об этом.

Я вполне осознаю, что это, вероятно, тривиальный вопрос, и, возможно, я просто застрял в ментальном цикле, который я создал, задумавшись, но в настоящий момент я не знаю, как добраться до того места, где я должен быть (хотя Я вижу замок на горизонте - спасибо, Кафка!).

Любая помощь с благодарностью.

2 ответа

Решение

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

Как я и предполагал, проблема была в том, что я застрял в заблуждении, которое, к счастью, было исправлено моим партнером по лаборатории. Итак, в конце концов, мы смогли заставить нашу программу работать - в последнюю минуту и ​​не на все 100%, но она работала и отвечала требованиям.

Так в чем было мое заблуждение? Достаточно забавно, я знал, куда мы должны были пойти, и идея была правильной. Проблема заключалась в том, что я пропустил большую часть логической операции - я уже рассчитал ее в своей голове, а затем объединил фактическое рабочее решение с устаревшей AND который разрушил функциональность.

В общем, правильная комбинация XOR а также AND было следующим:

programloop:
MOV A,40h       ;state of button 2, inverted (XOR FFh)
MOV B,A         ;save state to register B
IN A,03h        ;input at port-address 03h
AND B           ;find out if button is pressed
JPNZ blink      ;if yes, jump to blink

MOV A,20h       ;state of button 3, inverted (XOR FFh)
MOV B,A         ;save state to register B
IN A,03h        ;input at port-address 03h
AND B           ;find out if button is pressed
JPNZ goright    ;if yes, jump to goright

MOV A,10h       ;state of button 4, inverted (XOR FFh)
MOV B,A         ;save state to register B
IN A,03h        ;input at port-address 03h
AND B           ;find out if button is pressed
JPNZ goleft     ;if yes, jump to goleft
JP programloop  ;go back to beginning (input has to be checked constantly)

Это помогло с тремя кнопками, которые изменили поведение светодиодов.

Что касается частоты, нам пришлось снизить сложность только до двух состояний из-за жестких временных ограничений (мы неправильно прочитали задание и ошибочно начали с вопроса о бонусе, который стоил нам около 50% времени на разработку - да, у нас. Урок: всегда начните читать сверху и читайте внимательно.)

Но так как смена частоты сработала, оказалось, что все в порядке.

MOV A,03h       ;state of button five being pressed (inverted)
MOV B,A         ;saved state into register B for later use
IN A,03h        ;physical input over button
AND B           ;find out if button is pressed
JPNZ freq025Hz  ;if yes, jump to freq025Hz
JPZ freq4Hz     ;if no, jump to freq4Hz

Вот и все!

Еще раз спасибо всем за помощь.

Если остались какие-либо вопросы, не стесняйтесь задавать!

Перво-наперво: если вы используете MOV тогда вы, вероятно, используете синтаксис 8080 вместо синтаксиса Z80. По историческим правовым причинам Z80 не только расширяет язык ассемблера 8080, но и переименовывает всю существующую мнемонику (MOV в LD, например). Если вы ищете код Z80 и находите незнакомые инструкции, это, вероятно, будет частью этого.

Обычный способ реализации условных выражений if / else:

  1. выполнить любую операцию, которая устанавливает флаг состояния соответствующим образом; а также
  2. используйте один из условных переходов, чтобы пропустить некоторый код или нет, в зависимости от флага состояния.

В вашем случае вы хотите что-то делать или не делать что-то в зависимости от того, установлен ли бит, поэтому один из способов сделать это ANI (Z80: AND). Это вычисляет логическое значение и аккумулятора и операнда, сохраняя его в аккумуляторе, но среди прочего оно также устанавливает нулевой флаг. Так что вы можете использовать JNZ (/JP NZ) а также JZ (/JP Z) делать что-то или нет в зависимости от того, установлен ли бит. Например

; upon entry, A has an unknown value, loaded from somewhere.

ANI 08h    ; Set a = a & 8; so either bit 2 was originally set and a now
           ; has the value 8, or bit 2 wasn't set and a now has the value 0.

           ; Also: the zero flag is now set if a is zero, reset otherwise.

           ; So you've loaded NOT (a.bit2) into the zero flag.

           ; You've also lost the rest of the accumulator, but such is life.
           ; Keep a copy somewhere, or grab it again via IN as required.

JZ bitnotset

; code here will be performed only if bit 2 was originally unset.

bitnotset:

; this code will happen regardless of whether bit 2 was set.

Я не знаю о TEST в синтаксисе в стиле 8080 или Z80.

Вы также можете увидеть менее разрушительное и немного более эффективное решение для последовательного тестирования нескольких битов в байте путем их смещения в бит переноса. Это еще один вариант, но его не обязательно беспокоить, если в примечаниях к курсу не указано, в каком направлении вам следует искать.

Другие вопросы по тегам