Связь с администрацией сайта:       

demo

Среди толпы я одинок

4. Как кодируются инструкции в Z-машине

We do but teach bloody instructions
Which, being taught, return to plague th' inventor
Shakespeare, Macbeth
4.1 Инструкции
Одна команда Z-машины состоит из следующих разделов (в указанном порядке):
  Opcode 1 или 2 байта
  (типы операндов) 1 или 2 байта: 4 или 8 2-битовых полей
  операнды между 0 и 8 из них: каждый 1 или 2 байта
  (изменяемый) 1 байт
  (Branch offset) 1 или 2 байта
  (Текст для печати) кодированные строки (неограниченной длины)
Разделяющие квадратные скобки не присутствуют во всех Opcode. (Некоторые Opcode принимают как " Store " и " Branch ".)
 
4.2 Типы операндов
Есть четыре типа операндов. Они часто задаются числом, хранящегося в 2-х двоичных цифр:
  $$ 00 Большая постоянная(Large constant) ( от 0 до 65535) 2 байта
  $$ 01 малая константа(Small constant) ( от 0 до 255) 1 байт
  $$ 10 Переменная(Variable) 1 байт
  $$ 11 Пропущено вообще(Omitted altogether) 0 байт
4.2.1
Большие постоянные, как и все 2-байтовых слов данных в Z-машине, сохраняются с наиболее значимого байта (например , $2478 хранится в виде $24 с последующим $78 ). А «большая константа» на самом деле может иметь небольшое значение.
4.2.2
Номер переменной $00 относится к вершине стека, $01 до $0F означают локальные переменные текущей подпрограммы, и $10 до $ff означают глобальные переменные. Это незаконно ,чтобы ссылаться на локальные переменные , которые не существуют для текущей подпрограммы (не может быть даже нет).
4.2.3
Тип «Переменная» на самом деле означает «переменную по значению». Некоторые команды принимают в качестве операнда в «переменную по ссылке»: например, вкл имеет один операнд, ссылочный номер переменной приращения. Этот операнд обычно имеет тип «малая константа» (и Inform автоматически компонует строку как @INC, получается путем записи операнда, получается как малая константа со значением - ссылочный номер переменной).
4.3 Форма и стандарт операнда COUNT
Каждая команда имеет вид (long, short, extended или variable) и подсчета операндов (0OP, 1OP, 2OP или VAR). Если верхние два бита кода операции являются $$ 11, то форма является variable; если $$ 10, форма short. Если код операции 190 ( $ BE в шестнадцатеричном формате) и версии 5 или более поздней версии, форма "extended". В противном случае, форма " long".
4.3.1
В short форме, биты 4 и 5 опкода байта дают тип операнда, как указано выше. Если это $ 11 , то отсчет операндов равен 0OP; в противном случае, 1OP. В любом случае количество кода операции приведены в нижних 4 битах.
4.3.2
В long форме граф операндов всегда 2OP. Число опкода дается в 5 нижних битах.
4.3.3
В variable форме, если бит 5 равен 0, то счетчик равен 2 OP; если он равен 1, то счетчик равен  VAR. Число опкода дается в 5 нижних битах.
4.3.4
В extended виде, количество операндов равен VAR. Число опкода дается во втором байте кода операции.
4.4 Указание типов операнда
Далее указаны типы операндов.
4.4.1
В short форме, биты 4 и 5 опкода дают тип.
4.4.2
В long форме, бит 6 опкода дает тип первого операнда, бит 5 секунды. Значение 0 означает малую постоянную и 1 означает переменную. (Если инструкции 2OP нужна большая константа в качестве операнда, то он должен быть собран в переменной, а не long форме)
4.4.3
В variable или extended формах, байт из 4 -х типов операндов дается следующим образом. Он содержит 4 2-битовых полей: биты 6 и 7 первого поля, биты 0 и 1 четвертое. Значения операндов типа, как описано выше. После того, как один тип был дан как " Omitted", все последующие должны быть соответствующими. Пример: $$ 00101111 означает большую постоянную как variable (и без третьего или четвертого опкода).
4.4.3.1
В частном случае "double variable " VAR опкоды call_vs2 и call_vn2 (номера опкодов 12 и 26), дается второй байт типов, содержащий типы в течение следующих четырех операндов.
4.5 Операнды
Операнды приведены в следующем. Операнд подсчеты 0OP, 1OP или 2 OP требуют 0, 1 или 2 операнда. 
4.5.1
Обратите внимание, что только call_vs2 и call_vn2 может иметь более 4 операндов, и ни одна команда не может иметь более 8.
4.5.2
Opcode операнды всегда вычисляются от первого до последнего - этот порядок важен, когда указатель стека появляется в качестве аргумента. Таким образом:
@sub sp sp -> i;
 вычитает стек элемента из верхнего элемента стека второго сверху.
