| NedoPC Project | NedoPC Forum | NedoPC Group |

RW1P2


СОЗДАНИЕ ПЕРЕНОСИМЫХ ПРОГРАММ НА RW1P2

Copyright (c) 2001-2002, Alexander Shabarshin
Ekaterinburg, Russia (shaos@mail.ru)

  СОДЕРЖАНИЕ

  1. ВВЕДЕНИЕ
  2. ТРАНСЛЯТОР БИБЛИОТЕКИ СПРАЙТОВ
  3. КОМПИЛЯЦИЯ БАЙТКОДА
  4. ТРАНСЛЯЦИЯ КОДА ПРОЦЕССОРА
  5. СОЗДАНИЕ РАБОЧЕГО КОДА
  6. ПРОСТЫЕ ПРИМЕРЫ
  7. ОСОБЕННОСТИ RW1P2 ДЛЯ ПРОГРАММИСТА
  8. ВЗАИМОДЕЙСТВИЕ С СИСТЕМОЙ


  1. ВВЕДЕНИЕ

  Идея программирования в стиле RW1P2 заключается в том, что мы используем компилятор RW1C для компиляции программы на языке RW1 в байт-код RW0, который в дальнейшем транслируется в код конкретного процессора и системы. Важным свойством байт-кода является возможность отладки программ на уровне байт-кода (для этого сейчас создается реализация виртуальной машины RW0 на языке RW1P2), что может помочь отлавливать ошибки не доходя до уровня машинных команд.

  Программой в духе Robot Warfare 1 Platform 2 является код как таковой плюс библиотека спрайтов, выводимых в те или иные места экрана по ходу выполнения программы. В таком стиле можно программировать простые плоские игры, тетрис например, и др. У меня есть огромное желание написать на RW1 визуализатор боя роботов для перенесения нашей игры (http://robots.shaos.ru) на поддерживаемые системы. Кроме того правила трансляции RW0 байткода в код конкретного процессора являются открытыми (файл __RULES в каталоге конкретного процессора). Каждый может внести свои изменения, что-то улучшить или даже поддержать новую систему или процессор. Трансляция осуществляется через язык ассемблера (в-принципе можно использовать и другой низкоуровневый язык). В переспективе ассемблирование будет происходить внутри самого транслятора.

  2. ТРАНСЛЯТОР БИБЛИОТЕКИ СПРАЙТОВ

  SPR_COMP.EXE - программа для трансляции файлов спрайтов SPR в бинарные файлы BIN. В файле спрайтов спрайты представляются текстовыми строками, составленными из шестнадцатиричных чисел. Пока поддерживается лишь тип спрайтов 8x8-2/16, что значит размер спрайта 8 на 8 пикселов с использованием 2 цветов из 16 - для описания цвета символа и цвета фона. Пример строки из файла SPR:

   NAME DB #00,#11,#AA,#55,#00,#00,#00,#00,#F4 ;x
  В данном случае мы имеем 8 байт описания строк спрайта - один бит на пиксел и 1 байт атрибутов (4 старших бита - цвет фона, 4 младших бита - цвет символа). Кроме того имеется текстовый символ для замены спрайта на текстовых системах (например РАДИО-86РК). Этот символ пишется за символом комментария ; в той же строке. Если в этом же комментарии имеется символ '!', то байты описывающие спрайт инвертируются (полезно для систем, в которых используется только черно-белое представление, а переделывать спрайты нет возможности).

  Пример запуска транслятора библиотеки спрайтов:

   SPR_COMP -O#1000 -Sorion NAME.SPR
  -O опция для задания начального адреса библиотеки спрайтов в памяти целевого компютера, шестнадцатиричное значение пишется после символа #, без этого символа значение воспринимается как десятичное.

  -S опция задания системы цветности, по-умолчанию ORION (Орион-128). Кроме того есть системы SPECCY (для ZX-SPECTRUM) и SPEC (для компьютера Специалист). При использовании опции RADIO (Радио-86РК), бинарный файл создаваться не будет, заменяющие символы будут записаны непосредственно в файл определений RWI.

  Результатом работы программы будет бинарный файл BIN и файл определений RWI, который следует включить в создаваемую программу на языке RW1, использующую данную библиотеку. Имена этих файлов будут совпадать с именем файла SPR. В файле RWI для каждого спрайта из SPR будет создана запись в виде

   @имя_спрайта=числовой_идентификатор
  Эта строка является макроопределением для замены идентификатора спрайта в команде SET.

  Кроме того, в версии 1.2 (от 13 июня 2001 года) появилась опция -PALM, которая вместо одного BIN файла создает несколько файлов ресурсов, по одному на спрайт, с именами TbmpXXXX.bin, где XXXX - шестнадцатиричный индекс ресурса-пиктограммы (отсчитываются от начального адреса -O и увеличиваются на 1). Эти спрайты могут быть использованы совместно с ассемблером PILA для создания приложений для PalmOS. Для этого генерируется файл с расширением RES, описывающий созданные ресурсы.

  3. КОМПИЛЯЦИЯ БАЙТКОДА

  В программу на языке RW1 нужно включить файл описаний RWI с помощью команды препроцессора +. Например имея файл SPR.RWI, полученный после компиляции утилитой SPR_COMP, мы включаем его следующим образом:

   ROBOT "First"
   AUTHOR "Name"
   +RW1_STD.RWI
   +SPR.RWI // включение файла описания спрайтов
   MAIN()
   {
     // код программы
   }
Команды для использования спрайтов:
SELECT x y - задает местоположение для вывода спрайта,
SET n - выводит спрайт в текущее местоположение.

  Кроме того команды STEP,RIGHT,LEFT переопределены для управления текущим местом для вывода. В момент старта программы местоположение вывода располагается в левом верхнем углу - в точке (0,0). Направление движения - вправо.

  Компилируется программа компилятором-препроцессором RW1C версии не менее 2.0.6. Пример командной строки:

   RW1C -l -p first.rw1
  При этом при компиляции будут создаваться файл результатов препроцессорной обработки с расширением RW! и файл листинга LST.

  4. ТРАНСЛЯЦИЯ КОДА ПРОЦЕССОРА

  Трансляция осуществляется с помощью программы RW0COMP.EXE. У программы существует файл инициализации RW0COMP.INI в котором могут быть перечислены опции по умолчанию, которые могут быть переопределены из командной строки. Опции у программы следующие:

-Pprocessor - целевой процессор,
-Ssystem - целевая система,
-Oaddress - адрес начала программы,
-Baddress - адрес начала области переменных.

Например

   RW0COMP -Pi8080 -Sorion -O#1000 -B#4000 FIRST.RW0
  Или просто RW0COMP FIRST.RW0 если опции описаны в файле RW0COMP.INI, каждая в своей строке.

  Следует отметить, что для каждого процессора должен существовать файл LIB\processor\__RULES, где processor - имя процессора, а для каждой системы на таком процессоре должен существовать файл LIB\processor\system.A, где system - имя системы. Например для процессора I8080 определены четыре системы ORION, SPECCY, SPEC, RADIO в соответствующих А файлах. Ничего не мешает определить для системы SPECCY и родной процессор Z80 для более оптимального использования возможностей системы. В таком случае в каталоге LIB должен существовать каталог Z80 с файлом __RULES и специфическими системными функциями в файле SPECCY.A.

  В результате трансляции создается ассемблерный файл A, который в дальнейшем будет компилироваться самой утилитой RW0COMP, а пока, для процессора i8080 можно пользоваться утилитой RASM.EXE.

  5. СОЗДАНИЕ РАБОЧЕГО КОДА

  После создания бинарных файлов спрайтов и программы их нужно соединить, это осуществляется с помощью утилиты ADDBIN. Формат использования:

   ADDBIN target.BIN source.BIN hex
  Например, если у нас есть спрайты SPR.BIN, оттранслированные с адреса #8000 и программа FIRST.BIN, оттранслированная с адреса #A000, то соединить их можно так:
   ADDBIN game.bin first.bin 8000
   ADDBIN game.bin spr.bin A000
  При этом будет создан файл GAME.BIN, совмещающий в себе два бинарных файла со смещением от начала #1000 и #4000. Если необходимо удалить лидирующие нули, то это можно сделать с помощью утилиты LEADZERO.EXE (если вы хотите далее использовать программу BIN2BRU, то лидирующие нули убирать не нужно).

  Для ZX можно сделать отдельные TAP файлы для каждого блока с помщью утилиты BIN2TAP, а потом слить их вместе с помощью COPY /B. Придется написать простую программку на ZX-бейсике для загрузки бинарных файлов с "ленты". Например:

   10 LOAD "first" CODE
   20 LOAD "spr" CODE
   30 RANDOMIZE USR nnnn
  где nnnn - десятичное представление стартового адреса, с которого происходила кросскомпиляция. А можно обЗединить все в один BIN (как описано чуть выше) и сделать из него один TAP файл:
   BIN2TAP game.bin 8000
  При этом программа загрузчик получится чуть проще, но, возможно, получившийся TAP файл будет больше по размеру.

  Для ОРИОНА с помощью утилит BIN2BRU и BRU2RKO можно сделать файлы BRU или RKO.

  Для Радио, Ориона, Специалиста можно сгенерировать RSS файл с помощью утилиты BIN2RSSA. Такой формат файлов понимается эмулятором EMU80 Виктора Пыхонина.

  В случае Специалиста можно воспользоваться эмулятором Александра Шевцова SPMX42. Для этого не нужно создавать RSS-файл. Вместо этого берется BIN файл и переименовывается в файл с расширением I80. Также создается текстовый файл с таким же именем файла и расширением CPU:

   0000
   0000
   SPMX.ROM
  Здесь первые две строки - адрес загрузки и адрес старта, а третья строка - используемый файл с прошивкой ПЗУ.

  6. ПРОСТЫЕ ПРИМЕРЫ

  Создадим пример программы на RW1, которая просто выводит спрайт в клетку (0,0).

  Для начала придумаем спрайт, который будем выводить:

   ########  => #FF
   #      #  => #81
   # #  # #  => #A5
   #      #  => #81
   #      #  => #81
   #  #####  => #9F
   #      #  => #81
   ########  => #FF
  Предположим, цвет точек будет черным, а фона - красным (т.е. #40). Создадим файл MYSPR.SPR библиотеки спрайтов:
   ;8x8-2/16
   ;myspr.spr file
   MYSPR  DB  #FF,#81,#A5,#81,#81,#9F,#81,#FF,#40 ;@ 
  Откомпилируем его для системы Орион:
   SPR_COMP -O#6000 -Sorion myspr.spr
  В результате мы получили два файла - бинарный MYSPR.BIN и текстовый MYSPR.RWI, состоящий из одной строки:
   @MYSPR=24576
  Теперь напишем программу:
   // MY.RW1
   robot "MY"
   author "Shaos"
   +myspr.rwi
   main()
   {
      select 0 0 // выбор клетки для вывода
      set @MYSPR // вывод нашего спрайта
   }

  Первым делом ее надо скопилировать:

   RW1C -p -l my.rw1
  В результате получим выходной файл препроцессора MY.RW!, файл листинга MY.LST и нужный нам файл MY.RW0. Его-то нам и нужно транслировать дальше.
   RW0COMP -Pi8080 -Sorion -O#2000 -B#4000 my.rw0
  Заметьте, что стартовым адресом мы назначили адрес #2000, а с адреса #4000 у нас будут располагаться переменные программы. Если вы сделали все правильно, то должен получиться файл на языке ассемблера MY.A, похожий на этот:
\ RW0COMP.EXE         http://robots.ural.net
\ Copyright (c) 2001, Alexander Shabarshin (shaos@mail.ru)

        ORG     #2000
@BASE   EQU     #4000
@REGS   EQU     16448
@REG_X  EQU     16448
@REG_Y  EQU     16450
@REG_R  EQU     16458
@REG_A  EQU     16468
@REG_B  EQU     16470
@REG_C  EQU     16472
@REG_L  EQU     16476
        LXI_SP, @REGS
        \ SET _L_BASE AND _L_REGS
        LXI_H,  _L_BASE
        LXI_D,  @BASE
        PUSH_D
        CALL    _DE_S
        LXI_D,  @REGS
        CALL    _DE_S
        POP_H
        \ ERASE FROM BASE TO REGS
        MVI_C,  0
_STD_1: MOV_M,C
        INX_H
        MOV_A,H
        CMP_D
        JNZ     _STD_1
        MOV_A,L
        CMP_E
        JNZ     _STD_1
        JMP     _START
        \ DATA
_L_BASE DW  0
_L_REGS DW  0
_NPLANE DW  0
_ANGLE  DB  0
_COLOR  DB  0
_START:
\ *0x69 0x00 %w1 0x00 %w2
_j0000:
         MVI_A, #0000
        STA @REG_X
        MVI_A, #0000
        STA @REG_Y
\ *0x6A 0x00 %w1 0x00 0x00 0x00
_j0007:
         LXI_H,  #6000
        CALL    _SET
\ *0x43 0x00 %w1
_j000E:
         JMP _j0000
\ *0xFF
_j0012:
 
+LIB\i8080\_STD
+LIB\i8080\orion
+LIB\i8080\_PLATF2
  Этот файл можно отдавать на сЗедение ассемблеру RASM:
   RASM my.a
  Появление сообщения "Компиляция завершена", а также возникновение файлов MY.BIN и нового MY.LST, говорит нам, что создание кода прошло успешно. Теперь нам нужно объединить файлы MY.BIN и MYSPR.BIN. Вспомним стартовые адреса наших блоков кода и воспользуемся ADDBIN:
   ADDBIN mycode.bin my.bin 2000
   ADDBIN mycode.bin myspr.bin 6000
  Для эмулятора Ориона нам понадобится файл BRU:
   BIN2BRU mycode.bin 2000
  Важно помнить, что код программы в памяти должен располагаться раньше, чем код спрайтов. Итак, мы получили файл MYCODE$.BRU, который можем запустить на исполнение:
   ORIONEMU mycode$.bru
  Стартовав MYCODE$, мы увидим смешную красную рожицу в левом верхнем углу экрана :)

  Усложним программу:

   // MY.RW1
   robot "MY"
   author "Shaos"
   +myspr.rwi
   main()
   {
      dx = 20
      dy = 10
      for(xx=0,xx<dx,xx++)
      {
        for(yy=0,yy<dy,yy++)
        {
           select xx yy // выбор клетки для вывода
           set @MYSPR // вывод нашего спрайта
        }
      }
   }
  Посмотрите что получится теперь! :)))

  Если есть желание перекомпилировать эту программу под ZX-Spectrum, то я бы посоветовал выбрать следующие адреса: #8000 для кода, #A000 для переменных, #B000 для спрайтов.

   SPR_COMP -O#B000 -Sspeccy myspr.spr
   RW1C -p -l my.rw1
   RW0COMP -Pi8080 -Sspeccy -O#8000 -B#A000 my.rw0
   RASM my.a
   DEL mycode.bin
   ADDBIN mycode.bin my.bin 8000
   ADDBIN mycode.bin myspr.bin B000
   LEADZERO mycode.bin
   BIN2TAP mycode.bin 8000
  Программа-загрузчик на ZX-BASIC будет выглядеть так:
   10 LOAD "mycode" CODE
   20 RANDOMIZE USR 32768
  А теперь пример программы, воспринимающей ввод с клавиатуры:
   // MY2.RW1
   robot "MY2"
   author "Shaos"
   +myspr.rwi
   +inc/rw1_std.rwi // необходимо для @keyboard
   main()
   {
     buff = 0
     recv buff // попытка принять сообщение
     if(N==@keyboard) // если сообщение от клавиатуры
     { // в зависимости от кода символа выбрать координаты 
       b1 = buff/16 
       b2 = buff%16
       select b1 b2
       set @myspr
     }
   } // переход в начало main()
  Скомпилируйте ее для Ориона и посмотрите как она работает. Чтобы проверить это для РАДИО-86РК:
   SPR_COMP -O#6000 -Sradio myspr.spr
   RW1C -p -l my2.rw1
   RW0COMP -Pi8080 -Sradio -O#2000 -B#4000 my2.rw0
   RASM my2.a
   BIN2RSSA my2.bin mycode.rss RADIO 2000
  И загрузите получившийся файл MYCODE.RSS в эмулятор EMU80 Виктора Пыхонина http://www.uic.nnov.ru/~pyva/

  Для облегчения процесса создания приложения был создан интерпретатор команд системы SHJOB. Описание формата скрипта .shj для SHJOB:

 #!./shjob
 # Первая строка указывает имя интерпретатора для LINUX
 # что позволяет использовать скрипт, как исполняемый
 # файл, указав соответствующие атрибуты запуска
 # Комментарий после символа '#'
 $name=value # установка значения переменной
 command -k${name} # команда системы с переменными
 \need file # проверить существование файла, нет - выход
 \ren oldfile newfile # переименовать файл
 \del file # удалить файл
 \add file string # добавить строку в конец файла
  Вот пример скрипта для компиляции программы MY.RW1 для ZX-Spectrum:
 #!./shjob
 # my for speccy (i8080) -> my_.tap
 $name=my
 $spr=myspr
 $aspr=D000
 $abin=8000
 $avar=E000
 $syst=speccy
 $proc=i8080
 spr_comp -S${syst} -O#${aspr} ${spr}.spr
 \del ${name}.rw0
 rw1c -p -l ${name}.rw1
 \need ${name}.rw0
 \rename ${name}.lst ${name}.ls
 rw0comp ${name}.rw0 -P${proc} -S${syst} -O#${abin} -B#${avar}
 \need ${name}.a
 \del ${name}.lst
 rasm ${name}.a
 \need ${name}.bin 
 \del ${name}_.bin
 addbin ${name}_.bin ${name}.bin ${abin}
 addbin ${name}_.bin ${spr}.bin ${aspr}
 leadzero ${name}_.bin
 bin2tap ${name}_.bin ${abin}
 \del ${name}.bin
 \del ${spr}.bin
 \del ${name}.lst
 \del ${name}.ls
 \del ${name}.a

  7. ОСОБЕННОСТИ RW1P2 ДЛЯ ПРОГРАММИСТА

  В отличие от оригинального языка RW1, который используется для программирования боевых роботов, модификация RW1P2 имеет ряд отличий и добавлений.

  В версии 1.3 задействованы далеко не все регистры RW1: N - идентификатор передатчика сигнала после команды RECV (@KEYBOARD или @MOUSE), L - приемник по умолчанию значения выражения (например после (1+3) значение L будет 4), R - регистр случайных значений (в версии 1.3 обновляется во время команды RECV), T - некоторая характеристика времени (более точная реализация будет в следующих версиях), регистры для записи и чтения A,B,C - используются для передачи аргументов процедурам.

  Для опроса клавиатуры нужно выполнить:

   buff = 0
   recv buff
   if(N==@KEYBOARD) 
   {
      SAY "character &buff "
      ...
   }
  Лучше организовывать свою программу как цикл обработки сообщений. Кроме того полезно время от времени вызывать команду RECV для того, чтобы изменялись значения регистров R и T. Кроме того регистр R (случайное число от -32768 до 32767) будет менять свое значение при непосредственном присвоении var=R (но не в выражениях - var=R+1).

  Регистр T в будущих версиях будет обозначать количество десятых долей секунды, прошедших с момента старта программы. Это не будет работать для систем, не поддерживающих время, т.е. RADIO, SPEC, ORION. В случае SPECCY (ZX-Spectrum) это свойство будет поддержано.

  Важно помнить, что при вызове процедуры можно передавать лишь не более трех аргументов, потому что запись FUN(1,2,3) компилируется как A=1;B=2;C=3;CALL FUN. Если вы вызываете проуцедуру без параметров, то лучше писать CALL FUN, чем FUN().

  Старайтесь не использовать односимвольные имена для переменных и меток, это может конфликтовать с именами регистров RW1.

  Описание головной функции MAIN должно предшествовать описанию всех остальных функций. Все обЗявляемые переменные являются глобальными, поэтому следите за именами. Переменные обЗявляются лишь внутри функций. Напомню, что обЗявлением переменной является простая запись с присвоением, например VAR=0.

  Допускается иначе использовать команду SAY. В обычном смысле она выводит строку с возможными значениями переменных в нижнюю часть экрана (можно переопределить - см.ниже). Если же в качестве первого символа указать обратный слеш '\', а в качестве второго восклицательный знак '!', то все остальное будет просто вставлено в генерируемый ассемблерный файл (т.е. это реализация машиннозависимого встроенного ассемблера). Пример:

   SAY "\!mov a,x ;in asm" -> mov a,x ;in asm

