Project

General

Profile

Транслятор с языка Sim-nML » History » Revision 9

Revision 8 (Alexander Kamkin, 09/30/2011 02:28 PM) → Revision 9/17 (Alexander Kamkin, 09/30/2011 02:30 PM)

h1. Транслятор с языка Sim-nML 

 Данный документ содержит описание схемы трансляции спецификаций микропроцессоров на языке Sim-nML в набор Java классов, которые могут быть использованы инструментом MicroTESK для автоматизированной генерации тестовых программ. 

 h2. Язык Sim-nML 

 Язык Sim-nML является расширением языка nML. 

 h2. Java классы, создаваемые при трансляции 

 Список Java классов, которые создаются при трансляции: 

 # Класс @ProcessorName@, который наследуется от класса @Processor@. Содержит большую часть информации о специфицируемом процессоре. 

 >> *TODO:* уточнить, каким образом формируется имя этого класса. Возможен вариант получаеть это имя из имени файла со спецификацией на Sim-nML, или же можно требовать задавания этого имени от пользователя в качестве одного из параметров метода, который осуществляет трансляцию, или же можно использовать какие-то специальные аннотации в самой спецификации. 

 h2. Правила грамматики для «общих» нетерминальных символов 

 h3. Бинарная операция 

 <pre> 
 BinOp : ''+'' 
       | ''-'' 
       | ''*'' 
       | ''/'' 
       | ''%'' 
       | DOUBLE_STAR 
       | LEFT_SHIFT 
       | RIGHT_SHIFT 
       | ROTATE_LEFT 
       | ROTATE_LEFT 
       | ROTATE_RIGHT 
       | ''<'' 
       | ''>'' 
       | LEQ 
       | GEQ 
       | EQ 
       | NEQ 
       | ''&'' 
       | ''^'' 
       | ''|'' 
       | AND 
       | OR 
 </pre> 

 h3. Числовая константа 

 <pre> 
 ConstNumExpr : ConstExprVal 
              | ConstNumExpr BinOp ConstExprVal 

 ConstExprVal : CARD_CONST 
              | FIXED_CONST 
              | HEX_CONST 
              | ''!'' ConstNumExpr 
              | ''~'' ConstNumExpr 
              | ''+'' ConstNumExpr %prec ''~'' 
              | ''-'' ConstNumExpr %prec ''~'' 
              | ''('' ConstNumExpr '')'' 
 </pre> 

 >> *TODO:* предлагается все числовые константные выражения сразу вычислять, в оттранслированный Java код вставлять уже только значения выражений. 

 h3. Выражение 

 <pre> 
 Bit_Expr : ID 
          | Bit_Expr ''+'' Bit_Expr 
          | Bit_Expr ''-'' Bit_Expr 
          | Bit_Expr ''*'' Bit_Expr 
          | Bit_Expr ''/'' Bit_Expr 
          | Bit_Expr ''%'' Bit_Expr 
          | Bit_Expr DOUBLE_STAR Bit_Expr 
          | ''('' Bit_Expr '')'' 
          | FIXED_CONST 
          | CARD_CONST 
          | STRING_CONST 
          | BINARY_CONST 
          | HEX_CONST 
 </pre> 

 h3. OR правило 

 <pre> 
 OrRule               : Identifier_Or_List 

 Identifier_Or_List : ID 
                    | Identifier_Or_List ''|'' ID 
 </pre> 

 h3. AND правило 

 <pre> 
 AndRule         : ''('' ParamList '')'' 

 ParamList       : 
               | ParamListPart 
               | ParamList '','' ParamListPart 

 ParamListPart : ID '':'' TypeExpr 
               | ID '':'' ID 
 </pre> 

 h3. Атрибуты 

 В языке Sim-nML атрибуты используются для описания свойств инструкций и режимов адресации. Описание каждого такого объекта может содержать произвольное число атрибутов. Атрибуты можно разделить на два класса: предопределенные атрибуты и пользовательские атрибуты. Описание предопределенных атрибутов приведено ниже. 

 <pre> 
 AttrDefList : 
             | AttrDefList AttrDef 

 AttrDef       : ID ''='' AttrDefPart 
             | SYNTAX ''='' ID ''.'' SYNTAX 
             | SYNTAX ''='' AttrExpr 
             | IMAGE ''='' ID ''.'' IMAGE 
             | IMAGE ''='' AttrExpr 
             | ACTION ''='' ID ''.'' ACTION 
             | ACTION ''='' ''{'' Sequence ''}'' 
             | USES ''='' UsesDef 

 AttrDefPart : Expr 
             | ''{'' Sequence ''}'' 
 </pre> 

 h4. Атрибут syntax 

 Атрибут syntax используется для описания ассемблерного кодирования инструкции или режима адресации. Значения данного атрибута должны иметь строковый тип. Можно выделить следующие основные варианты определения атрибута syntax: 

 # Строковая 
 1)Строковая константа — значение определяется посредством строковой константы. Например, “nop”. 
 # Атрибут 2)Атрибут параметра — значение атрибута определяется как значение этого же атрибута syntax у одного из параметров описываемого объекта. Например, x.syntax. 
 # Форматированная 3)Форматированная строка — значение атрибута определяется с помощью специальной конструкции format. Данная конструкция является аналогом оператора printf в языке программирования С. Например, format(“%5b”, r). 

 >> *TODO:* 
 // TODO: добавить полное формальное описание конструкции format + описание транслчции данной конструкции в строковое выражение Java. 

 h5. Трансляция 

 Java 
 Трансляция: 
 При трансляции данного атрибута в классе, соответствующем описываемому объекту создается метод со следующей сигнатурой: 

 <pre> 
 public String syntax() 
 </pre> 

 Для случая 1 из приведенного выше списка тело метода просто возвращает данную строковую константу. Для случая 2 метод возвращает результат вызова метода syntax соответствующего аргумента данного объекта. Такой аргумент должен содержаться в качестве поля в классе, соответствующем описываемому объекту. Для случая 3 метод возвращает результат трансляции конструкции format в строковое выражение языка Java. 

 h4. 
 Атрибут image 

 
 Атрибут image используется для описания бинарного кодирования описываемого объекта. Значения данного атрибута должны иметь строковый тип, причем допустимы только строки, содержащие символы «0», «1» и пробел. Пробелы используются для улучшения читаемости. Варианты определения атрибута image совпадают с вариантами определения атрибута syntax. 
 Трансляция: 
 Полностью аналогична трансляции атрибута syntax. 

 h4. 
 Атрибут action 

 
 Атрибут action используется для описания семантики выполнения инструкций.  
 Трансляция: 
 // TODO: при трансляции атрибута action обратить внимание на то, что в некоторых спецификациях данные между соседними в дереве инструкциями передают с использованием переменных (var). Это надо корректно учитывать, так как по умолчанию при трансляции таких объектов предлагается создавать локальные переменные соответствующих методов. С другой стороны, использование переменных для передачи данных между операциями противоречит описанию языка, в котором сказано, что состояние переменных не сохраняется при переходе от одной инструкции к другой. 

 h4. 
 Атрибут uses 

 
 В текущей версии инструмента данный атрибут не рассматриваем. 
 Основные конструкции языка 

 h3. Конструкция let 

 Конструкция let используется для объявления констант. Константы обладают следующими свойтсвами: 
 1.Константы получают глобальную область видимости. 
 2.Константа может быть определена только один раз. 
 Правила грамматики для конструкции let: 
 LetDef  
 : 
 LET ID ''='' LetExpr 
 LetExpr 
 : 
 ConstNumExpr 

 | 
 STRING_CONST 

 | 
 IF ConstNumExpr THEN LetExpr OptionalElseLetExpr ENDIF 

 | 
 SWITCH ''('' ConstNumExpr '')'' ''{'' CaseLetExprList ''}'' 
 OptionalElseLetExpr 
 : 


 | 
 ELSE LetExpr 
 CaseLetExprList 
 : 
 CaseLetExprList1 

 | 
 CaseLetExprList1 DEFAULT '':'' LetExpr 
 CaseLetExprList1 
 : 
 CaseLetExprStat 

 | 
 CaseLetExprList1 CaseLetExprStat 
 CaseLetExprStat 
 : 
 CASE ConstNumExpr '':'' LetExpr 

 Примеры: 
 let REGS = 5 
 let byte_order = “big” 
 let PC = “NIA” 
 let SP = “GPR[29]” 
 Проблемы: 
 Не ясна семантика if и switch в том случае, когда определяемая величина не получает никакого значения, например 
 let c = if 0 then 0 endif 
 Ограничения: 
 На первом этапе разработки прототипа предлагается ограничить поддержку конструкции let только простыми вариантами (без if и switch). Сложные вариаты let практически не используются на практике (ни один из примеров спецификаций представленных на сайте языка не содержал таких конструкций), их ценность представляется сомнительной. 
 Трансляция: 
 Если LetExpr является ConstNumExpr, то вычисляется значение этого выражения. Для каждой определенной в спецификации константы определяется поле к классе ProcessorName следующего вида 
	 public static final <type> ID = LetExpr; 
 где <type> может принимать следующие значения: 
 String – в случае, если LetExpr является STRING_CONST 
 int – в случае, если LetExpr является числовым выражением и вычисленное    значение есть целое.число, убирающееся в int. 
 long – в случае, если LetExpr является числовым выражением и вычисленное    значение есть целое.число, не убирающееся в int. 
 float – в случае, если    LetExpr является числовым выражением и его вычисленное значение есть число с фиксированной или плавающей точкой, убирающееся в тип float. 
 double – в случае, если    LetExpr является числовым выражением и его вычисленное значение есть число с фиксированной или плавающей точкой, не убирающееся в тип float. 
 Ошибочные ситуации: 
 наличие целых чисел, которые «не убираются» в long 
 наличие чисел с плавающей точкой, которые «не убираются» в double 
 Конструкция type 
 Конструкция type используется для определения синонимов новых типов. Синонимы определяются на основе существующих стандартных типов: 
 bool: определяет булевский тип, имеющий два предопределенных значений false и true. При применении преобразования типов (смотри coerces) false отображается в 0, true – в 1. При обратном преобразовании 0 отображается в false, любое ненулевое значение отображается в true. 
 int(n):определяет интервал целых чисел  
 card(n): определяет интервал натуральных чисел  
 float: определяет число с плавающей точкой согласно стандарту IEEE754 // TODO: несоответствие грамматики и описания 
 fix(n, m):определяет число с фиксированной точкой, в котором n бит отводятся под мантису и m бит под экспоненту.// TODO: уточнить, что описано в документации 
 [n..m]: определяет интервал натуральных чисел (ограничение) 
 enum(): определяет перечислимый тип, где именованные константы принимают значения от 0 до n-1.Будет совпадать с типом card(ceiling()) 
 Правила грамматики для конструкции type: 
 TypeSpec 
 : 
 TYPE ID ''='' TypeExpr 
 TypeExpr 
 : 
 BOOL 

 | 
 INT ''('' ConstNumExpr '')'' 

 | 
 CARD ''('' ConstNumExpr '')'' 

 | 
 FIX ''('' ConstNumExpr '','' ConstNumExpr '')'' 

 | 
 FLOAT ''('' ConstNumExpr '','' ConstNumExpr'')'' 

 | 
 ''['' ConstNumExpr DOUBLE_DOT ConstNumExpr '']'' 

 | 
 ENUM ''('' IdentifierList '')'' 
 IdentifierList 
 : 
 ID 

 | 
 ID ''='' CARD_CONST 

 | 
 IdentifierList '','' ID 

 | 
 IdentifierList '','' ID ''='' CARD_CONST 

 Примеры: 
 type bit 
  = 
 card ( 1 ) 
 type byte 
  = 
 card ( 8 ) 
 type address 
  = 
 card ( REGS ) 
 type breakcode 
  = 
 card (20 ) 

 Проблемы:Моделирование чисел с фиксированной точкой. 
 Ограничения: в текущей реализации не рассматриваем случаи, когда определяется интервал, по мощности превосходящий максимальный соответствующий стандартный тип а Java. Например, исключаем из рассмотрения card (128). 
 Трансляция:  
 Для каждого такого типа-синонима создается новый класс с именем ID, единственным полем которого будет переменная объемлющего типа, а методы будут обеспечивать корректность работы с этой переменной, контролируя невыход их множества допустимых значений. В случае нарушения данных ограничений метод должен выбрасывать исключение. 
 Необходимо учесть, что при трансляции операторов присваивания таким переменным, надо использовать методы set из соответствующих классов. Причем эти методы set должны в качестве параметров принимать так же номер строки и позицию в nml файле, по которой находится данный оператор присваивания. Эти данные используются отладки спецификаций в случае ошибок. 
 Перечисления транслируются в стандартные Java перечисления. Например, пусть есть перечисление: 
 type <name> = enum(id1 = val1, id2 = val2, …, idn = valn) 
 Оно транслируется в отдельный файл <name>.java, который содержит Java перечисление следующего вида: 
 public enum <name> { 
	 id1(val1), id2(val2), …, idn(valn) 
 } 
 Ошибочные ситуации: 

 h3. Конструкция mem 

 Конструкция mem используется для описания памяти моделируемого микропроцессора. Общий вид такого определения представлен ниже: 
 mem M [N, type] [optional-properties] 
 В этом определении, M – имя данного объекта памяти, N – количество ячеек памяти, и type – тип каждой такой ячейки памяти. Если тип не указан, то по умолчанию тип полагается равным card(8). Доступ к данным ячейкам памяти осуществляется по средствам оператора индексирования:M[0], M[1], … , M[n-1]. Опциональные параметры могут быть следующими: 
 alias – описывает новую память как синоним какойто части уже описанной памяти. В этом случае оба имени будут ссылать на одни и те же ячейки памяти, но могут интерпретировать их по разному. Например: 
 mem A[6, int(32)] 
 mem M[3, card(32)] alias = A[3] 
 В этом случае ячейки памяти, доступные по обращениям A[3], A[4], A[5], теперь могут быть доступны и по обращениям M[0], M[1], M[2] соответственно. Отличие заключается в том, что в случае обращений с использованием имени A содержимое ячейки интерпретируется как 32-ух разрядное знаковое число, в случае же, когда обращение идет по имени M, содержимое интерпретируется, как беззнаковое число. 
 Правила грамматики для конструкции mem: 
 Bit_Optr : BIT_LEFT Bit_Expr DOUBLE_DOT Bit_Expr BIT_RIGHT 
 MemorySpec 
 : 
 MEM ID ''['' SizeType '']'' OptionalMemVarAttr 
 SizeType 
 : 
 TypeExpr 

 | 
 ConstNumExpr 

 | 
 ConstNumExpr '','' TypeExpr 
 OptionalMemVarAttr 
 : 


 | 
 ALIAS ''='' MemLocation 
 MemLocation 
 : 
 ID Opt_Bit_Optr 

 | 
 ID ''['' NumExpr '']'' Opt_Bit_Optr 
 Opt_Bit_Optr 
 : 


 | 
 Bit_Optr 
 Bit_Optr 
 : 
 BIT_LEFT Bit_Expr DOUBLE_DOT Bit_Expr BIT_RIGHT 

 // TODO: не ясна семантика Opt_Bit_Expr в грамматики для конструкции 
  mem, в примерах использование именно такой формы тоже не было встречено. 
 Примеры: 
	 mem A[6, int(32)] 
	 mem M[3, card(32)] alias = A[3]  
 Проблемы: 
 Ограничения: 
 Трансляция: 
 Анализ спецификаций на языке Sim-nML позволил выявить, что конструкция mem может быть использована для двух различных целей. Во-первых, она может использоваться для описания памяти моделируемого микропроцессора. В этом случае число ячеек памяти в описании довольно большое (N >> 1). Необходимо найти описание с максимальным числом ячеек, именно оно будет транслироваться в класс, моделирующий память. При трансляции данного описания создается класс ProcessorNameMemory, который является наследником абстрактного класса Memory из библиотеки поддержки трансляции. Класс ProcessorNameMemory имеет следующий вид: 
 class ProcessorNameMemory { 
	 public static final SIZE = <N>; 
	 protected HashMap(Long, <type>) memoryHashMap = new HashMap(Long, <type>)(); 
 } 
 Для всех других описаний памяти, которые являются синонимами основной памяти (используют alias <имя основной памяти>), в атрибутах action для операций необходимо изменять обращения по этим именам на обращения по имени основной памяти. 
 Второй класс описаний памяти составляют описания, которые имеют небольшое число ячеек (обычно 1 или 2). Такие описания используются в качестве локальных переменных при описании атрибутов action для инструкций. Все такие описания при трансляции запоминаются. Затем при трансляции атрибутов action в методы инструкций, для каждой запомненной памяти, по которой присутствует обращение в данном атрибуте, вводится локальная переменная соответствующего типа. Все обращения по данным элементам памяти заменяются при трансляции на обращения к данной переменной. Например, 
	 mem tmp_signed_byte [ 1 , int (32) ] 
	 … 
	 action = { 
		  tmp_signed_byte = 31 
		 … 
	 } 
 При трансляции атрибута action получаем получим: 
	 public void execute(...) { 
		 int tmp_signed_byte 
		 … 
	 } 

 // TODO: определить абстрактный класс Memory 

 Ошибочные ситуации: 

 h3. Конструкция reg 

 Конструкция reg используется для описания регистров микропроцессора. Общая форма описания регистров представлена ниже: 
 reg R [N, type] [optional-properties] 
 В представленном определении R – имя регистрового файла, N – опциональный параметр, показывающий количество регистров в регистровом файле и type – тип каждого регистра. Если параметр N не указан, то по умолчанию он полагается равным 1.Доступ к регистрам данного регистрового файла осуществляется посредством оператора индексирования — R[0], R[1], …, R[N-1]. Определение регистров может иметь следующие опциональные атрибуты: 
 Ports: позволяет указать число портов чтения и записи для данного регистрового файла. Например: 
 reg R[16, int(8)] port = 3, 2 
 В представленном примере регистровый файл R имеет 3 порта для записи и 2 порта для чтения. Кроме того, каждый регистр в данном регистровом файле имеет 2 порта для чтения, так же как и весь регистровый файл, и один порт для записи. Порты чтения и записи для регистров рассматриваются в качестве ресурсов и используются для определения зависимостей между инструкциями. 
 Initial: позволяет указать начальное значение для описанных регистров. Например: 
 reg R[1, card(32)] initial = 100 
 Правила грамматики для конструкции reg: 
 RegisterSpec 
 : 
 REG ID ''['' SizeType '']'' OptionalRegAttr 
 OptionalRegAttr 
 : 


 | 
 PortsDef 

 | 
 InitialDef 

 | 
 PortsDef InitialDef 

 | 
 InitialDef PortsDef 
 PortsDef 
 : 
 PORTS ''='' CARD_CONST '','' CARD_CONST 
 InitialDef 
 : 
 INITIALA ''='' ConstNumExpr 

 Примеры: 
	 reg GPR [2 ** REGS, signed_long] 
	 reg LO [1, signed_long] 
	 reg NIA [1, long] 
 Проблемы: 
 Ограничения: 
 Трансляция: 
 Для каждого описанного регистрового файла создается класс RegisterFileName, который является наследником абстрактного класса библиотеки поддержки трансляции Register. Класс Register содержит следующие поля и методы: 
 class Register { 
	 public static final int WRITE_PORTS = 1; 
	 public static final int READ_PORTS = 1; 
	 ... 
 } 
 Класс RegisterFileName содержит следующие поля и методы: 
 class RegisterFileName { 
	 public static final int READ_PORTS = <read_ports>; 
	 protected <type> value = <init_value>; 
	 ... 
 } 
 Так же в класс ProcessorName добавляются следующие поля и методы: 
	 public static final int RegisterFileName_WRITE_PORTS = <write_ports>; 
	 protected RegisterFileName <some_uniq_name> [] = { 
		 new RegisterFileName(), 
		 ... 
	 } 
 Причем количество элементов в массиве RegisterFileName равно N. 
 Ошибочные ситуации: 

 h3. Конструкция var 

 Конструкция var используется для определения временных переменных. Типичная конструкция определения временной переменной выглядит следующим образом: 
 var TEMP[N, type] 
 В приведенном выше определении TEMP – имя массива временных переменных, N – количество переменных в определенном массиве и type – тип каждой переменной в массиве. Если параметр N не определен, то по умолчанию он полагается равным 1. Доступ к переменным осуществляется посредством оператора индексирования — TEMP[0], TEMP[1], …, TEMP[N-1]. Важно отметить, что значения временных переменных не сохраняются при переходе от одной инструкции к другой. 
 // COMMENT: по всей видимости переменные были введены в язык для прекращения нецелевого использования конструкций определения памяти для введения временных данных. Смотри второй класс конструкций определения памяти в разделе «трансляция» описания конструкции mem. 
 Правила грамматики для конструкции var: 
 // TODO: противоречие между текстовым описанием и грамматикой. 
 VarSpec 
 : 
 VAR ID ''['' SizeType '']'' OptionalMemVarAttr 

 Примеры: 
	 var amod[1, card(8)] 
	 var carry[1, card(1)] 
	 var op1[1, int(32)] 
 Проблемы: 
 Ограничения: 
 Трансляция: 
 Трансляция выполняется аналогично второму классу конструкций определения памяти. Описание приводится в разделе «трансляция» описания конструкции mem. 
 Ошибочные ситуации: 
 Конструкция mode 
 Конструкция mode используется для спецификации механизмов адресации. Основу данного описания этих механизмов составляют два вида конструкций: «И»-правила и «ИЛИ»-правила. 
 «ИЛИ»-правила используются для описания логически связанной группы механизмов адресации. С помощью «ИЛИ»-правила можно задать группе таких механизмов общие атрибуты. Общий вид «ИЛИ»-правила следующий: 


 «И»-правила используются для описания листовых элементов в дереве механизмов адресации. Общий вид «И»-правила следующий: 


 Правила грамматики для конструкции mode: 
 ModeRuleSpec 
 : 
 MODE ID ModeSpecPart 
 ModeSpecPart 
 : 
 AndRule OptionalModeExpr AttrDefList 

 | 
 OrRule 
 OptionalModeExpr 
 : 


 | 
 ''='' Expr 
 Примеры: 
 Проблемы: 
 Ограничения: 
 Трансляция: 
 Трансляция дерева «И»-«ИЛИ» правил проводится идентично как для инструкций, так и для режимов адресации. Подробные описания общих концепций трансляции приведены в разделе «Трансляция» описания конструкции op. Эти положения верны и при описании режимов адресации. Специфические моменты при трансляции этих описаний отражены ниже. 
 У и правил конструкции mode может присутствовать дополнительный опциональный элемент, который вычисляет значение параметра, передающегося данным способом адресации. Для каждого правила, обладающего таким элементом, в соответствующем классе создается тело метода getValue() на основе описания данного элемента. Метод возвращает оттранслированное выражение записанное в правиле после знака равенства. 
 Ошибочные ситуации: 

 h3. Конструкция op 

 Конструкция op используется для описания системы команд моделируемого процессора. 
 Правила грамматики для конструкции op: 
 OpRuleSpec 
 : 
 OP ID OpRulePart 
 OpRulePart 
 : 
 AndRule AttrDefList 

 | 
 OrRule 

 Примеры: 
 Проблемы: 
 Ограничения: 
 Трансляция: 
 Общие положения при трансляции древовидной структуры «И»-«ИЛИ» правил заключаются в следующем. Для каждого правила создается класс. Классы, соответствующие элементам из правых частей «ИЛИ» правил связываются с классом, соответствующим элементу в левой части, отношением наследования. Каждый класс, соответствующий элементу из списка параметров в «И»-правиле, связывается с классом, соответствующим элементу из левой части правила, отношением агрегации. На примере ниже продемонстрированы данные принципы с использованием нотации UML для отображения зависимостей между классами. 
 op instruction(inst alu_op) 
 op alu_instruction = add | sub 
 В каждом из этих классов создаются методы, соответствующие атрибутам. Механизм трансляции атрибутов подробно описан в разделе «Атрибуты». Имена создаваемых классов должны содержать некоторый служебный суффикс, что будет говорить о служебном внутреннем использовании данных классов.  
 Для каждого элемента из списка параметров «И» правила в соответствующем классе создаются поле. Для класса также создается конструктор с сигнатурой, соответствующей данному правилу, который инициализирует эти поля. 
 // TODO: посмотреть информацию про модификаторы доступа классов, пакетов для защиты служебных классов от некорректного использования. 
 Далее, для каждого листового элемента в дереве инструкций создается еще один класс, который наследуется от класса Instruction (соответствует корню дерева). Эти классы распределяются по пакетам в соответствии со структурой дерева. Для каждого не листового узла дерева создается отдельный пакет, куда вложены все пакеты и классы, соответствующие потомкам данного узла. 
 Ошибочные ситуации: