 2.7 Работа с внешней памятью

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

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

     В  языке Форт применяется механизм виртуальной внешней памяти, состоящей
 из  блоков по 1 К байт каждый. Блок идентифицируется номером - числом в диа-
 пазоне от 1 до 32767. В адресном пространстве форт-системы выделяется память
 под  буферный  пул,  рассчитанный на одновременное хранение одного или более
 блоков.  Каждый  буфер  помимо  памяти  для хранения собственно блока данных
 содержит номер блока и признак его измененности.

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

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

     Наконец,  слово  UPDATE  (изменить)  устанавливает  признак измененности
 последнего блока, к которому было адресовано обращение через слово BLOCK или
 BUFFER.  Таким образом, впоследствии этот блок будет автоматически переписан
 во внешнюю память.

     При реализации обмена с внешней памятью в качестве буферного пула обычно
 используется  связный  участок оперативный памяти. Пусть его начало задается
 константой   FIRST,  а  конец  -  адрес  байта,  следующего  за  последним,-
 константой  LIMIT.  (Если  пул  располагается  вплотную  к  концу  адресного
 пространства,   то   этот   следующий  адрес  равен  нулю!)  Буфера  в  пуле
 располагаются  подряд,  каждый  начинается  двух-байтной  ячейкой, в которой
 записывается  номер  приписанного  блока, причем старший разряд используется
 под признак измененности. Далее идет буферная память для блока размером 1024
 байта, завершается буфер еще одной служебной ячейкой, в которой записан ноль
 (ее  назначение  указано  в п.2.8). Пусть переменные PREV и USE указывают на
 текущий  используемый  буфер и следующий, который будет выдан при запросе на
 свободный  буфер.  Определим  слово  +BUF,  которое  вычисляет адрес буфера,
 следующего  в  пуле  за  переданным, и возвращает признак несовпадения его с
 текущим:

          : +BUF ( A1 ---> A2,F )  1024  +  4  +
            DUP  LIMIT  -  IF  DROP  FIRST  THEN
            DUP  PREV  @  -  ;

 Пусть  служебные  слова RBLK A,N --> и WBLK A,N --> выполняют чтение блока с
 указанным  номером  в  заданную  область оперативной памяти и запись из нее.
 Тогда с учетом принятых условий слова, выполняющие работу с внешней памятью,
 можно задать так:

          : BUFFER ( N ---> A  ПРИПИСАТЬ БЛОКУ N БУФЕР)
            USE  @  DUP  >R  ( ВЕРНЕМ ЭТОТ БУФЕР)
            BEGIN +BUF UNTIL  USE ! ( УСТАНАВЛ.СЛЕДУЮЩИЙ)
            R@  @  0<  ( ПРИЗНАК ИЗМЕНЕННОСТИ?)
            IF  R@  2+  R@  @  32767  AND  WBLK  THEN
            R@  !  ( ПРИПИСАЛИ НОВОМУ БЛОКУ)
            R@  PREV  !  R>  2+  ;
          : BLOCK ( N ---> A:АДРЕС БУФЕРА С ДАННЫМИ БЛОКА)
            >R PREV @ DUP R@ - DUP + ( ТЕКУЩИЙ - ТОТ ЖЕ?)
            IF ( НЕТ)  BEGIN +BUF  0=
             IF  DROP  R@  BUFFER DUP R@  RBLK  2- THEN
             DUP @  R@  -  DUP  +  0= UNTIL  DUP  PREV !
            THEN  R>  DROP  2+  ;
          : UPDATE ( ---> )  PREV @ @  32768 OR  PREV @ ! ;

     Для  записи  всех  измененных  буферов  во  внешнюю  память служит слово
 SAVE-BUFFERS (сохранить буфера):

          : SAVE-BUFFERS ( ---> )
            LIMIT  FIRST  DO  I  @  32768  AND
               IF  I  @  32767  AND  DUP  I  !
               I  2+  SWAP  WBLK  THEN
            1028  +LOOP  ;

 При  исполнении  слова SAVE-BUFFERS все буфера остаются приписанными прежним
 блокам.  Слово  FLUSH  (очистить)  переписывает  все  исправленные  блоки во
 внешнюю   память   и  освобождает  буфера.  Многие  реализации  имеют  слово
 EMPTY-BUFFERS  (опустошить  буфера),  которое  освобождает  буферный пул, не
 переписывая исправленные блоки:

          : EMPTY-BUFFERS ( ---> )
            LIMIT  FIRST  DO  0  I  @  !  1028  +LOOP  ;
          : FLUSH ( ---> )  SAVE-BUFFERS  EMPTY-BUFFERS  ;

     Внешняя   память  форт-системы  в  основном  используется  для  хранения
 форт-текстов.  Блок  внешней  памяти  с  форт-текстом  называется  экраном и
 условно  разбивается  на 16 строк по 64 литеры в каждой. Такой формат экрана
 сложился традиционно и закреплен в стандарте.

     Программист  создает  и  исправляет  экраны во внешней памяти, используя
 встроенный  редактор  форт-системы.  Как  и в случае встроенного ассемблера,
 стандарт  не  определяет конкретный вид и состав его команд, поскольку это в
 значительной    степени    определяется    функциональными   возможностями и
 характеристиками  конкретных  терминалов  и средствами работы с ними. Обычно
 слова-команды текстового редактора составляют отдельный список слов с именем
 EDITOR   (редактор),   базирующийся   на   списке   FORTH.   Для  распечатки
 редактируемого   экрана  на  терминале  чаще  всего  используют  слово  LIST
 (распечатать),  которое,  кроме  того,  сохраняет  номер  экрана в служебной
 переменной SCR:

          : LIST ( N ---> ) DUP SCR !
            CR  ." ЭКРАН "  DUP  .  BLOCK
            16  0  DO  DUP  I  64  *  +
            CR  I  3  .R   SPACE  64  TYPE  LOOP  DROP  ;

 Вначале  печатается  номер  данного  экрана,  затем его строки. Перед каждой
 строкой  печатается  ее  номер - число в диапазоне от 0 до 15. По завершении
 редактирования  исправленные  экраны можно записать во внешнюю память словом
 FLUSH.