Этого не рекомендуется делать, если вы желаете, чтобы ваша программа адекватно работала на разных платформах.

  Включение файлов RWI (функции-макросы) желательно производить до функции MAIN, а файлов RWL (библиотеки процедуры) после функции MAIN (см.пример ниже).

  Фигурная скобка { или } должна располагаться одна в строке. Для while, for, do обязательно должны указываться открывающие и закрывающие фигурные скобки.

  8. ВЗАИМОДЕЙСТВИЕ С СИСТЕМОЙ

  Для взаимодействия с системой используется команда COMMAND. Для того, чтобы вы могли ее использовать, необходимо включить файл INC/RW1P2.RWI. Также для удобства можно использовать библиотеки LIB/*.RWL. Для RW1P2 версии 1.4 можно использовать следующие команды:

  @P2_TERMINFO - возвращает информацию о терминале. Использование - COMMAND @P2_TERMINFO. После вызова в регистрах находится следующая информация: A - размер экрана по горизонтали (в клетках), B - размер экрана по вертикали, C - цветовая модель (0 для текстового режима или количество битов цвета для графического). В случае использования LIB/P2TERM.RWL вызов будет выглядеть так - terminfo(0).

  @P2_SETSAY - установка параметров команды SAY "...". Использование - A=newx;B=newy;C=newcol;COMMAND @P2_SETSAY где newx и newy новые начальные координаты (в клетках) выводимой строки, а newcol - цвет текста в формате ОРИОН (4 старших бита - цвет фона, 4 младших бита - символа). В случае использования LIB/P2TERM.RWL вызов будет выглядеть так - termsetsay(newx,newy,newcol).

  @P2_SETATR - подмена атрибутов спрайта при выводе (это также изменяет цвет и в команде SAY). Использование - A=newcol;COMMAND @P2_SETATR где newcol - цвет в формате ОРИОН (4 старших бита - цвет фона, 4 младших бита - символа). Срабатывает только для двухцветных спрайтов. В случае использования LIB/P2TERM.RWL вызов будет выглядеть так - termsetatr(newcol). Для возвращения в режим без подмены - termsetatr(0).

  @P2_TERMCLR - очистка терминала. В регистре A должен быть передан идентификатор спрайта, которым будет заполнен терминал после очистки. В случае использования LIB/P2TERM.RWL вызов будет выглядеть так - termclear(spr).

  Вот пример использования COMMAND через библиотеку LIB/P2TERM.RWL:

   robot "RANDOMTEST"
   author "Shaos"
   +inc/rw1_std.rwi
   +inc/rw1p2.rwi
   +myspr.rwi
   main()
   {
     terminfo(0)
     dx=A;dy=B;col=C
     say "DX=&DX DY=&DY COL=&COL "
     dd = 0
     while(1)
     {
        rand=R // get 16-bit random
        xx=@ABS(rand)%dx
        rand=R // get 16-bit random
        yy=@ABS(rand)%dy
        select xx yy
        if(dd%2) set @MYSPR
        else set @MYSPR2
        dd = dd+1
     }
   }
   +lib/p2term.rwl

   Спрайты берутся отсюда:

   ;8x8-2/16
   ;myspr.spr file
   MYSPR  DB  #FF,#81,#A5,#81,#81,#9F,#81,#FF,#40 ;@
   MYSPR2 DB  #FF,#81,#A5,#81,#81,#9F,#81,#FF,#10 ;#
  Эта программа настраивается на размер экрана системы и затем случайным образом заполняет его красными и синими рожицами :)

  Кроме библиотеки терминала p2term.rwl есть еще несколько библиотек:

  p2syst.rwl - команды, связанные с системой
  p2chan.rwl - команды, связанные с каналами (файлы)
  random.rwl - генератор 16-битных псевдослучайных чисел
  string.rwl - библиотека строковых функций

апрель 2001 - июнь 2002
Александр Шабаршин
alexander@shabarshin.com
http://www.shabarshin.com


Rambler's Top100
^ Вверх
© 2002-2008 NedoPC.org