4.6 Store
"Store" инструкции возвращают значение: например, мул умножает свои два операнда вместе. Такие инструкции должны следовать правилу одного байта, давая переменное число, куда поместить результат.
4.7 Ветви(Branch)
Инструкции, которые проверяют состояние, называются «branch»(ветвь) инструкции.  Информация «ветвь» хранится в одном или двух байтах, что указывает на то, что делать с результатом теста. Если бит 7 первого байта равен 0, то ветвь возникает, когда условие было ложным; если 1, то ветвь идет по истине. Если установлен бит 6, то ветвь занимает только 1 байт, а "offset " находится в диапазоне от 0 до 63, в приведенных в нижних 6 бит. Если бит 6 чист, то смещение является подписанным под 14-битный номером, указанный в битах от 0 до 5 первого байта последующие все 8, вторым.
4.7.1
Смещение 0 означает «возвращение «ложно» из текущей подпрограммы», а 1 означает, что «возвращает истину от текущей подпрограммы».
4.7.2
В противном случае ветвь переходит в выполнение инструкции по адресу
  Адрес после ветвления данных + смещение - 2.
4.8 Текстовые Опкоды(Opcode)
Два опкода, print и print_ret , сопровождаются текстовой строкой. Это хранится в соответствии с обычными правилами: в частности, выполнение продолжается после последнего 2-байтового слово текста (один с верхним битом).
Примечание
Некоторые опкоды имеют тип VAR только потому, что доступные коды для других типов отсутствуют; print_char , например.
Inform ассемблер может собрать ветви в любой форме, хотя программист всегда должен использовать long форму, если нет другой причины её не использовать. Informавтоматически оптимизирует операторы ветвления, с тем, чтобы заставить многие из них работать в short форме. (Эта оптимизация будет происходить для ветвей, написанных вручную на ассемблере, а также ветвей, собранным Inform)
Дисассемблер TXD локальных чисел от 0 до 14 и глобальных от 0 до 239 (в соответствии с переменным числом от 1 до 15, и от 16 до 255, соответственно).
Формула ветви имеет смысл, так как в естественной реализации, счетчик команд по адресу после записи данных ветвления, происходит переход: таким образом, его можно рассматривать, как
  PC = PC + Offset - 2.
Если добавить правило "add the offset " , а затем, так как смещение не может быть 0 или 1 (из-за возвращения ложной и возвращения истинности), мы никогда бы не прошли мимо инструкции 1 байта (скажем, 0OP , как like quit), или указать ветвь "don't branch at all " (иногда полезно игнорировать результат теста в целом). Вычитание 2 означает, что единственные эффекты, которые мы не сможем достигнуть, являются
  PC = PC - 1 и ПК = ПК - 2
они будут ставить где-то обратно счетчик программы в той же инструкции, с неприятными последствиями.
Дисассемблер 
Если коротко, то первый байт инструкции может быть декодирован с помощью следующей таблицы:
  $00 -- $1f  long      2OP     small constant, small constant
  $20 -- $3f  long      2OP     small constant, variable
  $40 -- $5f  long      2OP     variable, small constant
  $60 -- $7f  long      2OP     variable, variable
  $80 -- $8f  short     1OP     large constant
  $90 -- $9f  short     1OP     small constant
  $a0 -- $af  short     1OP     variable
  $b0 -- $bf  short     0OP
  except $be  extended opcode given in next byte
  $c0 -- $df  variable  2OP     (operand types in next byte)
  $e0 -- $ff  variable  VAR     (operand types in next byte(s))
 
Вот пример разборки:
  @inc_chk c 0 label;    05 02 00 d4
      long form; count 2OP; opcode number 5; operands:
          02     small constant (referring to variable c)
          00     small constant 0
      branch if true: 1-byte offset, 20 (since label is
      18 bytes forward from here).
  @print "Hello.^";      b2 11 aa 46 34 16 45 9c a5
      short form; count 0OP.
      literal string, Z-chars: 4 13 10  17 17 20  5 18 5  7 5 5.
  @mul 1000 c -> sp;     d6 2f 03 e8 02 00
      variable form; count 2OP; opcode number 22; operands:
          03 e8  long constant (1000 decimal)
          02     variable c
      store result to stack pointer (var number 00).
  @call_1n Message;      8f 01 56
      short form; count 1OP; opcode number 15; operand:
          01 56  long constant (packed address of routine)
  .label;
 
 
Rate this item
(0 votes)
Login to post comments