![]() |
|
RW1P2
Copyright (c) 2001-2002, Alexander Shabarshin
СОДЕРЖАНИЕ
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 - целевой процессор, Например 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 - команды, связанные с системой
апрель 2001 - июнь 2002 |