Сборка Z80 (1 МГц) CP/M: Как получить правильный физический ввод с помощью кнопок
Я новичок, изучающий информатику. В области компьютерной инженерии мы работаем над 8-битным микропроцессором Zilog Z80 (1 МГц) и набором компонентов, которые необходимо подключать вручную с помощью макета и кабелей.
Соединительная часть меня не беспокоит, но у меня есть вопросы, касающиеся программы сборки, которую мне нужно написать, чтобы заставить мою программу работать (светодиодный индикатор, с ручным вводом для поведения и частоты).
Я уже прочитал руководство и знаю набор инструкций, которые можно использовать (только самое необходимое). Для начала, я не пытаюсь получить самый чистый, самый красивый код; но не волнуйтесь, я сделаю это позже, так как мне нравится чистый и эффективный код.
На данный момент программа, кажется, хорошо работает в симуляторе, поэтому синтаксис, кажется, в порядке. Тем не менее, я не уверен, как прогрессировать с определенными логическими проблемами.
Упражнение имеет следующие характеристики:
- Начальный адрес RAM: E000h
- Входной порт 1: 03ч
- Выходной порт 1: 05h
- Отображение ввода / вывода для портов
- Цепи автоматически разомкнуты (1), поэтому светодиоды НИЗКО активны (0)
- Вход 2,3,4 изменяет поведение движения светодиодов
- Вход 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:
- выполнить любую операцию, которая устанавливает флаг состояния соответствующим образом; а также
- используйте один из условных переходов, чтобы пропустить некоторый код или нет, в зависимости от флага состояния.
В вашем случае вы хотите что-то делать или не делать что-то в зависимости от того, установлен ли бит, поэтому один из способов сделать это 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.
Вы также можете увидеть менее разрушительное и немного более эффективное решение для последовательного тестирования нескольких битов в байте путем их смещения в бит переноса. Это еще один вариант, но его не обязательно беспокоить, если в примечаниях к курсу не указано, в каком направлении вам следует искать.