(*~\Глагол\ПриложенияLink\ПГ\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                             ОТДЕЛ МР;
(*============================================================================*)
(* НАЗНАЧЕНИЕ:                                                                *)
(*             управление Машинными Регистрами                                *)
(* ПРИМЕЧАНИЯ:                                                                *)
(*   Г(уляй) регистры выполняют те же задачи, что и М(ашинные) регистры.      *)
(*   Названия Г регистров совпадают с названиями М регистров. Значение Г      *)
(*   регистра в разные моменты времени может находится или в допустимом М     *)
(*   регистре или во В(нешнем) регистре (в стеке переменных).                 *)
(*============================================================================*)

ИСПОЛЬЗУЕТ
  ОО;

ПОСТ
        (* названия 32-х разрядных M-регистров
                                 процессора i386 М и их машинные коды. Из МР. *)
  EAX=0;  (* арифметический *)
  ECX=1;  (* арифметический *)
  EDX=2;  (* арифметический *)
  EBX=3;  (* арифметический *)

  ESP=4;        (* стэковые *)
  EBP=5;        (* стэковые *)
  ESI=6;  (* индексный *)
  EDI=7;  (* индексный *)

  СВО= -1;(* код для обозначения свободного регистра *)

  МРеги- = {EAX,ECX,EDX,EBX,ESI,EDI}; (* основные М-регистры *)

КвоМРегов=6;

  СтекМРеги-={ESP,EBP};               (* М-регистры для работы со стеком *)

КвоСтекМРегов=2;

  ВсеМРеги-   = МРеги + СтекМРеги;

КвоВсехМРегов = КвоМРегов + КвоСтекМРегов;

  ЯчМРеги-={EAX,ECX,EDX,EBX};        (* ячейковые М-регистры (арифметические) *)

КвоЯчМРегов =4;
КвоМатМРегов=8;  (* количество математических 80 битных М-регистров (FPU i87) *)

  (*
   * количество В(нешних) 32 битных регистров, которые располагаются в памяти;
   * их всегда должно быть > 3*КвоМатМРегов, для того, чтобы иметь
   * возможность сохранять все математические 80 битные М регистры (3*32 ~> 80)
   *)
КвоВРегов = 20 + 3*КвоМатМРегов;
                                  (* количество Г-регистров *)
КвоГРегов = КвоМРегов + КвоВРегов;

ВИД
                                    (* описание Г-регистра *)
  ГРег = НАБОР
    вМ:КЛЮЧ;  (* ВКЛ, если значение регистра расположено в М регистре *)
    мв:ЦЕЛ;   (* если вМ=ВКЛ, то название М регистра, иначе номер В регистра,
               * в котором расположено значение регистра *)
    допМРеги:МНОЖ; (* множество названий допустимых М регистров, в которые
                    * можно поместить значение регистра *)
    эпоха:ЦЕЛ (* эпоха обращения к регистру, т.е. у давно не используемого
               * регистра меньшее значение *)
  КОН;

  РядГРегов=РЯД КвоГРегов ИЗ ГРег;

  (*
   * ряд для перевода названия М регистра в номер того Г регистра (или СВО),
   * который обслуживает этот М регистр.
   *)
  РядГдляМ=РЯД КвоВсехМРегов ИЗ ЦЕЛ;

  (*
   * ряд для перевода номера В регистра в номер того Г регистра (или СВО),
   * который обслуживает этот В регистр. Если значение > КвоГРегов,
   * то это математический регистр с номером = значение - КвоГРегов.
   *)
  РядГдляВ=РЯД КвоВРегов ИЗ ЦЕЛ;

  НаборГРегов- = НАБОР
    ГРеги:РядГРегов;
    ГдляМ:РядГдляМ;
    МатМРегов:ЦЕЛ;
  КОН;

  (*
   * вид задач, которые создают машинный код для пересылки данных между
   *  М регистрами, В регистрами и С(тэком)
   *)
  ЗКодМВ=ЗАДАЧА (м,в:ЦЕЛ;мВв:КЛЮЧ);
  ЗКодММ=ЗАДАЧА (изм,вм:ЦЕЛ);
  ЗКодМС=ЗАДАЧА (м:ЦЕЛ;мВс:КЛЮЧ);
  ЗКодМатемМВ=ЗАДАЧА (в:ЦЕЛ;мВв:КЛЮЧ);

ПЕР
  КодМВ      :ЗКодМВ;
  КодМвМ,
  КодОбменМсМ:ЗКодММ;
  КодМС      :ЗКодМС;
  КодМатемМВ :ЗКодМатемМВ;

  ГРеги:РядГРегов;
  ГдляМ:РядГдляМ;
  ГдляВ:РядГдляВ;
  эпоха:ЦЕЛ;
                      (* наибольший номер используемого В регистра *)
  послВРег:ЦЕЛ;
                      (* задействовано математических М регистров *)
  МатМРегов:ЦЕЛ;


(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА СледЭпоха(г:ЦЕЛ);
УКАЗ
  ГРеги[г].эпоха:=эпоха;
  УВЕЛИЧИТЬ(эпоха)
КОН СледЭпоха;

(*-----------------------------------------локальная ЗАДАЧА-------------------*)
ЗАДАЧА СтекРег-(г:ЦЕЛ):КЛЮЧ;
УКАЗ
  ВОЗВРАТ ГРеги[г].вМ И (ГРеги[г].мв В СтекМРеги)
КОН СтекРег;

ЗАДАЧА РегСейчасМ-(г:ЦЕЛ):КЛЮЧ;
УКАЗ
  ВОЗВРАТ ГРеги[г].вМ
КОН РегСейчасМ;

ЗАДАЧА РегМВ-(г:ЦЕЛ):ЦЕЛ;
УКАЗ
  ВОЗВРАТ ГРеги[г].мв
КОН РегМВ;

ЗАДАЧА СейчасДопМРеги-(г:ЦЕЛ):МНОЖ;
УКАЗ
  ВОЗВРАТ ГРеги[г].допМРеги
КОН СейчасДопМРеги;

ЗАДАЧА УстДопМРеги-(г:ЦЕЛ; мреги:МНОЖ);
УКАЗ
  ГРеги[г].допМРеги:=мреги
КОН УстДопМРеги;

(******************************************************************************)
ЗАДАЧА Проверка-;
(* вызывается после вычисления выражения; проверяет, свободны ли регистры *)
ПЕР
  р:ЦЕЛ;
УКАЗ
  р:=0;
  ПОКА р < КвоГРегов ВЫП
    ПРОВЕРИТЬ(ГРеги[р].вМ = ОТКЛ);
    ПРОВЕРИТЬ(ГРеги[р].мв = СВО);
    ЕСЛИ р < КвоВсехМРегов ТО ПРОВЕРИТЬ(ГдляМ[р] = СВО) КОН;
    ЕСЛИ р < КвоВРегов     ТО ПРОВЕРИТЬ(ГдляВ[р] = СВО) КОН;
    УВЕЛИЧИТЬ(р)
  КОН
КОН Проверка;

(******************************************************************************)
ЗАДАЧА СбросВРегов-;
(* вызывается в начале задачи; обнуляет число используемых В регистров *)
УКАЗ
  послВРег:=-1
КОН СбросВРегов;

ЗАДАЧА НужноПамДляВРегов-():ЦЕЛ;
(* возвращает кол-во ячеек памяти необходимое для исп. В регистров *)
УКАЗ
  ВОЗВРАТ (послВРег+1)*4
КОН НужноПамДляВРегов;

ЗАДАЧА ЗанятьВРег-():ЦЕЛ;
(* распределяет свободный В регистр *)
ПЕР
  в:ЦЕЛ;
УКАЗ
  в:=0;
  ПОКА ГдляВ[в] # СВО ВЫП
    УВЕЛИЧИТЬ(в);
    ЕСЛИ в=КвоВРегов ТО
      ОО.Ошибка(ОО.НЕТ_РЕГИСТРОВ)
    КОН
  КОН;
  ЕСЛИ в > послВРег ТО послВРег:=в КОН;
  ГдляВ[в]:=СВО-1; (* # СВО И # ГРегу *)
  ВОЗВРАТ в
КОН ЗанятьВРег;

ЗАДАЧА ОсвободитьВРег-(в:ЦЕЛ);
УКАЗ
  ГдляВ[в]:=СВО
КОН ОсвободитьВРег;

(******************************************************************************)
ЗАДАЧА ЗанятьВРег64-():ЦЕЛ;
(* распределяет 8 смежных ячеек в памяти В регистров *)
ПЕР
  в,квоСВО:ЦЕЛ;
УКАЗ
  квоСВО:=0;
  в:=0;
  КОЛЬЦО
    ЕСЛИ ГдляВ[в] = СВО ТО
      УВЕЛИЧИТЬ(квоСВО);
      ЕСЛИ квоСВО = 2 ТО
        ВЫХОД
      КОН
    ИНАЧЕ
      квоСВО:=0
    КОН;
    УВЕЛИЧИТЬ(в);
    ЕСЛИ в = КвоВРегов ТО
      ОО.Ошибка(ОО.НЕТ_РЕГИСТРОВ)
    КОН
  КОН;
  ЕСЛИ в > послВРег ТО послВРег:=в КОН;
  ГдляВ[в  ]:=СВО-1; (* # СВО И # ГРегу *)
  ГдляВ[в-1]:=СВО-1; (* # СВО И # ГРегу *)
  ВОЗВРАТ в
КОН ЗанятьВРег64;

ЗАДАЧА ОсвободитьВРег64-(в:ЦЕЛ);
УКАЗ
  ГдляВ[в  ]:=СВО;
  ГдляВ[в-1]:=СВО
КОН ОсвободитьВРег64;

(******************************************************************************)
ЗАДАЧА СбросМатМРеги-;
УКАЗ
  МатМРегов:=0
КОН СбросМатМРеги;

ЗАДАЧА УвМатМРегов-;
УКАЗ
  УВЕЛИЧИТЬ(МатМРегов);
  ЕСЛИ МатМРегов >= КвоМатМРегов ТО
    ОО.Ошибка(ОО.НЕТ_ВЕЩ_РЕГИСТРОВ)
  КОН
КОН УвМатМРегов;

ЗАДАЧА УмМатМРегов-;
УКАЗ
  ПРОВЕРИТЬ(МатМРегов # 0);
  УМЕНЬШИТЬ(МатМРегов)
КОН УмМатМРегов;

(******************************************************************************)
ЗАДАЧА СтарыйМРег():ЦЕЛ;
(* возвращает свободный (или давно не используемый) М регистр *)
ПЕР
  м,г,минэпм,минэп:ЦЕЛ;
УКАЗ
  м:=EAX;
  минэп:=эпоха;
  КОЛЬЦО
    г:=ГдляМ[м];
    ЕСЛИ г = СВО ТО
      ВОЗВРАТ м
    КОН;
    (* на всякий случай ищем давно не используемый М регистр *)
    ЕСЛИ ГРеги[г].эпоха < минэп ТО
      минэп:=ГРеги[г].эпоха;
      минэпм:=м
    КОН;
    ЕСЛИ  м = EBX ТО
      м:=ESI         (* перепрыгиваем через ESP и EBP *)
    АЕСЛИ м = EDI ТО
      (* обошли все М регистры и не нашли свободного регистра,
         тогда возвращаем давно не используемый М регистр *)
      ВОЗВРАТ минэпм
    ИНАЧЕ
      УВЕЛИЧИТЬ(м)
    КОН
  КОН
КОН СтарыйМРег;

(******************************************************************************)
ЗАДАЧА СтарыйЯчМРег():ЦЕЛ;
(* возвращает свободный (или давно не используемый) ячейковый М регистр *)
ПЕР
  м,г,минэпм,минэп:ЦЕЛ;
УКАЗ
  м:=EAX;
  минэп:=эпоха;
  КОЛЬЦО
    г:=ГдляМ[м];
    ЕСЛИ г = СВО ТО
      ВОЗВРАТ м
    КОН;
    (* на всякий случай ищем давно не используемый М регистр *)
    ЕСЛИ ГРеги[г].эпоха < минэп ТО
      минэп:=ГРеги[г].эпоха;
      минэпм:=м;
    КОН;
    ЕСЛИ м = EBX ТО
      (* обошли все регистры и не нашли свободного регистра,
         тогда возвращаем давно не используемый регистр *)
      ВОЗВРАТ минэпм
    ИНАЧЕ
      УВЕЛИЧИТЬ(м)
    КОН
  КОН
КОН СтарыйЯчМРег;

(******************************************************************************)
ЗАДАЧА ГРегВоВРег(г:ЦЕЛ);
(* переносит содержимое Г регистра во В регистр *)
ПЕР
  в,м:ЦЕЛ;
УКАЗ
  ЕСЛИ ГРеги[г].вМ ТО
    м:=ГРеги[г].мв;
    в:=ЗанятьВРег();
    КодМВ(м,в,ВКЛ);
    ГдляМ[м]:=СВО;
    ГдляВ[в]:=г;
    ГРеги[г].мв:=в;
    ГРеги[г].вМ:=ОТКЛ
  КОН
КОН ГРегВоВРег;

(******************************************************************************)
ЗАДАЧА МатМРегВоМатВРег(матРег:ЦЕЛ);
(* распределяет 10 (реально 12) смежных ячеек в памяти В регистров и
 * выталкивает содержимое вершины М мат. стека в В регистры *)
ПЕР
  в,квоСВО:ЦЕЛ;
УКАЗ
  УВЕЛИЧИТЬ(матРег,КвоГРегов); (* чтобы матРег # ГРегам *)
  квоСВО:=0;
  в:=0;
  КОЛЬЦО
    ЕСЛИ ГдляВ[в] = СВО ТО
      УВЕЛИЧИТЬ(квоСВО);
      ЕСЛИ квоСВО = 3 ТО
        ВЫХОД
      КОН
    ИНАЧЕ
      квоСВО:=0
    КОН;
    УВЕЛИЧИТЬ(в);
    ЕСЛИ в = КвоВРегов ТО
      ОО.Ошибка(ОО.НЕТ_РЕГИСТРОВ)
    КОН
  КОН;
  ЕСЛИ в > послВРег ТО послВРег:=в КОН;
  ГдляВ[в  ]:=матРег;
  ГдляВ[в-1]:=матРег;
  ГдляВ[в-2]:=матРег;
  УмМатМРегов;
  КодМатемМВ(в,ВКЛ)
КОН МатМРегВоМатВРег;

(******************************************************************************)
ЗАДАЧА МатВРегВоМатМРег(матРег:ЦЕЛ);
(* заталкивает содержимое требуемого мат. регистра из В регистров на
 * вершину М мат. стека *)
ПЕР
  в:ЦЕЛ;
УКАЗ
  УВЕЛИЧИТЬ(матРег,КвоГРегов); (* чтобы матРег # ГРегам *)
  в:=0;
  ПОКА ГдляВ[в] # матРег ВЫП
    УВЕЛИЧИТЬ(в);
    ПРОВЕРИТЬ(в # КвоВРегов)
  КОН;
  УвМатМРегов;
  УВЕЛИЧИТЬ(в,2);
  КодМатемМВ(в,ОТКЛ);
  ГдляВ[в  ]:=СВО;
  ГдляВ[в-1]:=СВО;
  ГдляВ[в-2]:=СВО
КОН МатВРегВоМатМРег;

(******************************************************************************)
ЗАДАЧА МРегВоВРег(м:ЦЕЛ);
ПЕР
  г:ЦЕЛ;
УКАЗ
  г:=ГдляМ[м];
  ЕСЛИ г # СВО ТО
    ГРегВоВРег(г)
  КОН
КОН МРегВоВРег;

(******************************************************************************)
ЗАДАЧА РегВоДопМРег-(г:ЦЕЛ):ЦЕЛ;
(* Цель:  переносит содержимое регистра <г> в допустимый М регистр
 * Прим:  возвращает М регистр, содержащий значение регистра *)
ПЕР
  в,м:ЦЕЛ;
  допМРеги:МНОЖ;
УКАЗ
  ЕСЛИ ГРеги[г].вМ ТО
    СледЭпоха(г)
  ИНАЧЕ
    допМРеги:=ГРеги[г].допМРеги;
    ПРОВЕРИТЬ(допМРеги # {});
    ЕСЛИ допМРеги = МРеги ТО
      м:=СтарыйМРег()
    АЕСЛИ допМРеги = ЯчМРеги ТО
      м:=СтарыйЯчМРег()
    ИНАЧЕ
      м:=0;
      ПОКА НЕ (м В допМРеги) ВЫП УВЕЛИЧИТЬ(м) КОН
    КОН;
    МРегВоВРег(м);
    в:=ГРеги[г].мв;
    КодМВ(м,в,ОТКЛ); (* в -> м *)
    ГдляВ[в]:=СВО;
    ГдляМ[м]:=г;
    ГРеги[г].мв:=м;
    ГРеги[г].вМ:=ВКЛ;
    СледЭпоха(г)
  КОН;
  ВОЗВРАТ ГРеги[г].мв
КОН РегВоДопМРег;

(******************************************************************************)
ЗАДАЧА ЗанятьОпредРег-(допМРеги:МНОЖ):ЦЕЛ;
(* Цель:  распределяет свободный Г регистр под допустимые М регистры
 * После: старый М регистр готов к приему значений *)
ПЕР
  г,м:ЦЕЛ;
УКАЗ
  ПРОВЕРИТЬ(допМРеги # {});
  г:=0;
  ПОКА ГРеги[г].мв # СВО ВЫП
    УВЕЛИЧИТЬ(г);
    ЕСЛИ г = КвоГРегов ТО
      ОО.Ошибка(ОО.НЕТ_РЕГИСТРОВ)
    КОН
  КОН;
  ЕСЛИ допМРеги = МРеги ТО
    м:=СтарыйМРег()
  АЕСЛИ допМРеги = ЯчМРеги ТО
    м:=СтарыйЯчМРег()
  ИНАЧЕ
    м:=0;
    ПОКА НЕ (м В допМРеги) ВЫП УВЕЛИЧИТЬ(м) КОН
  КОН;
  ЕСЛИ м В МРеги ТО (* для ESP, EBP не занимаем М регистр *)
    МРегВоВРег(м)
  КОН;
  ГдляМ[м]:=г;
  ГРеги[г].мв:=м;
  ГРеги[г].вМ:=ВКЛ;
  ГРеги[г].допМРеги:=допМРеги;
  СледЭпоха(г);
  ВОЗВРАТ г
КОН ЗанятьОпредРег;

(******************************************************************************)
ЗАДАЧА ЗанятьРег-():ЦЕЛ;
(* распределяет свободный Г регистр под М регистр *)
УКАЗ
  ВОЗВРАТ ЗанятьОпредРег(МРеги)
КОН ЗанятьРег;

(******************************************************************************)
ЗАДАЧА ЗанятьЯчРег-():ЦЕЛ;
(* распределяет свободный Г регистр под ячейковый М регистр *)
УКАЗ
  ВОЗВРАТ ЗанятьОпредРег(ЯчМРеги)
КОН ЗанятьЯчРег;

(******************************************************************************)
ЗАДАЧА ОсвободитьРег-(г+:ЦЕЛ);
(* освобождает регистр *)
УКАЗ
  ЕСЛИ г # СВО ТО
    ПРОВЕРИТЬ((г>=0) И (г<КвоГРегов));
    ЕСЛИ ГРеги[г].вМ ТО
      ГдляМ[ГРеги[г].мв]:=СВО
    ИНАЧЕ
      ГдляВ[ГРеги[г].мв]:=СВО
    КОН;
    ГРеги[г].мв:=СВО;
    ГРеги[г].вМ:=ОТКЛ;
    г:=СВО
  КОН
КОН ОсвободитьРег;

(******************************************************************************)
ЗАДАЧА РегВОпредМРег-(г,м:ЦЕЛ);
(* переносит значение регистра в определенный М регистр *)
ПЕР
  муг:ЦЕЛ; (* М регистр со старым значением <г> *)
  гсм:ЦЕЛ; (* тот Г регистр, который занимал <м> регистр *)
УКАЗ
  ПРОВЕРИТЬ(м В МРеги);
  муг:=РегВоДопМРег(г);
  ЕСЛИ муг # м ТО
    гсм:=ГдляМ[м];
    ЕСЛИ (гсм # СВО) И (муг В ГРеги[гсм].допМРеги) И (муг В МРеги) ТО
      (* можно поменять местами *)
      КодОбменМсМ(муг,м);
      ГРеги[гсм].мв:=муг;
      ГдляМ[муг]:=гсм
    ИНАЧЕ
      ЕСЛИ гсм # СВО ТО ГРегВоВРег(гсм) КОН;
      КодМвМ(муг,м);
      ГдляМ[муг]:=СВО
    КОН;
    ГдляМ[м]:=г;
    ГРеги[г].мв:=м
  КОН;
  ГРеги[г].допМРеги:={м};
  СледЭпоха(г)
КОН РегВОпредМРег;

(******************************************************************************)
ЗАДАЧА РегВоМРег-(г:ЦЕЛ);
(* Цель:  переносит значение регистра <г> в М регистр принадлежащий 'МРеги' *)
ПЕР
  м:ЦЕЛ;
УКАЗ
  ЕСЛИ ГРеги[г].вМ ТО
    ЕСЛИ ГРеги[г].мв В МРеги ТО
      СледЭпоха(г)
    ИНАЧЕ (* переписываем значение ESP,EBP в осн. М регистр *)
      РегВОпредМРег(г,СтарыйМРег())
    КОН;
    ГРеги[г].допМРеги:=МРеги
  ИНАЧЕ
    ГРеги[г].допМРеги:=МРеги;
    м:=РегВоДопМРег(г)
  КОН
КОН РегВоМРег;

(******************************************************************************)
ЗАДАЧА РегВоЯчМРег-(г:ЦЕЛ);
(* Цель:  переносит значение регистра <г> в М регистр принадлежащий 'ЯчМРеги' *)
ПЕР
  м,ячм,ячг:ЦЕЛ;
УКАЗ
  ЕСЛИ ГРеги[г].вМ ТО
    ЕСЛИ ГРеги[г].мв В ЯчМРеги ТО
      СледЭпоха(г)
    ИНАЧЕ
      ячм:=EAX; (* пробегаем по всем ячейковым М регистрам *)
      м:=СВО;   (* подобранный новый М регистр *)
      КОЛЬЦО
        ячг:=ГдляМ[ячм];
        ЕСЛИ ячг = СВО ТО
          м:=ячм;
          ВЫХОД
        КОН;
        ЕСЛИ ГРеги[г].мв В ГРеги[ячг].допМРеги ТО
          м:=ячм
        КОН;
        ЕСЛИ ячм = EBX ТО
          ЕСЛИ м = СВО ТО
            м:=СтарыйЯчМРег()
          КОН;
          ВЫХОД
        КОН;
        УВЕЛИЧИТЬ(ячм)
      КОН;
      РегВОпредМРег(г,м)
    КОН;
    ГРеги[г].допМРеги:=ЯчМРеги
  ИНАЧЕ
    ГРеги[г].допМРеги:=ЯчМРеги;
    м:=РегВоДопМРег(г)
  КОН
КОН РегВоЯчМРег;

(******************************************************************************)
ЗАДАЧА ВходВЗадачу-(реги+:НаборГРегов);
(* сохраняет все используемые М регистры в стеке *)
ПЕР
  м,г:ЦЕЛ;
УКАЗ
  МРегВоВРег(EAX); (* чтобы был свободным для ответа *)
  реги.ГРеги:=ГРеги;
  реги.ГдляМ:=ГдляМ;
  реги.МатМРегов:=МатМРегов;
  г:=0;
  ПОКА г < КвоГРегов ВЫП
    ЕСЛИ ГРеги[г].вМ ТО
      м:=ГРеги[г].мв;
      КодМС(м,ВКЛ);
      ГдляМ[м]:=СВО;
      ГРеги[г].вМ:=ОТКЛ;
      ГРеги[г].мв:=СВО
    КОН;
    УВЕЛИЧИТЬ(г)
  КОН;
  ПОКА МатМРегов > 0 ВЫП
    МатМРегВоМатВРег(МатМРегов)
  КОН
КОН ВходВЗадачу;

(******************************************************************************)
ЗАДАЧА ВыходИзЗадачи-(реги+:НаборГРегов; вещОтв:КЛЮЧ);
(* восстанавливает все используемые М регистры из стека *)
ПЕР
  г:ЦЕЛ;
УКАЗ
  СбросМатМРеги;
  ЕСЛИ вещОтв ТО УвМатМРегов КОН;
  ЕСЛИ реги.МатМРегов > 0 ТО (* были МатМРеги *)
    ЕСЛИ вещОтв ТО МатМРегВоМатВРег(0) КОН; (* сохраним ответ в памяти *)
    ПОКА МатМРегов < реги.МатМРегов ВЫП
      МатВРегВоМатМРег(МатМРегов+1)
    КОН;
    ЕСЛИ вещОтв ТО МатВРегВоМатМРег(0) КОН  (* восстановим ответ в ST0 *)
  КОН;
  ГРеги:=реги.ГРеги;
  ГдляМ:=реги.ГдляМ;
  г:=КвоГРегов;
  ПОКА г > 0 ВЫП
    УМЕНЬШИТЬ(г);
    ЕСЛИ ГРеги[г].вМ ТО
      КодМС(ГРеги[г].мв,ОТКЛ)
    КОН
  КОН
КОН ВыходИзЗадачи;

(******************************************************************************)
ЗАДАЧА Подготовить-(кодМВ:ЗКодМВ;кодОбменМсМ,кодМвМ:ЗКодММ;
                    кодМС:ЗКодМС;кодМатемМВ:ЗКодМатемМВ);
ПЕР
  р:ЦЕЛ;
УКАЗ
  КодМВ:=кодМВ;
  КодОбменМсМ:=кодОбменМсМ;
  КодМвМ:=кодМвМ;
  КодМС:=кодМС;
  КодМатемМВ:=кодМатемМВ;
  р:=0;
  ПОКА р < КвоГРегов ВЫП
    ГРеги[р].вМ:=ОТКЛ;
    ГРеги[р].мв:=СВО;
    ЕСЛИ р < КвоВсехМРегов ТО ГдляМ[р]:=СВО КОН;
    ЕСЛИ р < КвоВРегов     ТО ГдляВ[р]:=СВО КОН;
    УВЕЛИЧИТЬ(р)
  КОН;
  эпоха:=0
КОН Подготовить;

КОН МР.
