Инструменты пользователя

Инструменты сайта


msx:basic_programming_guide:10

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

msx:basic_programming_guide:10 [2020-04-23 14:10]
msx:basic_programming_guide:10 [2022-09-09 23:28]
Строка 1: Строка 1:
-[<>] 
-~~TOC wide~~ 
  
-====== Глава X. Управление ресурсами памяти ====== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Мозг, хорошо устроенный,​ стоит больше,​ чем мозг, хорошо наполненный. 
-<WRAP rightalign>​ 
-—//​Мишель Монтень//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-===== X.1. Карта памяти (для компьютеров MSX 1) ===== 
- 
-Персональный MSX–компьютер имеет небольшой объем памяти — 96 Кбайт для [[msx:​msx_1]] и 242 Кбайта для [[msx:​msx_2]]. Поэтому полезной для пользователя оказывается информация о распределении ресурсов памяти и сведения о наличии и 
-объёме в ней свободных мест в любой момент времени. 
- 
-Общий объем памяти у компьютеров серии [[msx:​msx_1]] равен 96 Кбайт. Здесь и далее мы будем рассматривать только 64 Кбайта,​ с которыми обычно и работает основная масса пользователей. 
- 
-Взгляните на приведённый ниже [[#​pict_1|рис. 1]]… 
- 
-Вся память разбита на две основные части: 
-  * ROM ("Read Only Memory"​ — "​Постоянное Запоминающее Устройство"​) и 
-  * RAM ("​Random Access Memory"​ — "​Оперативное Запоминающее Устройство"​) 
- 
-ROM содержит те программы и данные,​ которые "​заложены"​ в компьютер при изготовлении. Вот почему он всегда выводит определённые сообщения при включении и способен "​понимать"​ программу на языке [[msx:​basic:​]]. 
- 
-В ROM находится //​интерпретатор//​ — программа на машинном языке, которая переводит один за другим операторы языка [[msx:​basic:​]] в программу на машинном языке, т.е. на //​единственном//​ языке, который понимает компьютер. С помощью этой программы компьютер проверяет синтаксис,​ выводит при необходимости сообщение об ошибке,​ переходит к следующему оператору или возвращается в командный режим и так далее. 
- 
-Здесь же находятся подпрограммы управления клавиатурой и экраном,​ которые составляют //​экранный редактор//​ [[msx:​basic:​]]. 
- 
-ROM в основном разделена на две части: 
-  - подпрограммы BIOS ("​Basic Input–Output System"​);​ 
-  - другие подпрограммы. Так, например,​ при включении компьютера наступает небольшая пауза; в этот момент происходят различные инициализации экрана дисплея (установка определённого режима ''​SCREEN'',​ установка ширины экрана ''​WIDTH''​ и др.). Это происходит оттого,​что "​зашитые"​ в ROM подпрограммы инициализации "​посылают"​ определённую информацию в рабочую область RAM, разговор о которой ещё пойдёт впереди. 
- 
-Подпрограммы BIOS осуществляют переход к другим подпрограммам. Они напоминают последовательность операторов ''​GOSUB'',​ которую можно увидеть на первом уровне хорошо структурированной программы на [[msx:​basic:​]]. Подпрограммы BIOS расположены по одним и тем же адресам ROM независимо от версии [[msx:​basic:​]] и осуществляют переход к другим подпрограммам, ​ положение которых может быть изменено. 
- 
-В противоположность ROM, RAM не сохраняет информацию при выключении компьютера. Поговорим теперь о его структуре. 
- 
-"​Верхушка"​ памяти (она изображена в //​нижней//​ части таблицы) занята //​рабочей областью//,​ которая состоит из: 
-  * таблицы системных переменных,​ 
-  * таблицы ловушек ("​Hooks Table"​). 
-"​Нижняя"​ область памяти (она изображена в //​верхней//​ части таблицы) занята:​ 
-  - текстом программы ("​Program Instruction Table",​ PIT); 
-  - таблицей переменных ("​Variable Table",​ VT). VT содержит все переменные,​ создаваемые в ходе выполнения программы;​ 
-  - таблицей массивов ("​Array Variable Table"​). 
- 
-Между "​верхней"​ и "​нижней"​ областью памяти располагаются:​ 
-  * свободная область ("Free Area"​);​ 
-  * //​стек//​ ("​Stack Area"​);​ стек содержит всю информацию,​ необходимую для выполнения программы. Например,​ именно здесь хранится адрес тех байт PIT, которые содержат сведения о следующем выполняемом операторе Вашей программы;​ 
-  * //​строковая//​ область ("​Character String Area"​);​ по умолчанию для неё отводится 200 байт, однако размеры этой области можно менять оператором ''​CLEAR''​ (см. [[#X.7. Оператор CLEAR|раздел X.7.]]); 
-  * //блок управления//​ файлами ("​Files Control Block"​). 
- 
-Если в Вашей программе присутствует оператор ''​MAXFILES=''​ (напомним,​ что он задаёт максимальное количество одновременно открытых файлов),​ то для каждого файла автоматически резервируется 267–байтное пространство для 
-осуществления обмена информацией с файловыми устройствами. 
- 
-{{anchor:​pict_1}} 
-<​code>​ 
-   &​H0000 ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 
-          ∗▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧∗ 
-          ∗▧▧▧▧▧▧▧▧▧ ​ ROM (Интерпретатор MSX BASIC) ▧▧▧▧▧▧▧∗ 
-          ∗▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧∗ 
-   ─ ─ ─ ─∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗─ ─ ─ ─ 
-   &​H8000 │                                                │ TXTTAB 
-          │            Программа на языке BASIC            │   │ 
-          │        ("​Program Instruction Table",​ PIT)      │   ▼ 
-          │                                                │ 
-          │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │─ ─ ─ ─ 
-          │                                                │ VARTAB 
-          │      Простые переменные ("​Variable Table"​) ​    ​│ ​  │ 
-          │                                                │   ▼ 
-          │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │─ ─ ─ ─ 
-          │        Массивы ("​Array Variable Table"​) ​       │ ARYTAB 
-          │                                                │   │ 
-          │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │   ▼ 
-          │                                                │ 
-          │        Свободная ​ область ("Free Area"​) ​       │ 
-          │                                                │ 
-RAM       ​│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ 
-          │                                                │   ▲ 
-          │               ​Стек ("​Stack Area"​) ​             │   │ 
-          │                                                │ STKTOP 
-          │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤─ ─ ─ ─ 
-          │                                                │   ▲ 
-          │   ​Строковая область ("​Character String Area"​) ​ │   │ 
-          │                                                │ FRETOP 
-          │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤─ ─ ─ ─ 
-          │                                                │ FILTAB 
-          │ Блок управления файлами ("​Files Control Block"​)│ ​  │ 
-          │                                                │   ▼ 
-  ─ ─ ─ ─ ┼────────────────────────────────────────────────│─ ─ ─ ─ 
-   &​HF380 │          Таблица системных переменных ​         │ HIMEM 
-          │           ​("​System Variable Table"​) ​           │   │ 
-  ─ ─ ─ ─ │─ ─ ─ ─ ─ - - - - - - - - - - - - - - - - ─ ─ ─ │   ▼ 
-   &​HF3A9 │                                                │ 
-          │         ​Таблица ловушек ("​Hooks Table"​) ​       │ 
-   &​HFFFF │                                                │ 
-  ─ ─ ─ ─ └────────────────────────────────────────────────┘ 
-</​code>​ __//Рис. 1//__ 
- 
-Приведённая карта памяти справедлива и для компьютеров серии [[msx:​msx_2]]. Но в отличие от компьютеров серии [[msx:​msx_1]] с объёмом ROM в 32 Кбайта и RAM в 64 Кбайта,​ компьютеры серии [[msx:​msx_2]] имеют гораздо больший объем памяти (108 Кбайт ROM и 134 Кбайта RAM). Спрашивается,​ где размещаются эта память?​ 
- 
-<WRAP centeralign>​Оказывается,​ вся память ПЭВМ разбита на блоки объёмом по 64 Кбайта,​ называемые //​слотами//​ !</​WRAP>​ 
- 
-Однако рассмотрение этого вопроса потребует от читателя дополнительных знаний,​ и поэтому мы рассмотрим его позднее (см. [[#XI.1.9. Слоты видеопамяти|раздел XI.1.9.]]). 
- 
-Память разделена на ячейки (//​байты//​),​ каждая из которых имеет адрес, закодированный //​двумя//​ байтами:​ 
-<​code>​ 
-         ​Адрес ячейки (байта) 
-┌─────────────────┬─────────────────┐ 
-│ 1 1 0 1 1 0 1 1 │ 1 0 1 1 1 1 0 1 │ 
-└────────▲────────┴────────▲────────┘ 
-         ​└── ​   Байты ​   ──┘ 
-</​code>​ 
- 
-Поэтому максимально большой адрес байта равен 
-  256·&​B11111111+&​B11111111+1 = 256·&​hFF+&​HFF+1 = 65535+1 = 65536 , 
-а следовательно,​ и обратиться можно не более, чем к 65536 ячейкам памяти (подумайте,​ почему производится умножение именно на 256?). 
- 
-Говорят,​ что "​объём непосредственно адресуемой памяти — 65536 байта"​. 
- 
-===== X.2. Функция PEEK и оператор POKE ===== 
- 
-{{anchor:​peek}} 
-Функция ''​PEEK''​ позволяет Вам "​посмотреть"​ содержимое любой ячейки памяти в адресном пространстве MSX–компьютера. 
-Её общий вид: 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-PEEK (адрес) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​PEEK''​ ("to peek" — "​заглядывать"​) — служебное слово; 
-  * адрес — арифметическое выражение,​ значение которого находится в диапазоне от &h0 до &hFFFF. 
-Функция ''​PEEK''​ возвращает целое число в интервале от 0 до 255, содержащееся в проверяемой ячейке памяти. 
- 
-Например:​ 
-  - <​code>​ 
-10 WIDTH 7:? PEEK(&​HF3B0) 
-run 
- 7 
-Ok 
-</​code>​ 
-  - <​code>​ 
-10 SCREEN 2:​PSET(15,​18):​SCREEN0:​PRINT PEEK(&​HFCB3);​PEEK(&​HFCB5) 
-run 
- ​15 ​ 18 
-Ok 
-</​code>​ 
-В первом примере мы "​попросили"​ компьютер вывести на экран содержимое ячейки с адресом &HF3B0 (в байте по этому адресу хранится значение систем ной переменной — длины дисплейной строки). Во втором примере мы использовали информацию из таблицы адресов системных переменных (см. Приложение 2((Пока не найдено,​ подробнее [[start#​Список отсутствующего материала|здесь]])) ). 
- 
-Величину,​ возвращаемую функцией ''​PEEK'',​ можно интерпретировать как код символа,​ команду [[msx:​basic:​]],​ номер строки,​ число, "​часть"​ числа, "​хранящегося"​ в нескольких байтах,​ и т.д. В некоторых случаях правильную интерпретацию можно дать по контексту,​ однако,​ если должной уверенности нет, надо //​анализировать//​ не только содержимое одной ячейки,​ но и содержимое ячеек, находящихся в её "​окрестности"​! 
- 
-{{anchor:​e102-01}} __//​Пример 1//__. \\ {{.examples:​102-01.bas|}} \\ [[+tab|wmsxbpge>​102-01.bas]] 
-<​code>​ 
-10 X=&​H8000'"​Заглянем"​ в память,​начиная с адреса &H8001! 
-20 X=X+1:​Y=PEEK(X) 
-30 IF Y<32 THEN ?"​│";:​GOTO 20 ELSE ?​CHR$(Y);"​ ";:​GOTO20 
-</​code>​ 
-Наличие условия Y<32 в строке 26 связано с тем, что существуют "​непечатаемые"​ символы,​ имеющие код ASCII, меньший 32. 
- 
-{{anchor:​poke}} 
-Поговорим теперь об очень полезном операторе ''​POKE''​. 
-Общий вид оператора:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-POKE A, D 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * POKE ("to poke" — "​помещать"​) — служебное слово; 
-  * A — арифметическое выражение,​ значение которого находится в диапазоне от &h8000 до &hFFFF; 
-  * D — арифметическое выражение,​ значение которого принадлежит отрезку [0,255] (поскольку оно должно умещаться в один байт). 
- 
-Оператор ''​POKE''​ вычисляет значения выражений А и D и сохраняет значение D (которое должно помещаться в одном байте!) по адресу А. Обратите внимание на то, что значение А может оказаться //​отрицательным//​! 
- 
-Если значение А не удовлетворяет ограничениям,​ то компьютер сообщит об ошибке: ​ 
-<WRAP centeralign>"​Overflow"​ (//"​Переполнение"//​),​ а если значение D, то \\ "​Illegal function call" \\ (//"​Неправильный вызов функции"//​).</​WRAP>​ 
- 
-Вы можете использовать оператор ''​POKE''​ для: 
-  * модификации текста Вашей программы;​ 
-  * изменения значений переменных;​ 
-  * размещения в RAM программы,​ написанной на машинном языке (её запись производится //​побайтно//​). 
-Более того, этот оператор позволяет Вам экспериментировать с "​подвалом"​ компьютера (рабочей областью). Но делайте так только в том случае,​ если Вы понимаете,​ что за этим последует! 
- 
-{{anchor:​e102-02}} __//​Пример 2//__. Сравните результаты работы двух программ:​ 
-<WRAP group> 
-<WRAP half column> 
-{{.examples:​102-021.bas|}} \\ [[+tab|wmsxbpge>​102-021.bas]]<​code>​ 
-10 SCREEN 1:​PRINT"​A"​ 
-20 WIDTH 10 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-{{.examples:​102-021.bas|}} \\ [[+tab|wmsxbpge>​102-021.bas]]<​code>​ 
-10 SCREEN 1:​PRINT"​A"​ 
-20 POKE &​HF3B0,​10 
-</​code>​ 
-</​WRAP>​ 
-</​WRAP>​ 
- 
-===== X.3. Таблица программных команд (PIT) ===== 
- 
-Таблица PIT обычно начинается по адресу &H8000. Однако её можно "​сдвинуть",​ изменив значение системной переменной TXTTAB в таблице системных переменных. 
- 
-{{anchor:​e103-01}} __//​Пример 1//__. Для помещения PIT с адреса &​HА000,​достаточно выполнить следующую программу:​ \\ {{.examples:​103-01.bas|}} \\ [[+tab|wmsxbpge>​103-01.bas]] 
-<​code>​ 
-NEW 
-Ok 
-5 '​Адрес &​HА001,​находящийся в двух ячейках с номерами,​ начиная с &hF676 (слове TXTTAB (&​HF676)),​ 
-6 '​определяет место,​с которого начнется текст программы 
-10 POKE &​HF676,&​H01 ​ '​Заполнение младшего байта слова TXTTAB 
-20 POKE &​HF677,&​HA0 ​ '​Заполнение старшего байта слова TXTTAB 
-30 POKE &​HA000,​0 ​    '​Первый байт PIT(&​HA000) должен быть нулевым! 
-40 NEW               '​Стираем данную программу! 
-</​code>​ 
- 
-Напомним Вам, что адрес &HА001 (как и любой другой!) размещается в двух байтах так: 
-<​code>​ 
-    Адрес ​  ​──▶ ​  &​HF676 ​   &​HF677 ​ ◀── ​  ​Адрес 
-младшего байта ​     │         ​│ ​      ​старшего байта 
-              ┌─────│─────────│────┐ 
-Содержимое ​   │ ┌───▼──┐ ​ ┌───▼──┐ │     ​Содержимое 
- ​младшего ​ ◀───── &Н01 │  │ &HА0 ─────▶ ​  ​старшего 
-  байта ​      │ └──────┘ ​ └──────┘ │       ​байта 
-              └────────────────────┘ 
-                   ​Слово TXTTAB 
-</​code>​ 
- 
-Очевидно,​ что в результате этих "​манипуляций"​ размер свободной области уменьшится на &H2000 байт (&​HA000-&​H8000=&​H2000),​ и область,​ расположенная между &H8000 и началом PIT, будет защищена от "​вторжения"​ программ на [[msx:​basic:​]],​ и следовательно,​ //"​безопасна"//​ для программ на машинном языке. 
- 
-Ясно, что величина PIT зависит от размера текста программы. 
- 
-После выполнения данной программы нажмите кнопку сброса <​key>​RESET</​key>​. 
- 
-А теперь мы расскажем Вам о том, как хранится программа,​ написанная на языке [[msx:​basic:​]] в PIT. 
- 
-Все строки программы на [[msx:​basic:​]] начинаются с //​двухбайтового//​ указателя. За этим указателем идут //два// байта, содержащие номер строки. Затем идёт текст строки с последующим нулевым байтом. 
- 
-За последней строкой следуют //два// дополнительных нулевых байта адрес которых находится в указателе последней строки программы. 
- 
-Цифры и зарезервированные служебные слова записываются во внутреннем коде (один или два байта на слово, цифру) 
- 
-Для остального текста используется код ASCII. 
- 
-__//​Пример 2//__. Введём в память следующую короткую программу:​ 
-<​code>​ 
-10 B=5 
-20 END 
-</​code>​ 
- 
-Теперь прочитаем,​ что же реально содержится в PIT, используя в непосредственном режиме команду 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-PRINT HEX$(PEEK(A)) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где значение переменной А (адреса) изменяется от &H8000 до &H8010. 
- 
-Вы обнаружите:​ 
-^  Значение А  ^  HEX$(PEEK(A)) ​ ^  Комментарии ​ ^ 
-|  8000  |  0  |Первый байт PIT всегда нулевой| 
-|  8001  |  09  |Указатель первой строки "​говорит"​ нам, что указатель следующей строки находится по адресу &​Н8009| 
-|  8002  |  80  |:::| 
-|  8003  |  А  |Номер первой строки &H000А = 10| 
-|  8004  |  0  |:::| 
-|  8005  |  42  |Шестнадцатеричный код ASCII буквы "​B"​| 
-|  8006  |  EF  |Внутренний код знака равенства| 
-|  8007  |  16  |Внутренний код цифры 5| 
-|  8008  |  0  |Конец первой строки| 
-|  8009  |  0F  |Указатель второй строки показывает,​ что указатель следующей строки находится по адресу &H800F| 
-|  800A  |  80  |:::| 
-|  800B  |  14  |Номер второй строки &H0014 = 20| 
-|  800C  |  00  |:::| 
-|  800D  |  81  |Внутренний код оператора ''​END''​| 
-|  800E  |  0  |Конец второй строки| 
-|  800F  |  0  |Конец программы| 
-|  8010  |  0  |:::| 
- 
-Теперь,​ надеемся,​ Вам стало ясно, как можно изменить программу с помощью оператора ''​POKE''​. 
- 
-Попробуйте выполнить следующее:​ 
-<​code>​ 
-POKE &​H8005,&​H41 ​  '​41 - шестнадцатеричный код ASCII буквы "​A"​ 
-POKE &​H8007,&​H17 ​  '​17 - внутренний код цифры "​6"​ 
-</​code>​ 
-А теперь наберите команду ''​LIST'',​ затем нажмите клавишу <​key>'​Ввод '​⏎</​key>​ и … : 
-<​code>​ 
-10 A=6 
-20 END 
-</​code>​ 
- 
-__//​Пример 3//__. 
- 
-Теперь Вам ясно, что "​инструкции"​ ''​PEEK''​ и ''​POKE''​ таят в себе поистине безграничные возможности. По существу,​ они позволяют нам распоряжаться памятью компьютера по своему усмотрению. 
- 
-Например,​ они позволяют нам при желании подшутить над компьютером:​ если известно,​ где хранится программа,​ то мы можем сделать так, что после одной из строк программы окажется строка с //​меньшим//​ номером. 
- 
-Пусть исходная программа имеет вид: 
-<​code>​ 
-10 PRINT 4 
-20 PRINT 2 
-</​code>​ 
- 
-Вам, конечно,​ уже известно,​ что строки программы на языке [[msx:​basic:​]] начинаются с двухбайтового указателя,​ за которым следуют два байта, содержащие номер строки. Поэтому вначале выполним команду:​ 
-<​code>​ 
-PRINT HEX$(PEEK(&​H8002));"​ ";​HEX$(PEEK(&​H8001)) 
-80 9 
-Ok 
-</​code>​ 
- 
-Таким образом,​ указатель следующей (с номером 20) строки располагается в ячейках с адресами &H8009 и &H800A, а следовательно,​ номер второй строки находится в ячейках с адресами &H800B и &H800C . 
-Проверим этот факт: 
-<​code>​ 
-PRINT HEX$(PEEK(&​H800C));"​ ";​HEX$(PEEK(&​H800B)) ​    ​┌──▶ ​ PRINT &H14 
-0 14    ────────────────────────────────────────────┘ ​     20 
-Ok                                                        Ok 
- 
-А теперь:​ 
-POKE &​H800B,​1 
-Ok 
-list 
-10 PRINT 4 
-1 PRINT 2 
-Ok 
-</​code>​ 
- 
-Программа действует,​ но строку с номером 1 нельзя ни стереть,​ ни исправить. Вы можете написать ещё одну 1–ю строку и даже новую 20–ю строку! 
- 
-{{anchor:​e103-04}} __//​Пример 4//__. \\ Введём в память короткую программу:​ 
-\\ {{.examples:​103-04.bas|}} \\ [[+tab|wmsxbpge>​103-04.bas]] 
-<​code>​ 
-10 FOR AB=-2.23227 TO 7 STEP 32.671533782376#​ 
-</​code>​ 
-Теперь "​просмотрим"​ содержимое ​ PIT, используя в непосредственном режиме простейшие команды:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-A=&​H8000:​ PRINT HEX$(PEEK(A)) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где значение переменной А (адреса) изменяется от &H8000 до &H8020. 
- 
-Мы обнаружим массу интересных вещей: 
-^  Значение А  ^  HEX$(PEEK(A)) ​ ^  Комментарии ​ ^ 
-|  8000  |  0  |Первый байт PIT всегда нулевой| 
-|  8001  |  21  |Указатель первой строки "​говорит"​ нам, что указатель следующей строки находится по адресу &​Н8021| 
-|  8002  |  80  |:::| 
-|  8003  |  А  |Номер первой строки &H000А = 10| 
-|  8004  |  0  |:::| 
-|  8005  |  82  |Код служебного слова ''​FOR''​| 
-|  8006  |  20  |Внутренний код символа "​пробел"​| 
-|  8007  |  41  |Шестнадцатеричный код ASCII буквы "​A"​| 
-|  8008  |  42  |Шестнадцатеричный код ASCII буквы "​B"​| 
-|  8009  |  EF  |Внутренний код символа "​="​| 
-|  800A  |  F2  |Внутренний код символа "​-"​| 
-|  800B  |  1D  |Указатель на тип одинарной точности (знак"​!"​)| 
-|  800C  |  41  |Вторая цифра числа указывает на порядок минимального значения параметра цикла| 
-|  800D  |  22  |1 и 2–я цифры мантиссы минимального значения параметра цикла| 
-|  800E  |  32  |3 и 4–я цифры мантиссы минимального значения параметра цикла| 
-|  800F  |  27  |5 и 6–я цифры мантиссы минимального значения параметра цикла| 
-|  8010  |  20  |Внутренний код символа "​пробел"​| 
-|  8011  |  D9  |Код служебного слова ''​TO''​| 
-|  8012  |  20  |Внутренний код символа "​пробел"​| 
-|  8013  |  18  |Внутренний код символа "​7"​| 
-|  8014  |  20  |Внутренний код символа "​пробел"​| 
-|  8015  |  DC  |Код служебного слова ''​STEP''​| 
-|  8016  |  20  |Внутренний код символа "​пробел"​| 
-|  8017  |  1F  |Указатель на тип двойная точность (знак #)| 
-|  8018  |  42  |Вторая цифра числа указывает на порядок шага| 
-|  8019  |  32  |1 и 2–я цифры мантиссы шага| 
-|  801А  |  67  |3 и 4–я цифры мантиссы шага| 
-|  801B  |  15  |5 и 6–я цифры мантиссы шага| 
-|  801C  |  33  |7 и 8–я цифры мантиссы шага| 
-|  801D  |  78  |9 и 10–я цифры мантиссы шага| 
-|  801E  |  23  |11 и 12–я цифры мантиссы шага| 
-|  801F  |  76  |13 и 14–я цифры мантиссы шага| 
-|  8020  |  0  |Конец строки| 
-|  8021  |  0  |Конец программы| 
- 
-Однако не пытайтесь изменять с помощью оператора ''​POKE''​ длину строки или путать указатели:​ результат будет //​катастрофическим//​! 
- 
-Если Вы хотите защитить свою программу от "​постороннего взгляда"​ (команды ''​LIST''​),​ то примените в непосредственном режиме команду:​ 
-<​code>​ 
-POKE &​H8001,​1 
-Ok 
-</​code>​ 
-(разумеется,​ Ваша программа должна располагаться с адреса &​H8000). 
- 
-Ну а если Вы нечаянно нажали <​key>​RESET</​key>,​ — не спешите отчаиваться! Вашу программу ещё можно спасти. Это очень легко сделать,​ набрав ту же команду 
-<​code>​ 
-POKE &​H8001,​1 
- 
-а затем 
-auto 
- 
-На экране появятся строки:​ 
-10* 
-20* 
-и так далее … 
-</​code>​ 
-Строки с "​*"​ — спасённые. Теперь достаточно "​скомандовать":​ ''​LIST''​ и …, о, чудо! Но это ещё не все! Оказывается,​ спасены и все строки между теми, номера которых не делятся нацело на 10! 
- 
-Если же Вы захотите защитить свою программу от запуска (команды ''​RUN''​),​ то примените в непосредственном режиме команду:​ 
-<​code>​ 
-POKE &​H8000,​1 
-Ok 
-</​code>​ 
-(разумеется,​ Ваша программа должна располагаться с адреса &​H8000). 
- 
-===== X.4. Таблица переменных (VT) ===== 
- 
-Непосредственно следующая за PIT таблица VT начинается с адреса,​ указанного в слове ''​VARTAB'',​ хранящегося по адресу &HF6C2 в области системных переменных (см. Приложение 2((Пока не найдено,​ подробнее [[start#​Список отсутствующего материала|здесь]]))). Её длина зависит от количества используемых переменных (скалярных и массивов) и их типов. 
- 
-Отметим,​ что переменные и массивы хранятся в порядке их создания. 
- 
-Будем говорить,​ что один программный объект "​располагается в памяти //​выше//​ другого",​ если адрес, с которого он расположен,​ больше. 
- 
-<WRAP centeralign>​Массивы хранятся //​выше//​ переменных.</​WRAP>​ 
- 
-Это значит,​ что всякий раз, когда интерпретатор встречает новую скалярную переменную,​ все массивы сдвигаются //"​вверх"//,​ чтобы высвободить пространство. Это может значительно замедлить выполнение программы! 
- 
-<WRAP centeralign>​Во избежание этого, описывайте все скалярные переменные и массивы в начале программы оператором ''​DIM''​ !</​WRAP>​ 
- 
-{{anchor:​varptr}} 
-Теперь мы расскажем Вам о важной функции ''​VARPTR'',​ которая указывает адрес расположения данных в оперативной памяти. Её синтаксис:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-VARPTR(γ) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​VARPTR''​ ("​VARiable PoinTeR"​ — "​указатель переменной"​) — служебное слово; 
-  * γ — идентификатор //​числовой//​ переменной. 
-Функция ''​VARPTR''​ возвращает //​адрес//​ X байта RAM, начиная с которого располагается значение переменной γ. 
- 
-Если переменная не существует,​ то выдаётся сообщение:​ <WRAP centeralign>"​Illegal function call"​.</​WRAP>​ 
- 
-{{anchor:​e104-01}} __//​Пример//​__. Будьте бдительны! \\ {{.examples:​104-01.bas|}} \\ [[+tab|wmsxbpge>​104-01.bas]] 
-<​code>​ 
-10 INPUT Z 
-20 PRINT VARPTR(Z) 
-run 
-? 0 
--32743 
-Ok 
- 
-run 
-?         ​◀── Нажата клавиша "​RETURN"​ 
-Illegal function call in 20 
-Ok 
-</​code>​ 
- 
-Функцию ''​VARPTR''​ часто используют совместно с функцией ''​PEEK''​ и оператором ''​POKE''​ соответственно для просмотра или изменения значения переменной. 
- 
-==== X.4.1. Хранение простых переменных ==== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Ты славно роешь землю, старый крот! \\ 
-Годишься в рудокопы. 
-<WRAP rightalign>​ 
-—//​В.Шекспир. Гамлет//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-Как уже неоднократно упоминалось,​ //​целое//​ число кодируется в двух байтах. Меньший по адресу байт называется //​старшим//,​ больший по адресу байт — //​младшим//​. 
- 
-Однако,​ напомним Вам, что <WRAP centeralign>​процессор Z80 "​хранит"​ младший байт "​перед"​ старшим.</​WRAP>​ 
- 
-Когда //​целочисленная//​ переменная получает значение,​ процессор записывает в оперативную память следующие //​пять//​ байт информации:​ 
-  - число 2 ("​паспорт"​ ''​VALTYPE''​),​ которое означает,​ что переменная является целочисленной (значение "​паспорта"​ занимает два байта);​ 
-  - код ASCII первого символа имени переменной;​ 
-  - код ASCII второго символа имени (0, если имя состоит из одного символа);​ 
-  - младший байт значения;​ 
-  - старший байт значения. 
-<​code>​ 
-┌───────────┐ ​ ┌───────────┐ ​ ┌───────────┐ ​ ┌───────────┐ ​ ┌───────────┐ 
-│  1–й байт │  │ 2–й ​ байт │  │  3–й байт │  │  4–й байт │  │  5–й байт │ 
-└─────▲─────┘ ​ └─────▲─────┘ ​ └─────▲─────┘ ​ └─────▲─────┘ ​ └─────▲─────┘ 
-      │              │              │              │              │ 
-      │          Код ASCII       ​Код ASCII    Младший байт ​  ​Старший байт 
-   ​VALTYPE ​   первого символа второго символа ​  ​значения ​      ​значения 
-             ​имени переменной имени переменной 
-</​code>​ 
- 
-Оказывается,​ что адрес четвёртого байта (младшего байта значения числовой переменной) возвращает как раз переменная ''​VARPTR''​! Кроме того,​напомним,​ что "​содержимое"​ байта с известным адресом может быть "​прочитано"​функцией ''​PEEK''​. 
- 
-Перед тем как работать с нижеприведённым примером,​ во избежание расхождений в результатах не забудьте "​почистить"​ память компьютера оператором ''​CLEAR''​. 
- 
-__//​Пример 1//__ 
-<​code>​ 
-A%=356:​PRINT HEX$(VARPTR(A%)) 
-8006 
-Ok 
-</​code>​ 
-Вы получили шестнадцатеричный адрес младшего байта значения переменной. 
- 
-|<​code>?​ РЕЕК(&​Н8003)</​code>​|Этот адрес соответствует байту ''​VALTYPE''​. Поэтому Вы должны получить 2.| 
-|<​code>?​ РЕЕК(&​Н8004)</​code>​|Этот адрес соответствует первому символу имени переменной. Вы должны получить число 65, которое является кодом ASCII символа "​А"​.| 
-|<​code>?​ PEEK(&​H8005)</​code>​|Получили число 0, поскольку имя переменной состоит лишь из одного символа.| 
-|<​code>?​ РЕЕК(&​Н8006)</​code>​|Этот адрес, возвращённый функцией ''​VARPTR'',​ соответствует младшему байту значения. Должно быть получено число 100.| 
-|<​code>?​ РЕЕК(&​Н8007)</​code>​|Этот адрес соответствует старшему байту значения. Вы, конечно же, получите число 1.| 
-Перепишем два последних значения в двоичной системе счисления:​ 
-<​code>​ 
-100 = 0110 0100₂ 
-  1 = 0000 0001₂ 
-</​code>​ 
-А теперь примем во внимание инверсию порядка байт: 
-<​code>​ 
-0000 0001 0110 0100  ──▶ 356₁₀ 
-────▲──── ────▲──── 
-    │         │ 
-    1        100 
-</​code>​ 
-И перед выполнением следующего примера не забудьте ввести в память компьютера оператор ''​CLEAR''​ ! 
- 
-__//​Пример 2//__. 
-<​code>​ 
-A%=-356:​PRINT HEX$(VARPTR(A%)) 
-8006 
-Ok 
-</​code>​ 
- 
-Полученный результат — это шестнадцатеричный адрес младшего байта. 
-|<​code>?​ РЕЕК(&​Н8003)</​code>​|Вы должны получить 2.| 
-|<​code>?​ РЕЕК(&​Н8004)</​code>​|Этот адрес соответствует первому символу имени переменной. Вы должны получить 65 (код ASCII символа "​A"​).| 
-|<​code>?​ PEEK(&​H8005)</​code>​|0,​ т.к. имя переменной состоит лишь из одного символа.| 
-|<​code>?​ РЕЕК(&​Н8006)</​code>​|Этот адрес, возвращаемый функцией ''​VARPTR'',​ соответствует инвертированному младшему байту значения. Разумеется,​ Вы получите число 156.| 
-|<​code>?​ РЕЕК(&​Н8007)</​code>​|Этот адрес соответствует инвертированному старшему байту значения. Вы получите число 254.| 
- 
-Перепишем два последних значения в двоичной системе счисления:​ 
-  156 = 1001 1100₂ 
-  254 = 1111 1110₂ 
- 
-Принимая во внимание инверсию порядка байт, запишем их содержимое:​ 
-  1111 1110 1001 1100 
-  ────▲──── ────▲──── 
-      │         │ 
-     ​254 ​      156 
- 
-А теперь учитывая,​ что двоичное число 1111111010011100₂ записано в дополнительном коде, получим 1111 1110 1001 1100₂ → 0000 0001 0110 0011₂ → 0000 0001 0110 0011+1 = 0000 0001 0110 0100₂ = 101100100₂ = 356. Ура! 
- 
-Приведём схему расположения информации в памяти для простой числовой переменной //​одинарной//​ и //​двойной//​ точности:​ 
-<​code>​ 
-Байт, адрес которого возвращает функция VARPTR() 
-                        │ 
-          ┌───┬───┬───┬─▼─┬───┬───┬───┬───┐ 
-          │▧▧▧│▧▧▧│▧▧▧│∗∗∗│███│███│ … │███│ 
-          └───┴───┴───┴───┴───┴───┴───┴───┘ 
- ​Адреса──▶ X-3 X-2 X-1  X └───────▲ … ────┘ 
-            ▲  ───▲─── ​ ▲         │ 
-            │     ​│ ​    ​│ ​     Значение 
-            │     ​│ ​ Знак и порядок 
-            │  Идентификатор 
-      Тип переменной 
-</​code>​ 
- 
-Прежде чем проверить работу ниже приведённой командной строки,​наберите команду ''​CLEAR''​. 
- 
-__//​Пример 3//__. 
-<​code>​ 
-AR!=22.3210E+4:​PRINT HEX$(VARPTR(AR!)) 
-8006 
-Ok 
-</​code>​ 
- 
-Если Вы прочитаете адреса с &​H8006-&​H3=&​H8003 по &​H8006+&​H3=&​H8009,​ то обнаружите:​ 
-|&​H8003|4|''​VALTYPE''​ //​переменной одинарной//​ точности (её значение занимает 4 байта)| 
-|&​H8004|65|Код ASCII символа "​А"​| 
-|&​H8005|82|Код ASCII символа "​R"​| 
-|&​H8006|70 = &B 0100 0110|| 
- 
-Адрес &H8006 содержит порядок,​ который кодируется следующим образом:​ 
- 
-^  Содержимое памяти ​ по адресу &​H8006 ​ ^^  Порядок ​ ^  Примечание ​ ^ 
-^  Двоичное значение ​ ^  Десятичное значение ​ ^:::^:::^ 
-|  01  000000 ​ |  64  |  0  | 
-|  01  000001 ​ |  65  |  1  | 
-|  01  000010 ​ |  66  |  2  | 
-|  …  |  …  |  …  | 
-|  01  000110 ​ |  70  |  6  |◀── ​ | 
-|  …  |  …  |  …  | 
-|  01  111110 ​ |  126  |  62  | 
-|  01  111111 ​ |  127  |  63  | 
-|  00  111111 ​ |  63  |  - 1  | 
-|  00  111110 ​ |  62  |  - 2  | 
-|  00  111101 ​ |  61  |  - 3  | 
-|  …  |  …  |  …  | 
-|  00  000010 ​ |  2  |  -62  | 
-|  00  000001 ​ |  1  |  -63  | 
-|  00  000000 ​ |  0  |  -64  | Бит знака мантиссы| 
- 
-Величина порядка задаётся формулой:​ <WRAP centeralign>​Порядок = Двоичное значение 7 младших битов — 64.</​WRAP>​ 
- 
-Первый бит байта содержит //знак мантиссы//,​ причём 0 соответствует знаку "​+",​ а 1 соответствует знаку "​-"​. 
-Продолжим наши исследования:​ 
-|&​H8007|34 = &B 0010 0010 = 22 в двоично–десятичной системе| 
-|&​H8008|50 = &B 0011 0010 = 32 в двоично–десятичной системе| 
-|&​H8009|16 = &B 0001 0000 = 10 в двоично–десятичной системе| 
- 
-В трёх последних байтах Вы, конечно же, "​узнаете"​ число 225. 
- 
-Итак, три последних адреса содержат мантиссу,​ записанную в двоично–десятичном виде (.223210). 
- 
-<WRAP centeralign>​Мантисса числа одинарной точности занимает 3 байта, которые позволяют закодировать 6 разрядов в двоично–десятичном виде.</​WRAP>​ 
- 
-Перед тем как выполнить предлагаемые в примере действия,​наберите и введите в память компьютера оператор ''​CLEAR''​. 
- 
-__//​Пример 4//__. 
-<​code>​ 
-AR#​=-22.321054981117E-4:​PRINT HEX$(VARPTR(AR#​)) 
-8006 
-Ok 
-</​code>​ 
- 
-Если Вы прочитаете адреса с &​H8006-&​H3=&​H8003 по &​H8006+&​H3=&​H8009,​ то обнаружите:​ 
-|&​H8003|8|''​VALTYPE''​ переменной //​двойной//​ точности (её значение занимает 8 байт)| 
-|&​H8004|65|Код ASCII символа "​А"​| 
-|&​H8005|82|Код ASCII символа "​R"​| 
-|&​H8006|190|<​code>​ 
-&B 1011 1110 
-   ▲ 
-   ​└── Знак мантиссы отрицательный! 
-</​code>​| 
- 
-Подсчитаем теперь величину порядка:​ 
-<​code>​ 
-print &​B0111110-64 
--2 
-Ok 
-</​code>​ 
- 
-"​Продолжим наши игры!":​ 
-|&​H8007|34 =  &B 0010 0010 = 22 в двоично–десятичной системе| 
-|&​H8008|50 =  &B 0011 0010 = 32 в двоично–десятичной системе| 
-|&​H8009|16 =  &B 0001 0000 = 10 в двоично–десятичной системе| 
-|&​H800A|84 =  &B 0101 0100 = 54 в двоично–десятичной системе| 
-|&​H800B|152 =  &B 1001 1000 = 98 в двоично–десятичной системе| 
-|&​H800C|17 =  &B 0001 0001 = 11 в двоично–десятичной системе| 
-|&​H800D|23 =  &B 0001 0111 = 17 в двоично–десятичной системе| 
- 
-В семи последних байтах "​узнаётся"​ число 0.22321054981117. 
- 
-<WRAP centeralign>​Мантисса числа двойной точности занимает 7 байт, которые позволяют закодировать 14 разрядов в двоично-десятичном виде.</​WRAP>​ 
- 
-Подведём //​итоги//​ всему сказанному о хранении числовых переменных. 
- 
-^  Тип ​ ^  Значение \\ VALTYPE ​ ^  Колич. \\ байт ​ ^  Номера \\ байт ​ ^  Значение (система счисления) ​ ^  Примечание ​ ^ 
-|  Целая ​ |  2  |  5  |  -3  |  ''​VALTYPE=2''​ (двоичная) ​ | 
-|:::​|:::​|:::​| ​ -2  |  Первый символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ -1  |  Второй символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ 0  |  //​Значение//​ (двоичная);​ \\ для записи отрицательных чисел применяется двоичный дополнительный код; ​ |"​Содержимое"​ этого байта возвращает функция ''​VARPTR()''​| 
-|:::​|:::​|:::​| ​ 1  |:::| 
-|  Одинарной точности ​ |  4  |  7  |  -3  |  VALTYPE=4 (двоичная) ​ | 
-|:::​|:::​|:::​| ​ -2  |  Первый символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ -1  |  Второй символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ 0  |  Порядок и знак (знак в первом бите)\\ (двоичная) \\ Величина порядка = двоичное значение семи последних битов — 64  |"​Содержимое"​ этого байта возвращает функция ''​VARPTR()''​| 
-|:::​|:::​|:::​| ​ 1÷3  |  //​Мантисса//​ (двоично–десятичная) ​ | 
-|  Двойной точности ​ |  8  |  11  |  -3  |  VALTYPE = 8 (двоичная) ​ | 
-|:::​|:::​|:::​| ​ -2  |  Первый символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ -1  |  Второй символ имени (код ASCII) ​ | 
-|:::​|:::​|:::​| ​ 0  |  Порядок и знак (знак в первом бите) \\ (двоичная) \\ Величина порядка = двоичное значение семи последних битов — 64  |"​Содержимое"​ этого байта возвращает функция ''​VARPTR()''​| 
-|:::​|:::​|:::​| ​ 1÷7  |  //​Мантисса//​ (двоично–десятичная) ​ | 
- 
-{{anchor:​e1041-05}} __//​Пример 5//​__. ​ Попробуйте самостоятельно в нем разобраться! \\ {{.examples:​1041-05.bas|}} \\ [[+tab|wmsxbpge>​1041-05.bas]] 
-<​code>​ 
-NEW 
-Ok 
-10 INPUT"​Введите число";​A:​PRINT"​Попробуем '​собрать'​ его из памяти"​ 
-30 B=VARPTR(A):​K$=RIGHT$("​00000000"​+BIN$(PEEK(B)),​8) 
-50 IF MID$(K$,​1,​1)="​1"​ THEN Z$="​-."​ ELSE Z$="​+."​ 
-60 FOR T=1 TO 7:​Z$=Z$+RIGHT$("​00"​+HEX$(PEEK(B+T)),​2):​NEXT 
-70 Z$=Z$+"​E"​ 
-80 IF MID$(K$,​2,​1)="​1"​ THEN Z$=Z$+"​+"​ ELSE Z$=Z$+"​-"​ 
-90 U=VAL("&​b"​+MID$(K$,​2,​7))-64 
-100 C$=MID$(STR$(U),​2):​Z$=Z$+RIGHT$("​00"​+C$,​2) 
-120 PRINT"​Вот Ваше число:";​Z$ 
- 
-run 
-Введите число? 0 
-Попробуем '​собрать'​ его из памяти 
-Вот Ваше число:​+.00000000000000E-64 
-Ok 
- 
-run 
-Введите число? -23545e37 
-Попробуем '​собрать'​ его из памяти 
-Вот Ваше число:​-.23545000000000E+42 
-Ok 
-</​code>​ 
- 
-==== X.4.2. Хранение элементов числовых массивов ==== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Что имеем — не храним;​ потерявши — плачем. 
-<WRAP rightalign>​ 
-—//​Козьма Прутков//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-Вначале мы расскажем Вам о том, как хранится в памяти //​целочисленный//​ массив. 
- 
-Приведём схемы расположения информации в памяти для целочисленных числовых массивов:​ 
-  * //​одномерный//​ массив.<​code>​ 
-  Байт, адрес которого возвращает функция VARPTR()──┐ 
-  ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─▼─┬───┬───┬───┬─ 
-  │     ​│ ​    ​│ ​    ​│ ​    ​│ ​    │ &H1 │     ​│ ​    ​│███│███│███│███│ … 
-  └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴───┴───┴───┴───┴─ 
-    X-8   ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​  ​X-2 ​  ​X-1 ​ └──▲───┘└──▲───┘ 
-    ▲    ─────▲───── ​ ────▲──── ​   ▲    ────▲──── ​    ​│ ​      │ 
-    │         ​│ ​          ​│ ​       │        │     ​Значение Значение 
-    │         ​│ ​  ​Служебная инф. ​  ​│ ​       │     ​нулевого первого 
-    │   ​Идентификатор ​     Для одномерного ​ │     ​элемента элемента 
-Тип массива ​                   массива ​  ​Количество 
-                                        элементов в массиве 
-</​code>​ 
-  * //​двухмерный//​ массив.<​code>​ 
-             ​Байт,​ адрес которого возвращает функция VARPTR()──┐ 
- ​┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─▼─┬───┬─ 
- ​│ ​    ​│ ​    ​│ ​    ​│ ​    ​│ ​    │ &H2 │     ​│ ​    ​│ ​    ​│ ​    ​│███│███│ … 
- ​└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴───┴───┴─ 
-  X-10   ​X-9 ​  ​X-8 ​  ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​  ​X-2 ​  X-1 └───▲───┘ 
-   ​▲ ​   ─────▲───── ─────▲───── ​  ​▲ ​  ​─────▲───── ─────▲───── ​   │ 
-   ​│ ​        ​│ ​          ​│ ​       │        │           ​│ ​     Значение 
-   ​│ ​        ​│ ​   Служебная инф. ​ │    Количество ​ Количество элемента 
-   ​│ ​  ​Идентификатор ​   Для двухмерного ​ столбцов ​   строк ​    (0,0) 
-Тип массива ​                 массива 
-</​code>​ 
-  * для //​элементов//​ целочисленных числовых массивов.<​code>​ 
-  ┌─── Байт, адрес которого возвращает функция VARPTR() 
-┌─▼─┬───┬───┬───┐ 
-│███│███│ … │███│ 
-└───┴───┴───┴───┘ 
-└───────▲───────┘ 
-        │ 
-    Значение 
-</​code>​ 
- 
-Не забыли ли Вы набрать и ввести в память компьютера оператор ''​CLEAR''?​ 
- 
-__//​Пример//​__. 
-<​code>​ 
-DIM C5%(2):​C5%(0)=32000:​C5%(1)=13:​C5%(2)=-4 
-Ok 
-print HEX$(VARPTR(C5%(0))-8) 
-8003 
-Ok 
-</​code>​ 
- 
-|<​code>?​ РЕЕК(&​Н8003)</​code>​|Этот адрес соответствует байту ''​VALTYPE''​. Поэтому Вы должны получить 2.| 
-|<​code>?​ РЕЕК(&​Н8004)</​code>​|Этот адрес соответствует первому символу имени массива. \\ Вы получите число 67, которое является кодом ASCII символа "​C"​.| 
-|<​code>?​ PEEK(&​H8005)</​code>​|Этот адрес соответствует второму символу имени массива Вы получите число 53, которое является кодом ASCII символа "​5"​.| 
-|<​code>?​ РЕЕК(&​Н8006)</​code>​|9 (служебная информация)| 
-|<​code>?​ РЕЕК(&​Н8007)</​code>​|0 (служебная информация)| 
-|<​code>?​ PEEK(&​H8008)</​code>​|Массив C5% — одномерный,​ поэтому мы получили 1.| 
-|<​code>?​ PEEK(&​H8009)</​code>​|3 = 00000011₂| 
-|<​code>?​ PEEK(&​H800А)</​code>​|0 = 00000000₂| 
- 
-Теперь можно найти количество элементов в массиве:​ 00000000 00000011₂ =3 
- 
-|<​code>?​ PEEK(&​H800B)</​code>​|0 = 00000000₂| 
-|<​code>?​ PEEK(&​H800C)</​code>​|125 = 01111101₂| 
- 
-А тогда нулевой элемент массива равен: 01111101 00000000₂ = 32000 
-|<​code>?​ PEEK(&​H800D)</​code>​|13 = 00001101₂| 
-|<​code>?​ PEEK(&​H800E)</​code>​|0| 
- 
-Добрались до первого элемента массива:​ 00000000 00001101₂ = 13 
-|<​code>?​ PEEK(&​H800F)</​code>​|252 = 11111100₂| 
-|<​code>?​ PEEK(&​H8010)</​code>​|255 = 11111111₂| 
- 
-Далее 11111111 11111100₂ → 00000000 00000011₂ + 1 → 00000000 00000100₂ = 4 
- 
-Приведём схемы расположения информации в памяти для нецелочисленных числовых массивов:​ 
-  * //​одномерный//​ массив.<​code>​ 
-  Байт, адрес которого возвращает функция VARPTR() ──┐ 
-  ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──▼──┬───┬───┬───┬── 
-  │     ​│ ​    ​│ ​    ​│ ​    ​│ ​    │ &H1 │     ​│ ​    │ ∗∗∗ │███│ … │███│ … 
-  └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴───┴───┴───┴── 
-    X-8   ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​  ​X-2 ​  ​X-1 ​   X  └─────▲─────┘ 
-    ▲    ─────▲───── ​ ────▲──── ​   ▲    ────▲──── ​   ▲        │ 
-    │         ​│ ​          ​│ ​       │        │        │  Значение нулевого 
-    │         ​│ ​  ​Служебная инф. ​  ​│ ​       │  Знак и порядок ​   элемента 
-    │   ​Идентификатор ​     Для одномерного ​ │ нулевого элемента 
-Тип массива ​                   массива ​     │ 
-                             ​Количество элементов в массиве 
-</​code>​ 
-  * //​двухмерный//​ массив.<​code>​ 
-             ​Байт,​ адрес которого возвращает функция VARPTR() ──┐ 
- ​┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──▼──┬─ 
- ​│ ​    ​│ ​    ​│ ​    ​│ ​    ​│ ​    │ &H2 │     ​│ ​    ​│ ​    ​│ ​    │ ∗∗∗ │ … 
- ​└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─ 
-  X-10   ​X-9 ​  ​X-8 ​  ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​  ​X-2 ​  ​X-1 ​   X 
-   ​▲ ​   ─────▲───── ─────▲───── ​  ​▲ ​  ​─────▲───── ─────▲───── ​  ▲ 
-   ​│ ​        ​│ ​          ​│ ​       │        │           ​│ ​       │ 
-   ​│ ​        ​│ ​   Служебная инф. ​ │    Количество ​     │  Знак и порядок 
-   ​│ ​  ​Идентификатор ​   Для двухмерного столбцов ​      ​│ ​ нулевого элем. 
-Тип массива ​                ​массива ​             Количество строк 
-</​code>​ 
-  * для //​элементов//​ нецелочисленных числовых массивов.<​code>​ 
-       ​┌─── Байт, адрес которого возвращает функция VARPTR() 
-     ​┌─▼─┬───┬───┬───┬───┐ 
-     ​│∗∗∗│███│███│ … │███│ 
-     ​└───┴───┴───┴───┴───┘ 
-       X └───────▲───────┘ 
-       ​▲ ​        │ 
-       ​│ ​    ​Значение 
-Знак и порядок 
-</​code>​ 
- 
-Думаем,​ что теперь Вы в состоянии самостоятельно разобраться с вопросами,​ касающимися "​хранения"​ в RAM многомерных (двухмерных,​ трёхмерных и т.д.) вещественных числовых массивов! 
- 
-===== X.5. Стек ===== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-А люди все роптали и роптали,​ \\ 
-А люди справедливости хотят: \\ 
-— Мы в очереди первые стояли,​ \\ 
-А те, кто сзади нас,— уже едят. 
-<WRAP rightalign>​ 
-—//​В.Высоцкий//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-//​Стек//​ (от англ. "​stack"​ — "​стог",​ "​груда"​) — структура данных или устройство памяти для хранения наращиваемой и сокращаемой последовательности значений,​ в которой в любой момент доступен только последний член последовательности. Примером //​стека//​ является стопка книг на столе, в которой брать и класть книги можно только сверху ("​Математический Энциклопедический Словарь"​). 
- 
-//​Стек//​ используется как программой на [[msx:​basic:​]],​ так и подпрограммами на машинном языке. 
- 
-"​Вершина"​ стека указывается в слове ''​STKTOP(&​HF674)''​. Его позиция зависит от размеров строкового пространства и блоков управления файлами,​ а также от второго аргумента оператора ''​CLEAR''​ (если этот оператор был выполнен). 
- 
-Если Вы хотите получить такие же результаты,​ как в последующем примере,​ воспользуйтесь командой ''​CLEAR''​! 
- 
-__//​Пример 1//__. 
- 
-Рассмотрим структуру расположения информации о цикле ''​FOR''​. 
- 
-  * <​code>​ 
-10 FOR AB%=2 TO 7 STEP 15 '​Оператора NEXT быть не должно! 
-run 
-Ok 
- 
-PRINT HEX$(PEEK(&​HF675))+HEX$(PEEK(&​HF674)) 
-F0A0 
-Ok 
-</​code><​code>​ 
-        Адрес значения AB% в VT 
-Адреса байт ​   │        ┌─ FF◀── для отрицательного шага 
- ​│ ​ ┌────┬─────▼─────┬──▼─┬────┬─────┬─────┬─────┬─────┬─────┬─────┬───┬─ 
- ​│ ​ │&​H82│ &H1B│ &H80│ &​H1│&​HFF│ ​ …  │ &HF │ &H0 │ &H7 │ &H0 │ &HA │&​H0│  ​ 
- ​│ ​ └────┴─────┴─────┴────┴────┴─────┴─────┴─────┴─────┴─────┴─────┴───┴─ 
- ​└─▶ X-27  X-26  X-25 X-24 X-23        X-10  X-9   ​X-8 ​  ​X-7 ​  ​X-6 ​ X-5 
-     ​▲ ​    ​────────── ​  ​▲ ​   ▲        ─────▲──── ​ ─────▲───── ​ ────▲──── 
-     ​│ ​                 │    │             ​│ ​          ​│ ​          │ 
-     ​│ ​            ​Знак шага │     ​Шаг (со знаком) ​ Верхний ​     Номер 
-Код оператора FOR      Тип параметра цикла ​         предел ​      ​строки 
-                                 ​┌── Адрес данного байта &HF0A0 
-              ─┬────┬─────┬───┬──▼──┐ 
-               ​│&​H15│ &H80│ … │ &HFF│ 
-              ─┴────┴─────┴───┴─────┘ 
-                 ​X-4 ​ X-3        X 
-               ​─────▲───── ​      ▲ 
-                    │            └── "​Вершина"​ стека 
-     ​Адрес конца программной строки 
-</​code>​ 
- 
-Перед выполнением следующего примера наберите команду CLEAR! 
- 
-  * <​code>​ 
-10 FOR AB=2.7 TO 7 STEP-32.671533782376 
-run 
-Ok 
- 
-PRINT HEX$(PEEK(&​HF675))+HEX$(PEEK(&​HF674)) 
-F0A0 
-Ok 
-</​code><​code>​ 
- ​Адрес параметра цикла AB в VT, увеличенный на 2 
-                 │ 
-      ┌─────┬────▼──────┬─────┬──────┬──────┬─ 
-      │ &​H82│&​H25│ &H80 │ &​HFF│ ​ &H5 │ &HC2 │ 
-      └─────┴────┴──────┴─────┴──────┴──────┴─ 
-        X-27 X-26  X-25   ​X-24 ​ X-23   ​X-22 ​ ◀── Адреса байт 
-         ​▲ ​  ​────────── ​   ▲     ​▲ ​     ▲      
-         ​│ ​                ​│ ​    ​│ ​     └── Порядок и знак шага 
-  Код оператора FOR        │     ​└───────── Тип параметра цикла 
-                           ​└─────────────── Знак шага 
-           ​─┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─ 
-            │ &H32│ &H67│ &H15│ &H33│ &H78│ &H23│ &H76│ &H41│ 
-           ​─┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─ 
-              X-21  X-20  X-19  X-18  X-17  X-16  X-15  X-14 
-             ​────────────────────▲─────────────────── ​   ▲ 
-                                 ​│ ​                      │ 
-                         ​Мантисса шага ​  ​Порядок и знак верхнего предела 
-┬──────┬────┬────┬────┬───┬───┬───┬─────┬───┬─────┬─────┬───┬────┐ 
-│ &H70 │ &H0│ &H0│ &​H0│&​H0│&​H0│&​H0│ &HA │&​H0│ &H1F│ &H80│ … │&​HFF│ 
-┴──────┴────┴────┴────┴───┴───┴───┴─────┴───┴─────┴─────┴───┴────┘ 
-  X-13  X-12 X-11 X-10 X-9 X-8 X-7  X-6  X-5   ​X-4 ​ X-3        X 
- ​────────────────────▲───────────── ───▲─── ​  ​────▲──── 
-                     ​│ ​                ​│ ​         │ 
-           ​Мантисса верхнего предела ​  ​│ ​  ​Адрес конца программной строки 
-                            Номер строки оператора FOR 
-</​code>​ 
-Не забудьте о команде ''​CLEAR''​! 
-  * <​code>​ 
-10 FOR AB!=2.7 TO 7 STEP-32.6715 
-run 
-Ok 
- 
-PRINT HEX$(PEEK(&​HF675))+HEX$(PEEK(&​HF674)) 
-F0A0 
-Ok 
-</​code><​code>​ 
- ​Адрес параметра цикла AB! в VT, увеличенный на 2 
-           │ 
- ​┌────┬────▼──────┬─────┬─────┬───┬────┬────┬─────┬─────┬─────┬─────┬─ 
- ​│&​H82│&​H22│ &H80 │ &HFF│ &H1 │ … │&​HC2│&​H32│ &H67│ &H15│ &H0 │ &H0 │ 
- ​└────┴────┴──────┴─────┴─────┴───┴────┴────┴─────┴─────┴─────┴─────┴─ 
-  X-27 X-26  X-25  X-24  X-23      X-14 X-13  X-12  X-11  X-10  X-9 
-   ​▲ ​  ​────────── ​ ─▲─ ​  ​─▲── ​      ​▲ ​  ​────────▲─────── ​ ────▲──── 
-   ​│ ​               │     ​│ ​        ​│ ​          ​│ ​            │ 
-Код FOR        Знак шага ​ │ Знак и порядок шага │    3÷6–я цифры мантиссы 
-                          │               ​Мантисса шага ​   верхнего 
-                  Тип параметра цикла ​                      ​предела 
- 
-            ─┬─────┬─────┬─────┬─────┬─────┬─────┬───┬─────┐ 
-             │ &H41│ &H70│ &HA │ &H0 │ &H1C│ &H80│ … │ &HFF│ 
-            ─┴─────┴─────┴─────┴─────┴─────┴─────┴───┴─────┘ 
-               ​X-8 ​  ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​       X 
-                ▲    ─▲─ ​ ─────▲───── ─────▲───── ​      ▲ 
-                │     ​│ ​       │           ​│ ​           └─"​Вершина"​ стека 
-                │     ​│ ​       │    Адрес конца строки 
-                │     ​│ ​ Номер строки 
-                │  1÷2–я цифры мантиссы верхнего предела 
- ​Знак и порядок верхнего предела 
-</​code>​ 
-Хотите получить те же результаты — пользуйтесь оператором ''​CLEAR''​! 
- 
-  * Пример под рубрикой:​ "​Стек в действии!"​ <​code>​ 
-10 FOR AB%=2 TO 7:​NEXT ​  ​◀── Цикл закрыт! 
-20 FOR I%=3 TO 9   ​◀── Цикл не закрыт! 
-run 
-Ok 
- 
-PRINT HEX$(PEEK(&​HF675))+HEX$(PEEK(&​HF674)) 
-F0A0 
-Ok 
-</​code><​code>​ 
-   ​Адрес текущего значения I% в VT 
-Адреса байт ​   │        ┌─ FF◀── для отрицательного шага 
- ​│ ​ ┌────┬─────▼─────┬──▼─┬────┬─────┬─────┬─────┬─────┬─────┬─────┬───┬─ 
- ​│ ​ │&​H82│ &H2C│ &H80│ &​H1│&​HFF│ ​ …  │ &H1 │ &H0 │ &H9 │ &H0 │ &​H14│&​H0│ 
- ​│ ​ └────┴─────┴─────┴────┴────┴─────┴─────┴─────┴─────┴─────┴─────┴───┴─ 
- ​└─▶ X-27  X-26  X-25 X-24 X-23        X-10  X-9   ​X-8 ​  ​X-7 ​  ​X-6 ​ X-5 
-     ​▲ ​    ​────────── ​  ​▲ ​   ▲        ─────▲──── ​ ─────▲───── ​ ────▲──── 
-     ​│ ​                 │    │             ​│ ​          ​│ ​          │ 
-Код оператора FOR  Знак шага │     ​Шаг (со знаком) ​ Верхний ​     Номер 
-                       ​Тип параметра цикла ​         предел ​      ​строки 
-                                 ​┌── Адрес этого байта: &HF0A0 
-              ─┬────┬─────┬───┬──▼──┐ 
-               ​│&​H21│ &H80│ … │ &HFF│ 
-              ─┴────┴─────┴───┴─────┘ 
-                 ​X-4 ​ X-3        X 
-               ​─────▲───── ​      ▲ 
-                    │            └── "​Вершина"​ стека 
-     ​Адрес конца программной строки 
-</​code>​ 
-Отметим,​ что для версии MSX Disk BASIC с отключённым дисководом B при нулевой длине строковой области максимальное число вложенных циклов равно 576. 
- 
-А теперь настала очередь оператора ''​GOSUB''​… 
- 
-Тем не менее, о команде ''​CLEAR''​ забывать не стоит! 
- 
-__//​Пример 2//__. 
-<​code>​ 
-10 GOSUB 30:INPUT A 
-20 '​Просто комментарий! 
-30 '​Еще один комментарий! 
-run 
-Ok 
- 
-PRINT HEX$(PEEK(&​HF675))+HEX$(PEEK(&​HF674)) 
-F0A0 
-Ok 
-</​code><​code>​ 
-                                                ┌── Адрес этого 
-┌────┬────┬────┬────┬────┬────┬────┬────┬────┬──▼─┐ байта: &HF0A0 
-│&​H8D│ &H0│ &​H0│&​H0A│ &​H0│&​h0A│&​h80│ &H0│ &​H0│&​HFF│ 
-└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ 
-  X-9  X-8  X-7  X-6  X-5  X-4  X-3  X-2  X-1   X 
-  ─▲─ ​     ────▲──── ​      ​───▲──── ​           ─▲─ 
-   ​│ ​          ​│ ​             │                 ​└─ Вершина стека 
- ​Код GOSUB     ​│ ​    ​Адрес следующего оператора 
-        Номер текущей строки 
-</​code>​ 
- 
-{{anchor:​e105-03}} __//​Пример 3//__. \\ Работу этих двух программ Вы должны проверить на ученическом дисплее. 
-  - {{.examples:​105-031.bas|}} \\ [[+tab|wmsxbpge>​105-031.bas]]<​code>​ 
-Ok 
-10 GOSUB 30:PRINT 1:END 
-20 PRINT 2:END 
-30 'POKE (&​HF0A0-4),&​H10 
-40 RETURN 
-run 
- 1 
-Ok 
-</​code>​ 
-  - {{.examples:​105-032.bas|}} \\ [[+tab|wmsxbpge>​105-032.bas]]<​code>​ 
-Ok 
-10 GOSUB 30:PRINT 1:END 
-20 PRINT 2:END 
-30 POKE (&​HF0A0-4),&​H10'​Адрес перехода 
-40 RETURN '​изменен с адреса &H800A на адрес &H8010 
-run 
- 2 
-Ok 
-</​code>​ 
- 
-===== X.6. Хранение строковых величин ===== 
- 
-Функция ''​VARPTR''​ указывает адрес расположения строковых данных в оперативной памяти. Она имеет следующий синтаксис:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-VARPTR(γ) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​VARPTR''​ ("​VARiable PoinTeR"​ — "​указатель переменной"​) — служебное слово; 
-  * γ — идентификатор //​строковой//​ переменной. 
-Если переменная не существует,​ то выдаётся сообщение:​ <WRAP centeralign>"​Illegal function call"​.</​WRAP>​ 
- 
-Функция ''​VARPTR''​ возвращает число X — //​адрес//​ байта, находящегося на 3 позиции правее той, с которой располагается информация о переменной γ. 
- 
-Пусть γ — простая строковая переменная. Изобразим "​кусочек"​ памяти в окрестности байта с адресом X: 
- 
-<​code>​ 
-                       ​┌── Байт, адрес которого возвращает функция 
-         ​┌───┬───┬───┬─▼─┬───┬───┐ ​     VARPTR(γ) 
-         ​│▧▧▧│▧▧▧│▧▧▧│∗∗∗│▧▧▧│▧▧▧│ 
-         ​└───┴───┴───┴───┴───┴───┘ 
-Адреса──▶ X-3 X-2 X-1  X  X+1 X+2  
-           ▲ └───▲───┘ ▲ └───▲───┘ 
-           ​│ ​    ​│ ​    ​│ ​    ​└─ Ссылка на адрес в PIT или на адрес в строковой области 
-Тип переменной ​  ​│ ​    ​└── Байт длины 
-           ​Идентификатор 
-</​code>​ 
- 
-Напомним Вам, что в программировании //​ссылка//​ — содержимое ячейки памяти,​ воспринимаемое как адрес некоторой другой ячейки. 
- 
-Указатели строковых переменных хранятся в VT. Они занимают 6 байт, причём:​ 
-  * один байт содержит "​паспорт"​ переменной ''​VALTYPE''​ (число 3); 
-  * два байта содержат имя строковой переменной;​ 
-  * один байт содержит длину строки,​ возвращаемую функцией ''​VARPTR(γ)''​(таким образом,​ обе функции ''​LEN(A$)''​ и ''​PEEK(VARPTR(A$))''​ возвращают одно и тоже значение). Приведём простой пример:​ <​code>​ 
-10 A$="​карандаш":​PRINT LEN(A$);​PEEK(VARPTR(A$)) 
-run 
- ​8 ​ 8 
-Ok 
-</​code>​ 
-  * следующие два байта указывают адрес первого байта строки. Если символьная переменная создаётся явным присваиванием символьной константы,​ то указатель задаёт адрес этой константы в PIT. Лишь затем [[msx:​basic:​]] //​может//​ переслать значение этой символьной переменной в зарезервированное для неё строковое пространство. 
- 
- 
-{{anchor:​e106-01}} __//​Пример 1//__. "​Сборка"​ значения строковой переменной A$ из памяти. \\ {{.examples:​106-01.bas|}} \\ [[+tab|wmsxbpge>​106-01.bas]] 
-<​code>​ 
-5 CLEAR:INPUT A$:​A$=A$+"":​A=PEEK(VARPTR(A$)):​PRINT A 
-30 B$="&​H"​+HEX$(PEEK(VARPTR(A$)+2))+HEX$(PEEK(VARPTR(A$)+1)):​PRINT B$ 
-40 B=VAL(B$):​BB=PEEK(B) 
-45 FOR I=0 TO A-1:PRINT CHR$(PEEK(B+I));:​NEXT I:END 
-run 
-? MSX 
- 3 
-&HF163 
-MSX 
-Ok 
-</​code>​ 
- 
-{{anchor:​e106-02}} __//​Пример 2//__. \\ {{.examples:​106-02.bas|}} \\ [[+tab|wmsxbpge>​106-02.bas]] 
-<​code>​ 
-10 A$="​ABCD"​ 
-run 
-Ok 
-PRINT HEX$(VARPTR(A$)) 
-8014   ​◀── ​ Это адрес байта, содержащего длину A$ 
-Ok 
-</​code>​ 
-Затем выполните команду ''​PRINT PEEK(AD)'',​ где значение переменной AD изменяется от &H8011 до &H8016. Вы получите:​ 
-|<​code>​PRINT PEEK(&​H8011)</​code>​|3|''​VALTYPE''​| 
-|<​code>​PRINT PEEK(&​H8012)</​code>​|65| Код ASCII символа "​A"​| 
-|<​code>​PRINT PEEK(&​H8013)</​code>​|0|Второй символ отсутствует| 
-|<​code>​PRINT PEEK(&​H8014)</​code>​|4|Длина значения A$| 
-|<​code>​PRINT PEEK(&​H8015)</​code>​|9 ​ =  0000 1001₂|Адрес (младший байт)| 
-|<​code>​PRINT PEEK(&​H8016)</​code>​|128 =  1000 0000₂|Адрес (старший байт)| 
- 
-1000 0000 0000 1001₂ ​ = &H8009 
- 
-Итак, строка помещается в PIT по адресу &H8009. 
- 
-Все остальное очевидно! 
-<​code>​ 
-? PEEK(&​H8009) ​ ? PEEK(&​H800A) ​ ? PEEK(&​H800B) ​ ? PEEK(&​H800C) 
- ​65 ​             66              67              68 ◀── Код ASCII "​D"​ 
-Ok              Ok              Ok              Ok 
-</​code>​ 
- 
-{{anchor:​e106-03}} __//​Пример 3//__. \\ {{.examples:​106-03.bas|}} \\ [[+tab|wmsxbpge>​106-03.bas]] 
-А теперь измените строку 10 и выполните программу. 
-<​code>​ 
-10 A$="​ABCD"​+""​ 
-run 
-Ok 
-</​code>​ 
-Повторите вышеуказанные шаги. Вы получите:​ 
-<​code>​ 
-PRINT HEX$(VARPTR(A$)) 
-8017 
-Ok 
-</​code>​ 
-|<​code>​PRINT PEEK(&​H8014)</​code>​|3|''​VALTYPE''​| 
-|<​code>​PRINT PEEK(&​H8015)</​code>​|65|Код ASCII для символа "​А"​| 
-|<​code>​PRINT PEEK(&​H8016)</​code>​|0|В имени нет второго символа| 
-|<​code>​PRINT PEEK(&​H8017)</​code>​|4|Длина строки| 
-|<​code>​PRINT PEEK(&​H8018)</​code>​|101 = &​H65|Новый адрес (млaдший байт)| 
-|<​code>​PRINT PEEK(&​H8019)</​code>​|241 = &​HF1|Новый адрес (старший байт)| 
- 
-Операция,​ выполненная над строкой,​ явилась причиной пересылки её по адресу &HF165 (без изменения). Вы можете убедиться в этом, используя "в окрестности"​ этого адреса функцию ''​PEEK''​. 
-<​code>​ 
-? PEEK(&​HF165) ​  ? PEEK(&​HF166) ​  ? PEEK(&​HF167) ​  ? PEEK(&​HF168) 
- ​65 ​              ​66 ​              ​67 ​              68 
-Ok               ​Ok ​              ​Ok ​              Ok 
-</​code>​ 
- 
-Забегая несколько вперёд,​ отметим,​ что функция ''​%%FRE(""​)%%''​ возвратила бы число 200 в первом случае,​ однако,​ во втором случае возвращает число 196. 
- 
-Приведём схемы расположения информации в памяти для строковых массивов:​ 
-  * //​одномерный//​ строковый массив.<​code>​ 
-                        VARPTR(B$(0))───┐ ​          ​┌── VARPTR(B$(1)) 
-      ┌───┬───┬───┬───┬───┬───┬───┬───┬─▼─┬───┬───┬─▼─┬───┬───┬─── ​ 
-      │   ​│ ​  ​│ ​  ​│ ​  ​│ ​  │ 1 │   ​│ ​  ​│∗∗∗│ ​  ​│ ​  ​│∗∗∗│ ​  ​│ ​  ​│∗∗∗ 
-      └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴─── 
-       X-8 X-7 X-6 X-5 X-4 X-3 X-2 X-1  X  X+1 X+2 X+3 X+4 X+5 
-       ​▲ ​  ​───▲─── ───▲─── ​ ▲  ───▲─── ​ ▲  ─▲───── ─▲─ ───▲─── 
-       ​│ ​     │       ​│ ​    ​│ ​    ​│ ​    ​│ ​  ​│ ​      ​│ ​    │ 
-Тип массива ​  ​│ ​  ​Служебная │     ​│ ​    ​│ ​  ​│ ​      │ Адрес 1–го элемента 
-    Идентификатор информация│ ​    ​│ ​    ​│ ​  │ Длина значения 1–го элемента 
-                            │     ​│ ​    │ Адрес 0–го элемента 
-              Размерность массива │ Длина значения 0–го элемента 
-                     ​Число элементов в массиве 
-</​code>​ <​WRAP>​ 
- 
-{{anchor:​e106-04}} __//​Пример 4//__. Обязательно разберите пример "с компьютером в руках"​! \\ {{.examples:​106-04.bas|}} \\ [[+tab|wmsxbpge>​106-04.bas]] 
-<​code>​ 
-10 DIM SM$(2):​SM$(0)="​рог"​+"":​SM$(1)="​Inform"​+"":​SM$(2)="​1989 г."​+""​ 
-run 
-Ok 
-print HEX$(VARPTR(SM$(0))-8) 
-8047 
-Ok 
-</​code>​ 
-|<​code>?​ РЕЕК(&​Н8047)</​code>​|Этот адрес соответствует байту ''​VALTYPE''​. Поэтому Вы должны получить 3.| 
-|<​code>?​ РЕЕК(&​Н8048)</​code>​|Этот адрес соответствует первому символу имени строкового массива. Вы должны получить число 83 — код ASCII символа "​S"​.| 
-|<​code>?​ PEEK(&​H8049)</​code>​|Этот адрес соответствует второму символу имени строкового массива. Вы должны получить число 77 — код ASCII символа "​М"​.| 
-|<​code>?​ РЕЕК(&​Н804A)</​code>​|12 ​ Служебная информация| 
-|<​code>?​ РЕЕК(&​Н804B)</​code>​|0 Служебная информация| 
-|<​code>?​ PEEK(&​H804C)</​code>​|Массив SM$ одномерный,​ поэтому мы и получили 1.| 
-|<​code>?​ PEEK(&​H804D)</​code>​|3 = 00000011₂| 
-|<​code>?​ PEEK(&​H804E)</​code>​|0 = 00000000₂| 
-Теперь находим количество элементов в массиве:​ 00000000 00000011₂ = 3 
-  ? PEEK(&​H800F)◀── 3 Длина значения элемента SM$(0). 
-Приведём схему расположения информации в памяти для элемента строкового массива:​ 
-<​code>​ 
-           ​┌───┬───┬───┐ 
-           ​│∗∗∗│▧▧▧│▧▧▧│ 
-           ​└───┴───┴───┘ 
-  Адреса ──▶ X  X+1 X+2 
-             ​▲ ​ ───▲─── 
-Байт длины ──┘ ​    ​└── Ссылка на адрес в строковой области 
-</​code>​ 
-Продолжим наш пример:​ 
-<​code>​ 
-PRINT HEX$(VARPTR(SM$(0))) 
-804F 
-Ok 
-? PEEK(&​h804F) 
-3                  ◀──── Длина значения 0–го элемента массива 
-Ok 
-? HEX$(PEEK(&​h8050)) 
-66                  ◀──── Младший байт адреса 0–го элемента в строковой области 
-Ok 
-? HEX$(PEEK(&​h8051)) 
-F1                  ◀──── Старший байт адреса 0–го элемента в строковой области 
-Ok 
-? CHR$(PEEK(&​hF166)) 
-р                    ◀─┐ 
-Ok                     │ 
-? CHR$(PEEK(&​hF167)) ​  │ Символы 
-о                    ◀─┤ значения 
-Ok                     │ 0–го 
-? CHR$(PEEK(&​hF168)) ​  │ элемента 
-г                    ◀─┘ 
-Ok 
-</​code>​ 
-</​WRAP>​ 
-  * //​двухмерный//​ строковый массив. <​code>​ 
-                    Значение,​ возвращаемое функцией VARPTR() ───┐ 
- ​┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──▼──┐ 
- ​│ ​    ​│ ​    ​│ ​    ​│ ​    ​│ ​    │ &H2 │     ​│ ​    ​│ ​    ​│ ​    │ ∗∗∗ │ 
- ​└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ 
-  X-10   ​X-9 ​  ​X-8 ​  ​X-7 ​  ​X-6 ​  ​X-5 ​  ​X-4 ​  ​X-3 ​  ​X-2 ​  ​X-1 ​   X 
-   ​▲ ​   ─────▲───── ─────▲───── ​  ​▲ ​  ​─────▲───── ─────▲───── ​  ▲ 
-   ​│ ​        ​│ ​          ​│ ​       │        │           ​│ ​       │ 
-   ​│ ​        ​│ ​   Служебная инф. ​ │        │           ​│ ​ Длина значения 
-   ​│ ​  ​Идентификатор ​      ​Для двухмерного │           ​│ ​ нулевого элем. 
-Тип массива ​                   массива ​    ​│ ​          │ 
-                              Количество столбцов ​ Количество строк 
-</​code>​ 
- 
-{{anchor:​clear}} 
-===== X.7. Оператор CLEAR ===== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Чтобы вычистить одно, приходится выпачкать что–нибудь другое;​ но можно испачкать всё, что угодно,​ и ничего при этом не вычистить. 
-<WRAP rightalign>​ 
-—//​Принцип Накопления Грязи по Питеру//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-Оператор ''​CLEAR''​ в общем виде записывается так: 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-CLEAR [[n][,A]] 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​CLEAR''​ ("​очистить"​) — служебное слово; 
-  * n — арифметическое выражение,​ целая часть значения которого указывает количество байт, резервируемых под строковое пространство;​ значение параметра n меняется от нуля до размеров свободного пространства и равно 200 по умолчанию;​ 
-  * А — арифметическое выражение,​ целая часть значения которого определяет адрес первого байта участка памяти,​ расположенного между блоком управления файлами и рабочей областью. Этот участок не будет "​обработан"​ интерпретатором,​ поэтому он является как бы "​резервной"​ памятью,​ где Вы можете хранить,​ например,​ подпрограммы на машинном языке и другие необходимые Вам данные. 
- 
-Другими словами,​ значение А "​переопределяет верхний предел пространства,​ используемого [[msx:​basic:​]]"​. 
- 
-Например,​ команда ''​CLEAR 1000, &​HF000''​ отводит 1000 байт для значений строковых констант в строковой области и RAM с адреса &HF000 для размещения машинной подпрограммы. 
- 
-//​Максимальным//​ значением выражения A, конечно же, является адрес, с которого начинается рабочая область (&​HF380). 
- 
-//​Минимальное//​ значение выражения A может быть определено по формуле:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-267·(MAXFIL+1)+VARTAB+145+n+2 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​MAXFIL''​ — имя слова, расположенного в рабочей области по адресу &HF85F. Этот адрес занимает 1 байт памяти;​ 
-  * ''​VARTAB''​ — имя слова, расположенного в рабочей области по адресу &HF6C2. Адрес занимает 2 байта памяти и отмечает конец PIT; 
-  * n — размер строкового пространства в байтах. 
- 
-Заметим,​ что //​минимальная//​ величина стека равна 145 байтам (это пространство между концом PIT и вершиной стека). 
-Отметим,​ что оба аргумента могут быть опущены;​ в этом случае оператор ''​CLEAR''​ производит "​чистку"​ значений всех числовых и строковых переменных,​ элементов массивов и определённых пользователем функций ''​DEFFN'',​ а также "​уничтожает"​ стек. 
- 
-Сохранятся только текст программы на [[msx:​basic:​]] и ранее зарезервированные машинные подпрограммы! 
- 
-Приведём два простеньких примера:​ 
-  * 1) {{anchor:​e107-01}} {{.examples:​107-01.bas|}} \\ [[+tab|wmsxbpge>​107-01.bas]] <​code>​ 
-10 DEF FNY(X)=X 
-11 CLEAR 
-12 PRINT FNY(1) 
-run 
-Undefined user function 
-Ok 
-</​code>​ 
-  * 2) {{anchor:​e107-02}} {{.examples:​107-02.bas|}} \\ [[+tab|wmsxbpge>​107-02.bas]]<​code>​ 
-10 M=9:​T$=STRING$(5,"​+"​):?​M;​T$ 
-20 CLEAR:?M;T$ 
-run 
- 9 +++++ 
- 0 
-Ok 
-</​code>​ 
-Параметр n в операторе ''​CLEAR n''​ указывает размер строковой области,​ зарезервированной для хранения строковых значений,​ причём:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-0 ≤ n ≤ FRETOP-VARTAB-145-16 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​FRETOP''​ — имя слова, расположенного в рабочей области по адресу &HF69B. Этот адрес занимает 2 байта памяти;​ 
-  * ''​VARTAB''​ — имя слова, расположенного в рабочей области по адресу &HF6C2. Этот адрес занимает 2 байта памяти. 
- 
-{{anchor:​e107-03}} __//​Пример 3//__. Нажмите кнопку <​key>​RESET</​key>​ Вашего компьютера. \\ {{.examples:​107-03.bas|}} \\ [[+tab|wmsxbpge>​107-03.bas]] 
-А теперь:​ 
-<​code>​ 
-10 PRINT HEX$(PEEK(&​HF69C));"​ ";​HEX$(PEEK(&​HF69B)) 
-11 PRINT HEX$(PEEK(&​HF6C3));"​ ";​HEX$(PEEK(&​HF6C2)) 
-12 PRINT &​HDC5F-&​H8003-145-16 
-DC 5F  ◀───── ​ Вы узнали адрес FRETOP ? 
-80 3   ​◀───── ​ Вы узнали адрес VARTAB ? 
- 23483 ◀───── ​ 0≤n≤23483 
-Ok 
-</​code>​ 
- 
-{{anchor:​e107-04}} __//​Пример 4//__. \\ {{.examples:​107-041.bas|}} \\ [[+tab|wmsxbpge>​107-041.bas]] 
-<​code>​ 
-10 CLEAR200:​T$=SPACE$(198):​B$=STRING$(2,"#"​):?​B$:​X$=STRING$(1,"​L"​):?​X$ 
-run 
-## 
-Out of string space in 10 
-Ok 
-</​code>​ 
-Получили сообщение об отсутствии места в строковой области,​ так как 200 байт, отведённых для неё по умолчанию,​ оказались уже исчерпанными. 
- 
-Однако... 
-\\ {{.examples:​107-042.bas|}} \\ [[+tab|wmsxbpge>​107-042.bas]] 
-<​code>​ 
-10 CLEAR 200:​T$=SPACE$(198):​B$=STRING$(2,"#"​):?​B$;:​CLEAR1:​X$=STRING$(1,"​L"​):?​ FRE(""​) 
-run 
-## 0 
-Ok 
-</​code>​ 
- 
-===== X.8. Функция FRE ===== 
- 
-{{anchor:​fre}} 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Garbage collection ("​чистка памяти",​ "​сборка мусора"​) — действия системы динамического распределения памяти для обнаружения неиспользуемых программой блоков памяти и присоединения их к списку свободной памяти для повторного использования. 
-<WRAP rightalign>​ 
-—//​Англо–русский словарь по программированию и информатике//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-Информацию о размере свободной области ("Free Area") в RAM можно получить с помощью функции ''​FRE'',​ обращение к которой ​ имеет вид: 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-FRE(A) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​FRE''​ ("​FREe"​ — "​свободный"​) — служебное слово; 
-  * A — арифметическое или строковое выражение,​ причём для интерпретатора важным является лишь тип выражения,​ а не его значение. 
- 
-На практике применяется следующий синтаксис:​ 
-<​code>​ 
-FRE(0) 
-</​code>​ 
-или 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-FRE(""​) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-. 
-</​WRAP>​ 
-</​WRAP>​ 
- 
-Функция ''​FRE(0)''​ возвращает количество байт, оставленных для расширения PIT, VT, стека, строковой области и блока управления файлами. 
- 
-{{anchor:​e108-01}} __//​Пример 1//__. \\ {{.examples:​108-01.bas|}} \\ [[+tab|wmsxbpge>​108-01.bas]] 
-<​code>​ 
-10 ? FRE(0):​X=451:?​ FRE(0):​Z#​=7.5:?​ FRE(0) 
-20 Y!=555:? FRE(0):​W%=111:?​ FRE(0) 
-run 
- 28739 
- 28728 ◀── т.к. переменная Х по умолчанию — двойной точности,​ а, следовательно,​ занимает в памяти 11 байт; 
- 28717 ◀── т.к. переменная Z — двойной точности (занимает в памяти также 11 байт); 
- 28710 ◀── т.к. переменная Y — одинарной точности (занимает в памяти 7 байт); 
- 28705 ◀── т.к. переменная W — целого типа (занимает в памяти 5 байт). 
-Ok 
-</​code>​ 
-Функция ''​FRE(0)''​ выдаёт сообщение:​ <WRAP centeralign>"​Out of memory"​ (//"​Не хватает памяти"//​)</​WRAP>​ при достижении значения,​ меньшего 145 байт, минимально допустимого для стека системы [[msx:​basic:​]]. Посмотрите (предварительно нажав кнопку <​key>​RESET</​key>​):​ 
-<​code>​ 
-CLEAR 28868:PRINT FRE(0) 
- 147 
-Ok 
-</​code>​ 
- 
-<​code>​ 
-CLEAR 28869:PRINT FRE(0) 
-Out of memory 
-Ok 
-</​code>​ 
- 
-Заметим,​что слово ''​VARTAB''​ отличается от слова ''​TXTTAB''​ на 2 байта (при отсутствии программы!),​ поэтому,​ добавив эти 2 байта к 145 байтам,​ необходимым для работы стека, получаем число 147! 
- 
-Функция ''​%%FRE(""​)%%''​ возвращает количество свободных байт в строковом пространстве. Например:​ 
-<​code>​ 
-print FRE(""​) 
- 200 
-Ok 
-</​code>​ 
- 
-<​code>​ 
-X$="​2²"​+"​3²":​print FRE(""​) 
- 196 
-Ok 
-</​code>​ 
- 
-Кроме того, функция ''​%%FRE(""​)%%''​ выполняет важное дополнительное действие. 
-Оно связано с наличием в [[msx:​basic:​]] строк переменной длины, обработка которых может привести к явлению "​фрагментации памяти"​ (внутри строковой области появляются участки,​содержащие неиспользуемую информацию — //"​мусор"//​). 
-Поэтому,​ если в качестве аргумента функции ''​FRE''​ задано выражение строкового типа, перед вычислением объёма свободной памяти функция выполняет //"​сборку мусора"//,​ т.е. удаление всех неиспользуемых данных и освобождение занимаемых ими областей. 
- 
-{{anchor:​e108-02}} __//​Пример 2//__. Оказывается,​что если у Вас в начале программы встречается оператор ''​A$="​ABCD"​+"​EF"'',​ а затем — оператор ''​A$="​X"​+"​Y"'',​ то Вы сразу же создадите 6–байтовое пространство,​ заполненное "​мусором"​! \\  
-Покажем это: 
-\\ {{.examples:​108-02.bas|}} \\ [[+tab|wmsxbpge>​108-02.bas]] \\ FIXME 
-<​code>​ 
-print HEX$(PEEK(&​HF69C));​ HEX$(PEEK(&​HF69B));​ 
-F168                               ​────▲─── 
-Ok                                     ​└── Адрес "​верхушки"​ строкового 
-a$="​ABCD"​+"​EF" ​                            ​пространства 
-Ok 
- 
-for t=0 to 5:print chr$(peek(&​HF168-t));:​next 
-FEDCBA 
-Ok 
-a$="​X"​+"​Y"​ 
-Ok 
- 
-for t=0 to 7:print chr$(peek(&​hF168-t));:​next 
-FEDCBAYX 
-└──▲─┘ 
-Ok └─── "​мусор"​ 
- 
-print fre(""​)'​Избавимся от "​мусора"​! 
-198 
-Ok 
- 
-for t=0 to 7:print chr$(peek(&​hF168-t));:​next 
-YXXCBAYX 
-  └──▲─┘ 
-Ok   ​└─── "​мусор"​ 
-</​code>​ 
- 
-Из примера следует,​ что строки хранятся в строковом пространстве в том порядке,​ в каком они были определены. 
- 
-Таким образом,​ функция ''​%%FRE(""​)%%''​ изменила положение значения строковой переменной (это и называется //"​сборкой мусора"//​). 
- 
-Если под строки зарезервирован большой объем строкового пространства и определено много символьных переменных,​ время "​сборки мусора"​ может составить несколько минут. При выполнении этой операции компьютер полностью "​застывает"​. Посмотрите… 
- 
-{{anchor:​e108-03}} __//​Пример 3//__. \\ {{.examples:​108-03.bas|}} \\ [[+tab|wmsxbpge>​108-03.bas]] 
-<​code>​ 
-10 CLEAR 5000 '​Объявлен размер строковой области - 5000 байт 
-15 DEFINT A-Z:DIM A$(1500):​FOR I=1 TO 1500:​A$(I)="​2"​+"":​NEXT 
-30 '​Размещение данных в строковой области,​ "​мусора"​ нет! 
-40 TIME=0:​PRINT FRE(""​),​TIME/​60/​60"​мин"​ 
-run                                  
-·3500··········3.61638888888 мин 
-Ok          (для MSX 1) 
- 
-run 
-·3500··········3.3716666666667 мин 
-Ok          (для MSX 2) 
-</​code>​ 
-Интересно,​ что при изменении в строке 10 оператора ''​CLEAR 5000''​ на оператор ''​CLEAR 1600'',​ результат получается почти тот же (≈3.607 мин. для компьютера [[msx:​msx_1]] и ≈3.38 мин. для компьютера [[msx:​msx_2]])! 
- 
-//​Единственный//​ способ уменьшить время "​сборки мусора"​ — это использовать минимальное количество строк и особенно строковых массивов! 
- 
-Следует заметить,​ что некоторые строки хранятся в тексте самой программы и, таким образом,​ не занимают места в строковой области. 
- 
-{{anchor:​e108-04}} __//​Пример 4//__. \\ {{.examples:​108-04.bas|}} \\ [[+tab|wmsxbpge>​108-04.bas]] 
-<​code>​ 
-10 ? FRE(""​);:​U$="​fywapro":​D$="​K":?​ FRE(""​);:​DIM E$(150):? FRE(""​) 
-20 FOR K=1 TO 150:​E$(K)=CHR$(K):​NEXT:?​ FRE(""​) 
-30 E$(1)="​APR":?​ FRE(""​):​E$(1)="​ "​+E$(1):?​ FRE(""​) 
-run 
-200  200  200     ​Далее пауза для "​сборки мусора"​… 
-50 
-51  ◀── ​ Произошла "​сборка мусора"​ (свободное место в строковой области 
-47       ​увеличилось,​ т.к. значение элемента массива E$(1) уже хранится 
-Ok       в тексте программы)… 
-</​code>​ 
-Таким образом,​ строковая область является областью памяти,​ резервируемой для хранения строковых данных. Если Вы хотите зарезервировать в строковом пространстве место для хранения 10 строк, содержащих каждая максимум 5 символов,​ то воспользуйтесь,​ например,​ оператором цикла: 
-<​code>​ 
-FOR I=1 TO 10:​A$(I)=SPACE$(5):​NEXT 
-</​code>​ 
-Во избежание "​сборки мусора":​ 
-  - определяйте все переменные в начале программы;​ 
-  - <​WRAP>​ используйте строковые функции ''​MID$'',​ ''​LEFT$'',​ ''​RIGHT$''​. 
-Перед работой со следующим примером выключите,​ а затем снова включите Ваш компьютер. 
- 
-{{anchor:​e108-05}} __//​Пример 5//__. \\ {{.examples:​108-05.bas|}} \\ [[+tab|wmsxbpge>​108-05.bas]] \\ FIXME 
-<​code>​ 
-A$="​полет"​ 
-Ok 
-for t=0 to 10:print chr$(peek(&​HF168-t));:​next 
-телопп██ 
-Ok   ​└▲─┘ 
-      └─────── "м у с о р" 
-A$="​налет"​ 
-Ok 
-for t=0 to 10:print chr$(peek(&​HF168-t));:​next 
-телоптеланн 
-└─▲─┘ ​    ▲ 
-  └───────└──── "м у с о р" 
-Ok 
-print fre(""​) 
- 195 
-Ok 
-for t=0 to 10:print chr$(peek(&​HF168-t));:​next 
-теланнеланн 
-     ​└─▲──┘ 
-       ​└─────── "м у с о р" 
-Ok 
-mid$(A$,​1,​2)="​по"​ 
-Ok 
-for t=0 to 10:print chr$(peek(&​HF168-t));:​next 
-телоппеланн 
-     ​└──▲─┘ 
-        └── "м у с о р" (он остался на прежнем месте!) 
-Ok 
-</​code>​ 
- 
-Отметим,​ что строковые функции ''​MID$'',​ ''​LEFT$'',​ ''​RIGHT$''​ не изменяют указатели на значения строковых переменных. Обычный же оператор присваивания,​ разумеется,​ указатели изменяет! Покажем это на примере (не забудьте о команде ''​CLEAR''​ !). 
- 
-{{anchor:​e108-06}} __//​Пример 6//__. \\ {{.examples:​108-06.bas|}} \\ [[+tab|wmsxbpge>​108-06.bas]] \\ FIXME 
-<​code>​ 
-a$="​полет"​ 
-Ok 
-print hex$(peek(varptr(a$)+2));​ hex$(peek(varptr(a$)+1)) 
-F164 
-Ok 
-a$="​налет"​ 
-Ok 
-print hex$(peek(varptr(a$)+2));​ hex$(peek(varptr(a$)+1)) 
-F15F 
-Ok 
-</​code>​ 
-а теперь… 
-<​code>​ 
-mid$(a$,​1,​2)="​по"​ 
-Ok 
-print hex$(peek(varptr(a$)+2));​ hex$(peek(varptr(a$)+1)) 
-F15F   ​◀── Обратите внимание,​ это значение совпадает с предыдущим! 
-Ok 
-</​code>​ 
-Как видим, значение указателя в последнем случае не изменилось! 
-</​WRAP>​ 
-  - <​WRAP>​при необходимости используйте оператор ''​SWAP A$,​В$''​ , который не меняет расположение значений переменных,​ а лишь меняет местами указатели на эти значения. Проиллюстрируем этот факт на примере… 
- 
-{{anchor:​e108-07}} __//​Пример 7//__. \\ {{.examples:​108-07.bas|}} \\ [[+tab|wmsxbpge>​108-07.bas]] \\ FIXME 
-<​code>​ 
-clear 
-Ok 
-print HEX$(PEEK(&​HF69C));​ HEX$(PEEK(&​HF69B)) 
-F168 
-Ok 
-A$="​Зачет":​B$="​Автомат"​ 
-Оk 
-for t=0 to len(a$)+len(b$):​print chr$(peek(&​hF168-t));:​next 
-течаЗтамотвАА 
-Ok 
-swap A$,B$ 
-Ok 
-for t=0 to len(a$)+len(b$):​print chr$(peek(&​hF168-t));:​next 
-течаЗтамотвАА 
-Ok 
-</​code>​ 
- 
-И наконец,​ функция ''​FRE()''​ может помочь Вам также в //​защите//​ Вашей программы. Например,​ в "​укромном"​ месте программы,​ работающей со строковой информацией,​ поместите оператор ''​%%X$=SPACE$(FRE(""​))%%''​ — конечно,​ Вы должны учесть,​ что целая часть значения аргумента функции ''​SPACE$''​ должна принадлежать отрезку [0,255]!. Это удержит "​любознательных"​ от модификации значений переменных Вашей программы (разумеется,​ в данном случае строковых)! 
- 
-Посмотрите:​ 
-<​code>​ 
-10 X$=SPACE$(FRE(""​)):​Y$="​2"​+Y$ 
-run 
-Out of string space in 10 
-Ok 
-</​code>​ 
-</​WRAP>​ 
- 
-===== X.9. Рабочая область ===== 
- 
-В рабочей области содержатся системные подпрограммы,​ системные переменные и "​ловушки",​ используемые интерпретатором во время выполнения операторов Вашей программы. В рабочей области хранятся данные о позиции курсора,​ цвете текста,​ состоянии функциональных клавиш и другая полезная информация,​ инициализируемая при включении компьютера. 
- 
-<WRAP centeralign>​Адрес,​ отмечающий //​начало//​ рабочей области,​ указан в самой этой области в слове ''​HIMEM'',​ содержимое которого занимает 2 байта, расположенных с адреса &HFC4A .</​WRAP>​ 
- 
-Ещё раз напомним Вам, что адреса,​ занимающие два байта, всегда записываются так: вначале записывается содержимое младшего байта, а затем — содержимое старшего байта! 
- 
-Отметим,​ что значением выражения ''​HEX$(PEEK(&​HFC4A)+256*PEEK(&​HFC4B))''​ является //​адрес начала рабочей//​ области. 
- 
-Поскольку рабочая область расположена в RAM, её переменные могут изменяться операторами ''​POKE''​. Но это следует делать только в том случае,​ если Вы //​знаете//,​ что за этим последует! 
- 
-==== X.9.1. Матрица клавиатуры ==== 
- 
-//​Матрицей//​ клавиатуры для MSX–компьютеров назовём таблицу вида: 
-| | ^  0–й бит ​ ^  1–й бит ​ ^  2–й бит ​ ^  3–й бит ​ ^  4–й бит ​ ^  5–й бит ​ ^  6–й бит ​ ^  7–й бит ​ ^ 
-|:::​^Адреса \\ байт^ ​ 254  ^  253  ^  251  ^  247  ^  239  ^  223  ^  191  ^  127  ^ 
-^  0–я строка ​ ^  FBE5  |  9  |  ;  |  1  |  2  |  3  |  4  |  5  |  6  | 
-^  1–я строка ​ ^  FBE6  |  7  |  8  |  0  |  =  |  -  |  H  |  :  |  V  | 
-^  2–я строка ​ ^  FBE7  |  \  |  .  |  B  |  @  |  ,  |  /  |  F  |  I  | 
-^  3–я строка ​ ^  FBE8  |  S  |  W  |  U  |  A  |  P  |  R  |  [  |  O  | 
-^  4–я строка ​ ^  FBE9  |  L  |  D  |  X  |  T  |  ]  |  Z  |  J  |  K  | 
-^  5–я строка ​ ^  FBEA  |  Y  |  E  |  G  |  M  |  C  |  ~  |  N  |  Q  | 
-^  6–я строка ​ ^  FBEB  |  SHIFT  |  CTRL  |  GRAPH  |  CAPS  |  РУС ​ |  F1  |  F2  |  F3  | 
-^  7–я строка ​ ^  FBEC  |  F4  |  F5  |  ESC  |  TAB  |  STOP  |  BS  |  SELECT ​ |  RETURN ​ | 
-^  8–я строка ​ ^  FBED  |  SPACE  |  HOME  |  INS  |  DEL  |  ←  |  ↑  |  ↓  |  →  | 
-^  9–я строка ​ ^  FBEE  |  RET  |  +  |  *  |  0  |  1  |  2  |  3  |  4  | 
-^  10–я строка ​ ^  FBEF  |  5  |  6  |  7  |  8  |  9  |  -  |  ,  |  .  | 
- 
-Последние две строки соответствуют цифровой (правой) зоне клавиатуры учительского компьютера серии [[msx:​msx_2]]. Более подробная информация по этой теме [[msx:​russification:​russification#​матрица_клавиатуры|здесь]]((Примечание редактора)). 
- 
-Ответим теперь на Ваш очевидный вопрос:​ <WRAP centeralign>​Как воспользоваться этой таблицей?</​WRAP>​ 
- 
-__//​Пример 1//__. Ниже приведены программа,​ останавливаемая нажатием клавиши <​key>​GRAPH</​key>:​ 
-  10 Z=PEEK(&​HFBEB):​IF Z<>​251 THEN 10 
-и программа,​ останавливаемая нажатием клавиш <​key>​SHIFT+CTRL</​key>:​ 
-  10 Z=PEEK(&​HFBEB):​IF Z<>​(254 AND 253) THEN 10 
-А теперь ответ на Ваш следующий вопрос:​ <WRAP centeralign>​А как получить матрицу клавиатуры ?</​WRAP>​ 
- 
-Для "​чтения"​ нажатой клавиши достаточно "​прочесть"​ слово ''​NEWKEY''​ (11 байт) по адресу &HFBE5 из таблицы системных переменных. 
- 
-__//​Пример 2//__. Программа "​пробегает"​ все клавиши и возвращает позицию нажатой клавиши (X,Y) матрицы клавиатуры. 11 значений,​ записанных в слове ''​NEWKEY'',​ соответствуют 11 строкам матрицы клавиатуры. 
-Если не нажата ни одна клавиша,​ содержанием каждого из 8 байт, соответствующих строке матрицы является 1. Это фиксируется двоичным числом &​B11111111=255. Когда же клавиша нажата,​ считанное на этой строке значение отличается от 255: бит соответствующей колонки "​сбрасывается"​ в 0. 
-{{anchor:​e1091-01}} {{.examples:​1091-01.bas|}} \\ [[+tab|wmsxbpge>​1091-01.bas]] 
-<​code>​ 
-10 FOR Y=0 TO 10:​Z=PEEK(&​HFBE5+Y) 
-30 IF Z=255 THEN 80 '​──▶ 
-40 PRINT"​Y=";​Y:​Z$=RIGHT$("​00000000"​+BIN$(Z),​8) 
-60 PRINT"​X=";​8-INSTR(Z$,"​0"​):​PRINT 
-80 NEXT:GOTO 10 '​──▶ 
-</​code>​ 
- 
-==== X.9.2. Динамическая клавиатура [46] ==== 
- 
-[[bibliography#​b46|[46]]] 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-Промедление с лёгким делом превращает его в трудное,​ промедление же с трудным делом превращает его в невозможное. 
-<WRAP rightalign>​ 
-—//​Д.Лоример//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-Исследуем один подход к разработке учебных программ,​ работающих под управлением интерпретатора [[msx:​basic:​]]. Существенная особенность этого подхода состоит в том, что программа в процессе выполнения модифицируется ​ 
-(происходит изменение отдельных строк BASIC–программы или добавление новых строк). Считается,​ что допущение самомодификации программы во время выполнения является признаком плохого стиля программирования,​ поэтому начнём с примера,​ который показывает,​ что предлагаемый подход является не только оправданным,​ но и в ряде случаев единственно возможным. 
- 
-Пусть необходимо табулировать функцию y=f(x), конкретно x², то есть для каждого значения аргумента вычислить значение функции и результат записать в таблицу. Соответствующая программа выглядит следующим образом:​ 
-<​code>​ 
-10 '​Программа табулирования функции. 
-20 DIM X(200),​Y(200) 
-30 INPUT XN,XK '​Задание границ изменения аргумента функции. 
-           … 
-100 GOSUB 1000 '​Обращение к подпрограмме табулирования. 
-           … 
-999 END 
-1000 FOR I=1 TO 200:​Y(I)=X(I)*X(I):​NEXT I:RETURN 
-</​code>​ 
-Части программы между строками 30 и 100, 100 и 999 содержат операторы,​ обеспечивающие масштабирование,​ заполнение таблицы,​ защиту от ошибочных действий пользователя и т.д. Простота программы обусловлена тем, что задача табулирования решается для //​фиксированной//​ функции. Попытаемся теперь разработать программу,​ которая позволяет табулировать любую функцию одной переменной,​ аналитическое выражение которой вводится с клавиатуры! 
- 
-Для реализации на ПЭВМ "​YAMAHA"​ используем специальный механизм,​ введенный Дж.Баттерфилдом (J.Batterfield) и названный им принципом //"​динамической клавиатуры"//​. 
- 
-В //​командном//​ (!) режиме информация,​ набираемая пользователем на клавиатуре,​ аппаратно записывается в буфер (называемый в дальнейшем //​буфером клавиатуры//,​ БК). БК размещается в рабочей области с адреса &HFBF0 по адрес &HFC17 и занимает 40 байт. При нажатии клавиши <​key>'​Ввод '​⏎</​key>​ содержимое БК считывается интерпретатором и выполняется соответствующая команда. 
- 
-Имитация действий пользователя на основе принципа "​динамической клавиатуры"​ осуществляется следующим образом:​ 
-  - с помощью оператора INPUT вводится текст запроса (в данном случае аналитическое выражение табулируемой функции) в символьную строку F$ (в приведённой ниже программе — строка 10); 
-  - символьная строка дополняется впереди номером,​ а в конце — кодом команды ''​RETURN''​ (строки 15 и 1890): \\ ''​F$=%%"​%%номер строки 1%%"​%%+F$+CHR$(13)''​ ; 
-  - строка побайтно переписывается в БК, начиная с адреса &HFBF0, при помощи оператора ''​POKE''​ и функции ''​PEEK''​ (подпрограмма,​ начинающаяся со строки 1880); 
-  - строка ''​S$=%%"​%%goto%%"​%%+%%"​%%номер строки 2%%"​%%+CHR$(13)'',​ где //​номер строк//​ и 2 — номер строки программы,​ куда после модификации необходимо передать управление,​ побайтно переписывается в БК (строка 25); 
-  - выполнение программы прекращается командой ''​END'',​ в результате происходит переход из программного режима в командный. Интерпретатор считывает содержимое БК до первого появления ''​CHR$(13)''​ и выполняет его как команду,​ то есть модифицирует строку с номером //​номер строки//​ 1. Далее считывается остаток содержимого БК до второго появления ''​CHR$(13)'',​ и он также выполняется интерпретатором,​ как команда,​ после чего происходит переход в программный режим с передачей управления в строку с номером //​номер строки 2//. 
- 
-Таким образом,​ указанный алгоритм решает задачу автоматической модификации программы в соответствии с текстом запроса,​ вводимого пользователем с клавиатуры,​ и запуска её с указанного номера строки. 
- 
-{{anchor:​e1092-01}} __//​Пример//​__. \\ {{.examples:​1092-01.bas|}} \\ [[+tab|wmsxbpge>​1092-01.bas]] 
-<​code>​ 
-1 GOTO 10 
-2 GOTO 30 
-10 LINEINPUT"​Введите ​ аналитическую ​ запись функции:";​F$ 
-11 INPUT"​Укажите номер строки,​ содержащей оператор описания функции пользователя DEFFN (51< номер строки <​59)";​SN:​GOSUB 2410 
-13 GOSUB 1550 '​Сохранение F$ 
-15 F$=STR$(SN)+F$:​F$=MID$(F$,​2,​LEN(F$)-1) 
-20 GOSUB 1880 
-25 F$="​goto2":​GOSUB 1880:END 
-30 GOSUB 1730 '​Восстановление F$ 
-50 '​∗∗ Программа табулирования функции Y(x) ∗∗ 
-60 INPUT"​Введите[A,​B] и шаг табулирования H";​A,​B,​H 
-65 FOR X=A TO B STEP H:PRINT X;​FNY(X):​NEXT 
-90 END 
-1550 '​∗∗∗∗∗ Ф о р м и р о в а н и е  F$ ∗∗∗∗∗ 
-1590 F$="​deffny(x)="​+F$:​POKE &​HF600,​LEN(F$) 
-1620 FOR I=1 TO LEN(F$):​POKE &​HF601+I,​ASC(MID$(F$,​I,​1)):​NEXT 
-1720 RETURN'​──▶ 
-1730 '​∗∗∗∗∗ В о с с т а н о в л е н и е  F$ ∗∗∗∗∗ 
-1740 LF=PEEK(&​HF600):​F$=""​ 
-1750 FOR I=1 TO LF:​C=PEEK(&​HF601+I):​F$=F$+CHR$(C):​NEXT 
-1780 RETURN'​──▶ 
-1880 '​∗∗∗∗∗ Д и н а м и ч е с к а я  к л а в и а т у р а ∗∗∗∗∗ 
-1890 F$=F$+CHR$(13) 
-1900 AD=PEEK(&​HF3F9)*256+PEEK(&​HF3F8)-65536! 
-1910 L1=&​HFC17-AD+1 
-1920 IF LEN(F$)<​=L1 THEN GOTO 1990 
-1930 L2=LEN(F$)-L1:​N=0 
-1940 FOR I=AD TO &​HFC17:​N=N+1 
-1950 POKE I,​ASC(MID$(F$,​N,​1)):​NEXT 
-1960 FOR I=&​HFBF0 TO &​HFBF0+L2-1:​N=N+1 
-1970 POKE I,​ASC(MID$(F$,​N,​1)):​NEXT 
-1980 AD=&​HFBF0+L2+65536!:​POKE&​HF3F9,​FIX(AD/​256):​POKE&​HF3F8,​AD-FIX(AD/​256)*256:​GOTO 2050 
-1990 N=0 
-2000 FOR I=AD TO AD+LEN(F$)-1:​N=N+1 
-2010 POKE I,​ASC(MID$(F$,​N,​1)):​NEXT 
-2020 IF LEN(F$)<​L1 THEN AD=AD+LEN(F$) ELSE AD=&​HFBF0 
-2030 AD=AD+65536! 
-2040 POKE&​HF3F9,​FIX(AD/​256):​POKE&​HF3F8,​AD-FIX(AD/​256)*256 
-2050 RETURN'​──▶ 
-2410 IF LEN(F$)>​19 THEN CLS:LOCATE 1,​10:​PRINT"​Эта программа имеет ограничение:":​GOTO 2420 ELSE GOTO 2460 
-2420 PRINT:PRINT "​Длина формулы не должна превосходить 19 символов!";​LEN(F$) 
-2440 PRINT:​LOCATE 1,​23:​PRINT"​Для продолжения нажмите любую клавишу"​ 
-2450 W$=INKEY$:​IF W$=""​ THEN 2450 ELSE GOTO 10 
-2460 RETURN'​──▶ 
-</​code>​ 
- 
-===== X.10. Порты ввода–вывода ===== 
- 
-<WRAP group 99%> 
-<WRAP half column> \\ </​WRAP>​ 
-<WRAP half column><​WRAP justify> 
-И я надеюсь,​ что наши потомки будут благодарны мне не только за то, что я здесь разъяснил,​ но и за то, что мною было добровольно опущено с целью предоставить им удовольствие самим найти это. 
-<WRAP rightalign>​ 
-—//​Pене Декарт. Геометрия//​ 
-</​WRAP></​WRAP>​ 
-</​WRAP></​WRAP>​ 
- 
-//​Порт//​ ввода–вывода — многоразрядный вход или выход компьютера,​ через который процессор обменивается данными с внешними устройствами (клавиатурой,​ принтером,​ дисководом,​ видеопамятью и видеопроцессором,​ игровыми ​ манипуляторами). Часто говорят,​ что порты представляют собой "​интерфейсные схемы компьютера"​. 
- 
-Порт ввода–вывода напоминает морской порт, через который ввозят и вывозят товары. В нашем случае через порты вводятся и выводятся данные. Порты принимают данные от периферийных устройств и направляют их в эти устройства. Используя прямой доступ к портам ввода–вывода,​Вы более полно используете возможности компьютера. 
- 
-Процессор "​работает"​ с портами по адресам,​ которые не следует путать с адресами ROM или RAM: 
-  - порты с адресами &​H00÷&​H7F. Вы не можете //​изменить//​ их содержимое (сравните с ROM!); 
-  - порты с адресами &​H80÷&​HFF. Их содержимое изменять можно (сравните с RAM!); 
-  - порты с адресами &​H100÷&​HFFFF зарезервированы(пока не используются). 
- 
-Некоторые порты, их функции и адреса перечислены ниже: 
- 
-^  Адрес ​ ^  Чтение(Запись) ​ ^  Назначение ​ ^ 
-|  Порты, отвечающие за работу с локальной сетью КУВТ YAMAHA [[msx:​msx_1]] ​ ||| 
-|  &​h00 ​ |  Чтение(Запись) ​ |  Посылаемые данные ​ | 
-|  &​h01 ​ |  Чтение ​ |  Статус ​ | 
-|  &​H02 ​ |  Чтение ​ | Номер компьютера в локальной сети (только для компьютеров [[msx:​msx_1]]) ​ | 
-|  Порты, отвечающие за работу с локальной сетью КУВТ YAMAHA [[msx:​msx_2]] ​ ||| 
-|  &​H09 ​ | |  Командный порт (передача или приём) ​ | 
-|  &​H0C ​ | |  Порт состояния ​ | 
-|  &​H0E ​ | |  Порт данных ​ | 
-|  — — —  |  — — —  |  — — —  | 
-|  &​H0A ​ | |  Используются при инициализации сетевого ОЗУ ​ | 
-|  &​H0B ​ | |:::| 
-|  &​H0D ​ | |:::| 
-|  //​Принтер// ​ ||| 
-|  &​H90 ​ |  Чтение ​ |  Ввод сигнала занятости принтера ​ | 
-|  &​H91 ​ |  Запись ​ |  Код выводимого символа ​ | 
-|  &​H92 ​ |  Запись ​ |  ?  | 
-|  //​Видеопроцессор//​ (VDP)  ||| 
-|  &​H98 ​ |  Чтение(Запись) ​ |  Обращение к видеопамяти ​ | 
-|  &​H99 ​ |  Чтение(Запись) ​ |  Чтение (запись) в регистр VDP  | 
-|  &​H9A ​ |  Запись ​ |  Запись в регистр палитры ​ | 
-|  &​H9B ​ |  Запись ​ |  Косвенная запись в регистры VDP  | 
-|  //​Звукогенератор//​ (PSG)  | 
-|  &​HA0 ​ |  Запись ​ |  Ввод в порт номера регистра ​ | 
-|  &​HA1 ​ |  Запись ​ |  Ввод в порт информации для установленного регистра ​ | 
-|  &​HA2 ​ |  Чтение ​ |  Последнее число, записанное в PSG  | 
-|  Программируемый //​периферийный интерфейс//​ (PPI)  ||| 
-|  &​HA8 ​ |  Чтение(Запись) ​ |  Запись (чтение) данных в порт A  | 
-|  &​HA9 ​ |  Чтение(Запись) ​ |  Запись (чтение) данных в порт B  | 
-|  &​HAA ​ |  Чтение(Запись) ​ |  Запись (чтение) данных в порт C  | 
-|  &​HAB ​ |  Чтение(Запись) ​ |  Запись (чтение) режимов PPI  | 
-|  Порты, отвечающие за работу с  //​дисководом// ​ | 
-|  &​HB4 ​ |  Запись ​ |  ?  | 
-|  &​HB5 ​ |  Чтение(Запись) ​ |  ?  | 
-|  &​HFC ​ |  Чтение(Запись) ​ |  Регистры распределения //​слотов//​ (расширений памяти) для компьютеров серии [[msx:​msx_2]] ​ | 
-|  &​HFD ​ |  Чтение(Запись) ​ |:::| 
-|  &​HFE ​ |  Чтение(Запись) ​ |:::| 
-|  &​HFF ​ |  Чтение(Запись) ​ |:::| 
- 
-<WRAP centeralign>​Для работы с портами ввода–вывода используются:​ функция ''​[[#​INP]]''​ и операторы ''​[[#​OUT]]''​ и ''​[[#​WAIT]]''​.</​WRAP>​ 
- 
-{{anchor:​out}} 
-Формат оператора ''​OUT'':​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-OUT адрес, данное 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​OUT''​ ("​OUTput"​ — "​вывод"​) — служебное слово; 
-  * //​адрес//​ — арифметическое выражение,​ целая часть значения которого принадлежит отрезку [128,255] (128=&​H80,​ 255=&​HFF);​ 
-  * //​данное//​ — арифметическое выражение,​ целая часть значения которого принадлежит отрезку [0,255]. 
- 
-Оператор OUT "​посылает"​ заданное операндом //​данное//​ значение в порт, номер которого задан значением параметра ​ //​адрес//​. 
- 
- 
-<WRAP centeralign>​ 
-//​Внимание!//​ \\  
-На компьютерах серии [[msx:​msx_2]] прежде,​ чем использовать оператор ''​OUT'',​ необходимо в непосредственном режиме выполнить команду ''​[[msx:​network_basic#​CALL NETEND]]''​ (отключить Ваш компьютер от локальной сети) 
-</​WRAP>​ 
- 
-{{anchor:​inp}} 
-Опишем синтаксис функции ''​INP'':​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-INP (адрес) 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​INP''​ ("​INPut"​ — "​ввод"​) — служебное слово; 
-  * //​адрес//​ — арифметическое выражение,​ целая часть значения которого принадлежит отрезку [0,255]. 
- 
-Функция ''​INP''​ возвращает целочисленное значение,​ "​прочитанное"​ из порта, имеющего указанный адрес. 
- 
-Видна ли Вам аналогия между операторами ''​POKE''​ и ''​OUT''​ , ''​PEEK''​ и ''​INP''​ ?! 
- 
-При помощи функции ''​INP''​ Вы можете использовать в своих расчётах номер Вашего компьютера. Чтобы поместить в переменную А номер компьютера,​ на котором Вы работаете в локальной сети [[msx:​msx_1]],​ примените оператор:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-A=INP(&​H02) AND 15 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-. 
-</​WRAP>​ 
-</​WRAP>​ 
- 
-Объясним роль логической операции ''​AND''​. Значением,​ возвращаемым функцией ''​INP(&​H02)'',​ является двоичное число, записанное в одном байте. "​Содержимое"​ четырёх старших битов байта нас не интересует. Заметим,​ что число 15 = &​b00001111. Как Вы уже, наверное,​ догадались,​ логическая операция ''​AND''​ позволяет выделить нужные нам четыре младших бита. 
- 
-==== X.10.1. Программируемый периферийный интерфейс (PPI) ==== 
- 
-Теперь мы перейдём к рассказу о работе с портами Программируемого Периферийного Интерфейса (PPI — "​Parallel Programming Interface"​). Подробное описание [[msx:​ppi:​ppi|здесь]]. 
- 
-Напомним Вам, что //​интерфейс//​ (англ. "​interface"​ — "​сопряжение"​ — способ и средства установления и поддержания информационного обмена между исполнительными устройствами автоматической или человеко–машинной системы. 
- 
-В //​параллельном//​ интерфейсе порция двоичной информации,​ состоящая из n битов, передаётся одновременно по n каналам. 
- 
-<WRAP centeralign>​Порт А используется для выбора //​слотов//,​ осуществляющих управление расширенной памятью компьютера.</​WRAP>​ 
- 
-<WRAP centeralign>​Порты PPI B и C применяются для "​работы"​ с матрицей клавиатуры,​ причём номер строки матрицы клавиатуры "​посылается"​ в порт C, а номер столбца "​читается"​ в порту B.</​WRAP>​ 
- 
-{{anchor:​e1011-01}} __//​Пример 1//__. //​Обнаружение//​ нажатия клавиши <​key>​GRAPH</​key>​. \\ {{.examples:​1011-01.bas|}} \\ [[+tab|wmsxbpge>​1011-01.bas]] 
- 
-Отметим,​ что клавиша <​key>​GRAPH</​key>​ находится в строке 6 и столбце 2 матрицы клавиатуры (и строки,​ и столбцы матрицы нумеруются,​ начиная с 0). Тогда: 
-  - номер строки матрицы клавиатуры "​посылаем"​ в порт C : <​code>​OUT &​HAA,​6</​code>​ 
-  - "​извлекаем"​ номер столбца из порта B: <​code>​X=INP(&​HA9)</​code>​ 
-До нажатия клавиш значением Х является число 255 = &​b11111111.В момент нажатия какой–либо клавиши соответствующий бит порта B (в нашем случае второй) на мгновение обнуляется. 
- 
-Таким образом,​ нажатие клавиши <​key>​GRAPH</​key>​ легко обнаружить,​ если выделить значение интересующего нас бита командой:​ 
-<​code>​ 
-IF (X AND &​b00000100)=0 THEN PRINT"​GRAPH"​ 
-</​code>​ 
-Программа,​ позволяющая обнаружить нажатие клавиши <​key>​GRAPH</​key>,​ выглядит так: 
-<​code>​ 
-10 OUT &​HAA,​6:​X=INP(&​HA9) 
-20 IF (X AND 4)=0 THEN PRINT "​GRAPH":​END 
-30 GOTO 10 
-</​code>​ 
- 
-Надеемся,​ что Вы обратили внимание на недостаток этой программы:​ после её запуска неожиданно включается индикатор <​key>​CAPS</​key>​ (но это не означает,​что Вам удалось смоделировать нажатие клавиши <​key>​CAPS</​key>​!). 
- 
-Разберёмся,​ почему так происходит. 
- 
-Взгляните на приведённую ниже таблицу,​ в которой описаны назначения битов порта C: 
-|Биты 0÷3|Строка клавиатуры| 
-|Бит 4|Если 0, то запускается кассетная лента| 
-|Бит 5|Сигнал записи на ленту| 
-|Бит 6|Если 0, то включается индикатор "​CAPS"​| 
-|Бит 7|Управление звуковым сигналом| 
-Все ясно! Индикатор "​CAPS"​ включается потому,​ что в порт C записывается значение 
-<​code>​ 
-6 = &​b00000110,​ а значит,​ шестой бит порта C "​опрокинулся"​ в нуль. 
-       ​▲ ​                 ─────┬──── 
-       ​└───────────────────────┘ 
-</​code>​ 
- 
-Фактически только четыре //​младших//​ бита порта C определяют номер строки матрицы клавиатуры. Для "​маскирования"​ (игнорирования) значений четырёх старших битов достаточно вместо команды ''​OUT &​HAA,​6''​ выполнить команду: ​ 
-<​code>​ 
-OUT &HAA,6 OR (INP(&​HAA) AND  &HF0) 
-         ​│ ​       │            │                ┌── !!! 
-         ​▼ ​       ▼            ▼                ▼ 
- &​B00000110 OR (&​B∗1∗∗∗∗∗∗ AND &​B11110000) = &​B∗1∗∗ 0110 
-</​code>​ 
-(символом "​∗"​ отмечены биты, состояние которых в данном случае роли не играет). 
- 
-{{anchor:​e1011-02}} __//​Пример 2//__. Включение индикатора "​CAPS"​ (если он выключен!) можно осуществить следующей командой:​ \\ {{.examples:​1011-02.bas|}} \\ [[+tab|wmsxbpge>​1011-02.bas]] 
- 
-<​code>​ 
-OUT &HAA, INP(&​HAA) XOR &​B01000000 
-           ​│ ​              ​│ ​        ​┌─ !!! 
-           ​▼ ​              ​▼ ​        ▼ 
-    &​B∗1∗∗∗∗∗∗ ​ XOR  &​B01000000 = &​B∗0∗∗∗∗∗∗ 
-</​code>​ 
- 
-{{anchor:​e1011-03}} __//​Пример 3//__. \\ {{.examples:​1011-03.bas|}} \\ [[+tab|wmsxbpge>​1011-03.bas]] 
-<​code>​ 
-10 OUT &HAA,6 OR (INP(&​HAA) AND &​HF0):​B=INP(&​HA9) 
-20 IF (B AND 1)=0 THEN PRINT "​Нажата клавиша SHIFT" 
-30 IF (B AND 2)=0 THEN PRINT "​Нажата клавиша CTRL" 
-40 IF (B AND 4)=0 THEN PRINT "​Нажата клавиша GRAPH":​GOTO 10 ELSE 10 
-</​code>​ 
-В ходе работы программы индикатор "​CAPS"​ сохранит состояние,​ в котором он находился до пуска программы! 
- 
- 
-{{anchor:​e1011-04}} __//​Пример 4//__. Получим матрицу клавиатуры при помощи оператора ''​OUT''​! \\ {{.examples:​1011-04.bas|}} \\ [[+tab|wmsxbpge>​1011-04.bas]] 
-<​code>​ 
-10 INPUT "​Номер строки";​N 
-20 INPUT "​Номер столбца";​T 
-30 OUT &​HAA,​INP(&​HAA) AND &HF0 OR N 
-40 B=((INP(&​HA9) AND 2^T)=0) 
-50 IF B THEN PRINT "​Клавиша нажата":​END 
-60 GOTO 30 
-</​code>​ 
- 
-{{anchor:​e1011-05}} __//​Пример 5//__. Включение и выключение кассетной ленты. Операторы ''​MOTOR ON''​ и ''​MOTOR OFF''​ (подробнее о них [[09#​motor|здесь]]) могут быть имитированы с помощью команды:​ \\ {{.examples:​1011-05.bas|}} \\ [[+tab|wmsxbpge>​1011-05.bas]] 
-<​code>​ 
-OUT &HAA, INP(&​HAA) XOR &​B00010000 
-</​code>​ 
- 
-==== X.10.2. Программируемый звуковой генератор (PSG) ==== 
- 
-Вначале приведём два примера записи информации в PSG при помощи портов ввода–вывода. 
- 
-{{anchor:​e1012-01}} __//​Пример 1//__. \\ 
-<WRAP group> 
-<WRAP half column> 
-{{.examples:​1012-011.bas|}} \\ [[+tab|wmsxbpge>​1012-011.bas]] 
-<​code>​ 
-10 SOUND 7,8  '​Шум из канала A 
-20 SOUND 8,15 '​Громкость 
-30 SOUND 6,26 '​Частота звука 
-40 END 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-{{.examples:​1012-012.bas|}} \\ [[+tab|wmsxbpge>​1012-012.bas]] 
-<​code>​ 
-10 OUT &​HA0,​7:​OUT &HA1,8: A=INP(&​HA2) 
-20 OUT &​HA0,​8:​OUT &​HA1,​15:​B=INP(&​HA2) 
-30 OUT &​HA0,​6:​OUT &​HA1,​26:​C=INP(&​HA2) 
-40 PRINT A;B;C 
-</​code>​ 
-</​WRAP>​ 
-</​WRAP>​ 
-<​code>​ 
-run 
- ​8 ​ 15  26 
-Ok 
-</​code>​ 
- 
-{{anchor:​e1012-02}} __//​Пример 2//__. Представьте,​ что Вы находитесь на берегу Чёрного моря в районе Ялты. Закройте глаза и … \\ {{.examples:​1012-02.bas|}} \\ [[+tab|wmsxbpge>​1012-02.bas]] 
-<​code>​ 
-10 FOR I=0 TO 13:READ V 
-20 OUT &​HA0,​I:​OUT &HA1,V '​Имитация действия оператора SOUND I,V 
-30 NEXT:END 
-100 DATA 0,​0,​0,​0,​0,​0,​30,&​HB7,​16,​0,​0,​0,​90,​14 
-</​code>​ 
- 
-А теперь мы расскажем Вам, как можно "​музицировать"​ при помощи //​непосредственной//​ записи в регистры звукового генератора. Взгляните на следующую небольшую табличку:​ 
- 
-^  Исполняемая \\ нота ​ ^  Содержимое нулевого \\ регистра ​ ^  Содержимое первого \\ регистра ​ ^ 
-|<​code>​PLAY "​O4C"</​code>​| ​ 172  |  1  | 
-|<​code>​PLAY "​O4C#"</​code>​| ​ 148  |  1  | 
-|<​code>​PLAY "​O4D"</​code>​| ​ 125  |  1  | 
-|<​code>​PLAY "​O4D#"</​code>​| ​ 104  |  1  | 
-|<​code>​PLAY "​O4E"</​code>​| ​ 83  |  1  | 
-|<​code>​PLAY "​O4F"</​code>​| ​ 64  |  1  | 
-|<​code>​PLAY "​O4F#"</​code>​| ​ 46  |  1  | 
-|<​code>​PLAY "​O4G"</​code>​| ​ 29  |  1  | 
-|<​code>​PLAY "​O4G#"</​code>​| ​ 13  |  1  | 
-|<​code>​PLAY "​O4A"</​code>​| ​ 254  |  0  | 
-|<​code>​PLAY "​O4A#"</​code>​| ​ 240  |  0  | 
-|<​code>​PLAY "​O4B"</​code>​| ​ 227  |  0  | 
-|<​code>​PLAY "​O5C"</​code>​| ​ 214  |  0  | 
- 
-{{anchor:​e1012-03}} __//​Пример 3//__. Гамма "​до–мажор"​. \\ {{.examples:​1012-03.bas|}} \\ [[+tab|wmsxbpge>​1012-03.bas]] 
-<​code>​ 
-10 DATA 1,​172,​1,​125,​1,​83,​1,​64,​1,​29,​0,​254,​0,​227,​0,​214 
-20 OUT &​HA0,​8:​OUT &HA1,15 '​Установим громкость канала A 
-30 FOR T=1 TO 8:READ I1,I2 
-40 OUT &​HA0,​1:​OUT &​HA1,​I1:​OUT &​HA0,​0:​OUT &HA1,I2 
-45 FOR K=1 TO 100:NEXT '​Если Вам захочется "​озвучить",​ например,​ "​выстрел",​ достаточно убрать из программы эту строку 
-50 NEXT 
-60 OUT &​HA0,​8:​OUT &HA1,0 '​Сбросим громкость канала A 
-</​code>​ 
- 
-{{anchor:​e1012-04}} __//​Пример 4//__. "В траве сидел кузнечик!"​ \\ {{.examples:​1012-04.bas|}} \\ [[+tab|wmsxbpge>​1012-04.bas]] 
-<​code>​ 
-10 '​DEFINTA-Z:​BEEP 
-20 OUT &​HA0,​8:​OUT&​HA1,​15:​OUT &​HA0,​1:​OUT &​HA1,​0:​OUT &​HA0,​0:​OUT &​HA1,​254 
-30 RESTORE 240:​S=S+1:​IF S=1 THEN K=14 ELSE K=12 
-40 FOR I=1 TO K:READ S1,S0,T1 
-50 OUT &​HA0,​8:​OUT &HA1,15 
-60 OUT &​HA0,​1:​OUT &​HA1,​S1:​OUT &​HA0,​0:​OUT &HA1,S0 
-70 TIME=0 
-80 T=TIME:IF T<T1 THEN 80 
-90 SOUND 8,0             '​OUT &​HA0,​8:​OUT &​HA1,​0:​FOR J=1 TO 10:NEXT 
-100 NEXT 
-110 IF S=1 THEN 30 
-120 RESTORE 260:S=0 
-130 S=S+1:IF S=1 THEN K=20 ELSE K=14 
-140 FOR I=1 TO K:READ S1,S0,T1 
-150 OUT &​HA0,​8:​OUT &HA1,15 
-160 OUT &​HA0,​1:​OUT &​HA1,​S1:​OUT &​HA0,​0:​OUT &HA1,S0 
-170 TIME=0 
-180 T=TIME:​IFT<​T1 THEN 180 
-190 OUT &​HA0,​0:​OUT &​HA1,​0:​OUT &​HA0,​1:​OUT &​HA0,​0:​FOR J=1 TO 10:​NEXT:​NEXT 
-200 IF S=1 THEN RESTORE 270:GOTO 130 
-210 OUT &​HA0,​8:​OUT &HA1,15 
-220 OUT &​HA0,​1:​OUT &​HA1,​0:​OUT &​HA0,​0:​OUT &​HA1,​254 
-230 RUN 
-240 DATA 0,​254,​15,​1,​83,​15,​0,​254,​15,​1,​83,​15,​0,​254,​15,​1,​13,​15,​1,​13,​30 
-250 DATA 1,​13,​15,​1,​83,​15,​1,​13,​15,​1,​83,​15,​1,​13,​15,​0,​254,​15,​0,​254,​30 
-260 DATA 0,​254,​15,​0,​0,​15,​0,​254,​30 
-270 DATA 0,​227,​15,​0,​227,​7.5,​0,​227,​7.5,​0,​227,​15,​0,​227,​15 
-280 DATA 0,​215,​15,​0,​215,​7.5,​0,​215,​7.5,​0,​215,​15,​0,​215,​15 
-290 DATA 0,​215,​15,​0,​227,​15,​0,​254,​15,​1,​13,​15,​0,​254,​15,​0,​254,​30 
-300 DATA 0,254,15 
-</​code>​ 
- 
-{{anchor:​wait}} 
-==== X.10.3. Другие порты. Оператор WAIT ==== 
- 
-Приведём примеры использования "​содержимого"​ других портов. 
- 
-{{anchor:​e1013-01}} __//​Пример 1//__. Использование портов с адресами &H90 и &H91 для вывода символа на принтер. 
- 
-Вначале о "​роли"​ первого бита порта с номером &H90: 
-<​code>​ 
- ​7–й бит ​ 6–й бит ​ 5–й бит 4–й бит ​ 3–й бит 2–й бит 1–й бит 0–й бит 
-┌───────┬────────┬────────┬────────┬───────┬───────┬───────┬───────┐ 
-│   ​∗ ​  ​│ ​   ∗   ​│ ​   ∗   ​│ ​   ∗   ​│ ​  ​∗ ​  ​│ ​  ​∗ ​  ​│ ​      ​│ ​  ​∗ ​  │ 
-└───────┴────────┴────────┴────────└───────┴───────┴───▲───┴───────┘ 
-Принтер в режиме ​ ON LINE (подключен к ПЭВМ): 0 ───────│ 
-Принтер в режиме OFF LINE (отключен от ПЭВМ): 1 ───────┘ 
-</​code>​ 
- 
-A теперь:​ включите принтер и вставьте бумагу… 
-\\ {{.examples:​1013-01.bas|}} \\ [[+tab|wmsxbpge>​1013-01.bas]] 
-<​code>​ 
-5 CLEAR 300 
-10 INPUT"​Слово";​A$ 
-15 WAIT &​H90,​2,​255 'Вы включите,​ наконец,​ принтер или нет? 
-20 A$=A$+CHR$(13)+CHR$(10) '​CHR$(13) - код возврата каретки;​ 
-21 ' ​                       CHR$(10) - код перевода строки 
-30 FOR I=1 TO LEN(A$) 
-35    OUT &​H90,​0:​OUT &​H90,​137 '​Инициализация принтера 
-40    B=ASC(MID$(A$,​I,​1)) 
-50    OUT &H91,B 
-60 NEXT I 
-</​code>​ 
- 
-{{anchor:​e1013-02}} __//​Пример 2//__. Считывание кода выведенного на экран символа:​ \\ {{.examples:​1013-02.bas|}} \\ [[+tab|wmsxbpge>​1013-02.bas]] 
-<​code>​ 
-10 K$=INKEY$:​IF K$=""​ THEN 10 ELSE PRINT K$; 
-20 PRINT INP(&​H98):​GOTO 10 
-</​code>​ 
- 
-Оператор ''​WAIT''​ используется сравнительно редко. Его синтаксис:​ 
-<WRAP group> 
-<WRAP half column> 
-<​code>​ 
-WAIT P,M[,C] 
-</​code>​ 
-</​WRAP>​ 
-<WRAP half column> 
-, 
-</​WRAP>​ 
-</​WRAP>​ 
-где: 
-  * ''​WAIT''​ ("​ожидать"​) — служебное слово; 
-  * P — арифметическое выражение,​ целая часть значения которого задаёт адрес порта; 
-  * M и C — арифметические выражения,​ целые части значений которых принадлежат отрезку [0,255]. 
- 
-Оператор ''​WAIT''​ "​заставляет"​ компьютер "​ожидать",​ пока результатом "​опроса"​ порта с указанным адресом не окажется число 0 (данный порт "​работает"​ в режиме //​чтения//​ ). Другими словами,​ этот оператор является "​бесконечным циклом",​ который "​ждёт",​ пока от порта ввода–вывода не придёт определённый сигнал. 
- 
-Вы можете прервать затянувшееся "​ожидание",​ нажав клавиши <​key>​CTRL+STOP</​key>​ (при этом Вы вернётесь в командный режим). 
- 
-Содержимое порта с указанным адресом заносится в некоторый регистр процессора Z–80, который мы назовём X. Далее содержимое регистра X комбинируется со значениями параметров M и С, по формуле:​ 
-<​code>​ 
-X = (X XOR C) AND M 
-</​code>​ 
-Если после этого содержимое регистра X окажется равным 0, то происходит "​выход из оператора ''​WAIT''"​. В противном случае порт вновь "​опрашивается",​ и процесс повторяется. 
- 
-Приведём таблицу–"​подсказку":​ 
-|  X  |0   ​0 ​  ​0 ​  ​0 ​  ​1 ​  ​1 ​  ​1 ​  ​1| ​   ​ 
-|  C  |0   ​0 ​  ​1 ​  ​1 ​  ​0 ​  ​0 ​  ​1 ​  1| 
-| | | 
-|  X XOR C  |0   ​0 ​  ​1 ​  ​1 ​  ​1 ​  ​1 ​  ​0 ​  0| 
-|  M  |0   ​1 ​  ​0 ​  ​1 ​  ​0 ​  ​1 ​  ​0 ​  1| 
-| | | 
-|  (X XOR C) AND M  |0   ​0 ​  ​0 ​  ​1 ​  ​0 ​  ​1 ​  ​0 ​  0| 
-Вопрос к читателю:​ Какой вид будет иметь таблица–"​подсказка"​ при отсутствии параметра C ? 
- 
-{{anchor:​e1013-03}} __//​Пример 3//__. \\ {{.examples:​1013-03.bas|}} \\ [[+tab|wmsxbpge>​1013-03.bas]] 
-<​code>​ 
-10 WAIT &​HAA,​64,​255 
- 
-(&​B∗1∗∗∗∗∗∗ XOR &​B11111111) AND &​B01000000 = &​B00000000 = 0 ! 
-</​code>​ 
-Эта программа закончит свою работу,​ если загорится индикатор "​CAPS"​. 
- 
-__//​Пример 4//__. 
-  * <​code>​WAIT &​H90,​2,​255 '​Ожидается ​ включение ​ принтера </​code>​ 
-  * <​code>​WAIT &​H90,​2,​0 ​  '​Ожидается ​ отключение ​ принтера</​code>​ 
- 
- 
-__//​Дополнение//​__. Работа с портом ввода–вывода с адресом &h0C 
- 
-Предварительно кратко опишем структуру порта &h0C… 
-<​code>​ 
-Старший ┌───┬───┬───┬───┬───┬───┬───┬───┐ Младший 
-  бит ​  │ ∗ │ ∗ │ ∗ │ ∗ │ ∗ │ ∗ │ ∗ │ ∗ │   ​бит 
-        └─▲─┴─▲─┴─▲─┴─▲─┴─▲─┴─▲─┴─▲─┴─▲─┘ 
-          │   ​│ ​  ​│ ​  ​│ ​  ​│ ​  ​│ ​  ​│ ​  ​└── Общий бит готовности сети 
-          │   ​│ ​ Не используются ​ │       (0: сеть готова) 
-          │   ​│ ​                  ​└────── Бит регистрации данных 
-          │   ​│ ​                          (0: данные поступили) 
-          │   ​└── Бит направления поступления информации (1: от учителя) 
-          └────── Бит направления поступления информации (1: от ученика) 
-</​code>​ 
- 
-А теперь два примера использования данного порта… 
- 
-__//​Пример 1//__. //​Посылка//​ байта по сети 
-<​code>​ 
-OUT_BYTE:: ​                 ; На входе в регистре A - данное 
- DI                  ; 
-        PUSH DE             ; 
-        LD   ​D,​A ​           ; 
- LD   ​A,​005H ​        ; OUT 9,5 - это запись байта в сетевое ОЗУ 
- OUT  (009H),​A ​      ; 
-OUT_B: ​ IN   ​A,​(0CH) ​       ; 
- AND  041H           ; 
- CP   ​040H ​          ; 
- JR   ​NZ,​OUT_B ​      ; Если сеть не готова,​ то ждем 
- LD   ​A,​D ​           ; 
- OUT  (00EH),​A ​      ; 
-        POP  DE             ; 
-        EI                  ; 
- RET                 ; 
-</​code>​ 
- 
-__//​Пример 2//__. //​Приём//​ байта из сети 
-<​code>​ 
-IN_BYTE:: ​                  ; На выходе в регистре A - данное 
- DI                  ; 
- ​ LD ​  ​A,​003H ​        ; OUT 9,3 - считывание байта из сетевого ОЗУ 
- OUT  (009H),​A ​      ; 
-IN_B:   ​IN ​  ​A,​(00CH) ​      ; 
- AND  083H           ; 
- CP   ​080H ​          ; 
- JR   ​NZ,​IN_B ​       ; Если сеть не готова,​ то ждем 
- IN   ​A,​(00EH) ​      ; 
-        EI                  ; 
- RET                 ; 
-</​code>​ 
- 
-====== Диск с примерами ====== 
- 
-{{.examples:​examples10.dsk|Загрузить образ диска}} 
- 
-[[+tab|wmsxbpged>​examples10.dsk|Открыть диск в WebMSX]] 
- 
- 
----- 
- 
-[<>] 
- 
- 
-{{tag>​MSX BASIC Book_msxbpg}} 
msx/basic_programming_guide/10.txt · Последние изменения: 2022-09-09 23:28 (внешнее изменение)