Список системных вызовов
В этом посте:
- Описание понятия системного вызова
- Таблица системных вызовов СМ-1800
Что такое системные вызовы?
У компьютера, помимо процессора и памяти, есть переферийные устройства. Эти устройства могут выполнять разные задачи – например, выводить текст на экран, считывать нажатия клавиатуры, записывать и считывать информацию на диске и т.д.
Для взаимодействия с внешними устройствами у Intel 8080 есть инструкции IN и OUT.
Они позволяют передавать значения по одному байту между процессором и внешним устройством.
Но в компьютере, чаще всего, устройства имеют сложные протоколы взаимодействия – например, для чтения с диска может быть нужно отправить команду на чтение, затем отправить адрес, затем дождаться ответа и наконец получить данные. В дополнение к этому, у компьютера как правило набор переферийных устройств не меняется.
Из-за этого производитель компьютера записывает в ПЗУ несколько подпрограмм, которые выполняют часто используемые задачи – например, “вывести строку текста по этому адресу на экран” или “ждать, пока не будет нажата клавиша на клавиатуре”.
Эти подпрограммы называются системными вызовами, потому что они являются частью системы и их можно вызывать инструкцией CALL.
Это название я использую по аналогии с системными вызовами в современных операционных системах, хотя в современных ОС они имеют очень другой механизм работы. Можно также провести аналогию с вызовами-прерываниями BIOS, но они также имеют другой механизм работы.
Для целей этой серии статей мы будем называть системным вызовом процедуры, которые находятся в ПЗУ (эмулятора) СМ-1800 и позволяют управлять внешним оборудованием.
Некоторые системные вызовы принимают аргументы, а некоторые возвращают значения. Для этого пользовательский код загружает в регистры процессора аргументы, вызывает системный вызов, а затем может считать возвращаемое значение из регистров.
Пример получения возвращаемого значения:
; Сейчас регистр A имеет неизвестное значение...
CALL 0x0055 ; Вызываем подпрограмму для считывания символа с клавиатуры
; Сейчас регистр A имеет значение -- код символа, который был нажат на клавиатуре
; Используем это значение...
Пример передачи аргумента:
; Сейчас регистр A имеет неизвестное значение...
MVI A, 0x55 ; Записываем в регистр A значение 0x55
CALL 0x0061 ; Вызываем подпрограмму для вывода значения регистра A в шестнадцатиричном формате в консоль
; Теперь в консоли написано "55"
Замечание по поводу названий системных вызовов
Названия системных вызовов для СМ-1800 придуманы мной – они могут не соответствовать каким-то другим источникам. Это является основной причиной, по которой я начал писать эту серию статей – я не смог найти никакой документации про это, и поэтому для удобства объяснения я придумал свои названия для этих системных вызовов.
Эти названия используются в этих статьях для обозначения системных вызовов, а также в include-файле, содержащем метки для этих процедур (todo). Добавьте этот файл в ваш assembly-код, чтобы использовать эти названия в вашем коде.
Согласно официальной спецификации ассемблера Intel 8080, метки ассемблера могут быть длиной не больше 5 символов. Такое ограничение иногда присутствовало в старых ассемблерах. Для поддержки таких ассемблеров предоставляются два варианта названий для системных вызовов: более длинные, которые лучше описывают процедуру, и более короткие, соответствующие ограничениям этих старых ассемблеров. В тексте и примерах кода будут использоваться более длинные названия.
Замечание по поводу уверенности
Поскольку вся эта информация получена не из официальной документации, а из изучения эмулятора СМ-1800, некоторая из нее может быть не полностью примерно верной. Например, системные вызовы могут иметь поведение, отличающееся от ожидаемого.
Чтобы узнать более подробно, что именно делает конкретный системный вызов, нужно их изучать: либо проверять их поведение, либо изучать их исходный код из дизассемблированного образа ПЗУ. Только используя оба подхода можно быть уверенным в том, что именно делает конкретный системный вызов.
Уверенность помечается одним из следующих символов:
- про подпрограмму ничего не известно, или описание взято из внешнего источника: 🤔
- исходный код подпрограммы прочитан: 👀
- подпрограмма была опробована на практике и ее поведение соответствует описанию: 🛠
- подпрограмма была прочитана и опробована: 🔬
Таблица системных вызовов
Версия таблицы: 0.0 (2022-03-07)
Проверяйте версию своего include-файла прежде чем использовать эти названия!
| Адрес | Название | Простое название | Категория | Входные аргументы | Выходные аргументы | Описание | Уверенность |
|---|---|---|---|---|---|---|---|
0x003D |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0040 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0043 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0046 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0049 |
printNewLine |
PNL |
??? | ∅ | ∅ | Переводит курсор на новую строку | 🛠 |
0x004C |
printStr |
PSTR |
??? | BC |
∅ | Выводит строку по адресу | 🛠 |
0x004F |
printStrNL |
PSNL |
??? | BC |
∅ | Выводит строку по адресу и переводит курсор на новую строку | 🛠 |
0x0052 |
??? | ??? | ??? | ??? | ??? | ||
0x0055 |
inputChar |
IKCHR |
??? | ??? | A |
Ожидает ввода символа с клавиатуры и возвращает его | 🛠 |
0x0058 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x005B |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x005E |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0061 |
printHex |
PAXX |
??? | A |
∅ | Выводит аргумент на экран как шестнадцатиричное число | 🛠 |
0x0064 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0067 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x006A |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x006D |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0070 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0073 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0076 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0079 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x007C |
??? | ??? | ??? | ??? | ??? | Устанавливает A в 0 |
👀 |
0x007E/0x007F |
??? | ??? | ??? | ??? | ??? | Устанавливает A в 0 |
👀 |
0x0081/0x0082 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0085 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0088 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x008B |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x008E |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0091 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0094 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
0x0097 |
??? | ??? | ??? | ??? | ??? | ??? | 🤔 |
Описание системных вызовов
printNewLine
Эта подпрограмма переводит курсор на новую строку.
Это полезно для разделения между собой нескольких элементов вывода на экран.
printStr
Эта подпрограмма принимает в комбинированном регистре BC адрес в памяти.
Строка, располагающаяся по этому адресу, выводится на экран.
Строка – это последовательность байтов, в конце которой находится байт 0x00.
Рассмотрим этот сегмент памяти:
| Адрес | Значение | Смысл в ASCII |
|---|---|---|
0x5000 |
0x48 |
H |
0x5001 |
0x65 |
e |
0x5002 |
0x6C |
l |
0x5003 |
0x6C |
l |
0x5004 |
0x6F |
o |
0x5005 |
0x20 |
` ` |
0x5006 |
0x77 |
w |
0x5007 |
0x6F |
o |
0x5008 |
0x72 |
r |
0x5009 |
0x6C |
l |
0x500A |
0x64 |
d |
0x500B |
0x00 |
|
0x500C |
0x4F |
O |
0x500D |
0x4B |
K |
0x500E |
0x00 |
|
0x500F |
0x43 |
C |
0x5010 |
0x61 |
a |
0x5011 |
0x6E |
n |
0x5012 |
0x63 |
c |
0x5013 |
0x65 |
e |
0x5014 |
0x6C |
l |
0x5015 |
0x00 |
Здесь есть три строки: одна начинается по адресу 0x5000 и значит Hello world, одна начинается по 0x500C и значит OK, и одна начинается по 0x500F и значит Cancel.
Каждая из этих строк заканчивается байтом, равным 0x00 – он не считается частью строки и не выводится на экран.
Можно использовать части строк, у которых изменена позиция начала.
Например, если начать читать с адреса 0x5003, то прочитается (и будет выведена) строка lo world.
printStrNL
Эта подпрограмма делает то же, что и printStr.
После вывода строки, курсор переводится на новую строку.
inputChar
Эта подпрограмма останавливает выполнение программы до тех пор, пока на клавиатуре не будет введен символ с клавиатуры.
После этого код введенного символа помещается в регистр A.
Символ также отображается на экране.
printHex
Эта подпрограмма выводит на экран два символа – шестнадцатиричное значение регистра A.
Если вам помогла эта статья, вы можете поддержать автора: