Пока проистекает нудное причёсывание листинга дизассемблера, переосмысливание некоторых моментов и написания руководства я решил подбрасывать дровишек в эту "топку", чтоб не завяла тема и чтоб люди не скучали. Поэтому потихоньку буду выкладывать заметочки, которые пишу для себя при исследовании ПЗУ. Итак! Заметка намберван. "Переменные, переменные!"
Что будет, если сразу после загрузки компьютера напечатать:
PRINT ABC
Компьютер ответит:
0
Оk
Вот так вот просто, незатейливо. Это, конечно, может породить кучу проблем. Но с другой стороны, это довольно-таки удобно. Теперь наберём:
LET ABC=123
PRINT ABC
123
Ok
Очевидные вещи! Но, что здесь происходит? Что такое это ABC, и где она хранится? Разберёмся по порядку.
Переменные с точки зрения Бейсика могут быть двух видов - числовые и строковые. По адресу ENBASPRG находится системная переменная, которая указывает на конец Бейсик программы. Вот тут то и начинается область переменных. После включения компьютера эта область начинается с адреса &h4003. По адресу BGARRAY располагается системная переменная, которая хранит адрес начала области массивов (с массивами разберёмся позднее). А вот по адресу VAR_TOP находится системная переменная, которая хранит адрес конца области переменных. Таким образом, все наши переменные располагаются в области начинающейся с ENBASPRG и заканчивающейся на VAR_TOP. Под каждую переменную отводится 6 байт. Рассмотрим форматы переменных:
<Имя (2 байта)> <Данные (4 байта)>
1. Числовые переменные.
Два байта - определяют имя переменной. Формируются следующим образом. Из имени переменной берётся два первых символа и меняются местами. Таким образом для нашей переменной ABC эти два байта будут выглядеть как BA. Отсюда следует неутешительный вывод - имя переменной может состоят из скольки угодно букв, но значимыми будут только первые две! Т. е. переменные ABC и ABD для Бейсика - абсолютно одно и то-же. Исключение составляют строковые переменные (AB и AB$ - разные вещи).
Четыре байта - собственно число в формате BCDEINMEM.
2. Строковые переменные.
Два байта - также определяют имя переменной и формируются по тем же правилам, что и для числовых переменных. Единственное - после преобразований в первом байте определяющем имя переменной старший бит устанавливается в 1. Это и говорит о том, что переменная строковая!
Два байта - Длина строки. Сначала идёт младший байт, потом старший.
Два байта - адрес, по которому собственно и располагается строка. Адрес этот должен лежать в области с BGSTRAR по ENSTRAR. Строки в памяти располагаются от старших адресов к младшим. Видимо с целью какой-то там оптимизации. Соответственно, как и у длинны - младший байт адреса первый, за ним старший байт адреса.
Имея эту информацию уже довольно-таки несложно написать парсер переменных. Хранение же переменных получается довольно компактным.
Рассмотрим теперь ситуацию, когда надобно создать переменную из машинного кода и затем использовать её где-нибудь, например в печати оператором Бейсика PRINT.
Вот код, создающий новую (или работающий со старой, если есть) переменную:
Ну вот! Программа наподобие:Код:ORG 0x5000-0x26 DB 0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74 DB 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0 DB 'tstprg' DB 0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74 DW START, ENDE, START START: lxi h, name; грузим в HL адрес имени переменной call 0x0b1a; GETVAR push de; тут в DE - адрес содержимого вновь созданной переменной lxi h, numb; грузим в HL адрес нашего числа call 0x13c6; FIN - переводим строку с числом в FACCUM pop hl; теперь адрес содержимого нашей переменной в HL call 0x1319; FCOPYTOMEM - копируем FACCUM в память по адресу в HL ret numb db "1.234E2" db 0x0 name db "AB" db 0x0 ENDE: END
Выдаст следующее:Код:10 X=USR$(&H5000) 20 PRINT AB
123.4




Speccy-2010 R1, R2
Ответить с цитированием