01 апреля 2021 |
|
Разработка с помощью NedoOS Alone Coder Под NedoOS можно разрабатывать на ас─ семблере, Си,Паскале и Недоланге,но в этой статье я расскажу именно про ассемблер. На нём примеров больше всего, и с ним будет более понятно, как работает система. Кроме примеров, NedoOS предоставляет ра─ зработчику большой набор функций, которые обычно лень писать с нуля, а также среду для автоматической сборки. Первое знакомство Первое знакомство с системой для разра─ ботчика выглядит так (если у вас Windows): 1. скачать всё из http://nedoos.ru/svn/ в директорию,не содержащую пробелов в пути 2. войти в эту директорию, а точнее, в поддиректорию src/ 3. запустить mkevo.bat. При этом пересобирается вся система (на момент написания этой статьи - 70 паке─ тов), создаётся образ SD-карты sd_nedo.vhd (если его не было), а на него записывается всё, что есть в release/. Образ лежит в us/ - директории эмулятора. Как это работает внутри: 1. mkevo.bat записывает файлы настроек для конфигурации ZX Evo в файл src/_sdk/ syssets.asm 2. mkevo.bat запускает make.bat с пара─ метром noneedtrd (то есть не делаем trd- образ дискеты, она нам не нужна) 3. make.bat при необходимости создаёт директорию release/ 4. make.bat собирает пакет fatfs4os (фа─ йловая система FAT) 5. make.bat собирает пакет kernel (ядро ОС), создаётся nedoos.$c 6. make.bat в цикле собирает все пакеты путём вызова build.bat у каждого из них, а после сборки пакета копирует в release/ полученные *.com, *.ext, *.txt, *.new и поддиректорию, одноимённую с директорией пакета 7. make.bat при отсутствии параметра noneedtrd (а он у нас присутствует) созда─ ёт и заполняет test.trd 8. mkevo.bat переименовывает nedoos.$c в sd_boot.$c (чтобы можно было запускать из Evo Reset Service одной кнопкой 5) 9. mkevo.bat запускает chkimg.bat с па─ раметром sd (если бы был hdd, то работали бы с образом жёсткого диска hdd_nedo.vhd ) 10. chkimg.bat при необходимости создаёт образ (с помощью images.exe ) 11. chkimg.bat записывает на образ всё, что есть в release/ (с помощью dmimg.exe ) 12. mkevo.bat запускает настроенный эму─ лятор. Аналогично работают сборщики для оста─ льных конфигураций: mkevsd-g.bat - ZX Evo без SD-карты в NeoGS mkatm3.bat - ATM3 на дискете mkatm3hd.bat - ATM3 на HDD (Nemo IDE,можно исправить в батнике) mkatm3sd.bat - ATM3 на SD-карте mkpe26.bat - Pentagon 2.666LE на дискете mkpe26sd.bat - Pentagon 2.666LE на SD card mkatm2.bat - ATM2 на дискете mkatm2hd.bat - ATM2 на HDD (ATM IDE) Они все однотипные,так что каждый может создать свой сборщик или исправить сущест─ вующий. makeall.bat вызывает все mk*.bat. Его надо запускать перед коммитом в репозито─ рий. Батник сборки Из всего этого (особенно из пункта про build.bat ) видно, что программу пользова─ теля лучше писать по образцу имеющихся программ. Проще всего взять директорию emptyapp (или, если ваша программа похожа на какую-то существующую - то директорию той), скопировать её целиком и исправлять. Как выглядит простейший build.bat: 1. Настройка путей: if "%settedpath%"=="" call ../_sdk/ setpath.bat 2. Компиляция (может быть много строк, с вызовом нужных утилит конверсии ресурсов и т.п.): sjasmplus --nologo --msg=war emptyapp.asm Вот это место вы можете исправить для вашей программы, но если её главный модуль называется emptyapp.asm - не исправляйте:) А остальное исправлять, скорее всего, и так не придётся. 3. Если build.bat вызван отдельно (у ме─ ня это кнопка F9 в Notepad++ ), то копиро─ вать в release/ и на образ SD-карты: if "%currentdir%"=="" ( FOR %%j IN (*.com) DO ( copy /Y %%j "../../release/bin/" > nul "../../tools/dmimg.exe" ../../us/ sd_nedo.vhd put %%j /bin/%%j ) if "%makeall%"=="" ....usemul.exe ) Вариант для игр с кучей файлов в одно─ имённой поддиректории: SET releasedir2=../../../release/ if "%currentdir%"=="" ( FOR %%j IN (*.com) DO ( "../../../tools/dmimg.exe" ../../../us/ sd_nedo.vhd put %%j /nedogame/%%j move "*.com" "%releasedir2%nedogame">nul IF EXIST %%~nj xcopy /Y "%%~nj" "%releasedir2%nedogame%%~nj">nul ) cd ../../../src/ call ..toolschkimg.bat sd if "%makeall%"=="" ..usemul.exe ) Может быть, кто-то сможет сделать везде одинаково? Но пока живём так. Есть ещё вариант батника runcurl.bat, который после сборки пытается передать со─ бранный *.com по HTTP на уже запущенный эмулятор, а потом его удалённо запустить. Для этого в эмуляторе должна быть запущена NedoOS, а в ней веб-сервер 3ws. Главный модуль программы Предположим,что вы пишете игру.Её исхо─ дники лежат в src/games/somegame/. Её гла─ вный модуль называется main.asm. Её com- файл называется somegame.com, а дополните─ льные файлы генерируются в src/games/ somegame/somegame/ (при сборке попадут в release/nedogame/somegame/somegame/ ). Как выглядит main.asm: DEVICE ZXSPECTRUM128 include "../../_sdk/sys_h.asm" ;там все системные константы и макросы STACK=0x4000 ;так удобнее всего для игр org PROGSTART ;все программы начи─ ;наются с этого адреса begin ld sp,STACK ;иначе получится sp=0 ;Наша программа работает не через stdio, а ;сама ковыряется в экране, поэтому: OS_HIDEFROMPARENT ;разбудить роди─ ;теля программы (обычно навигатор) ld e,0+128 ;e=0: EGA, e=2:MC, ;e=3: 6912, e=6: text ;+8=noturbo ;+128=keep screen ;e=-1: disable gfx OS_SETGFX ;включаем граф.режим и ;получаем фокус (out:e=old gfxmode) ld de,path OS_CHDIR ;входим в поддиректорию ;...грузим файлы... mainloop ;...играем... jr mainloop ld hl,0 ;результат QUIT ;выход path db "somegame",0 ;...всякие процедурки, таблицы, инклюды... end savebin "somegame.com",begin,end-begin LABELSLIST "../../../us/user.l" ;сохраним ;метки,смотреть их дебагере Unreal Speccy Если код вашей программы компилируется в несколько страниц, то используйте дирек─ тиву PAGE и несколько savebin (можно под─ смотреть в проекте br, как это делается). Отладка Итак, если вы написали вышеприведённый пример main.asm и запустили build.bat (не забудьте указать там main.asm ),то как раз попадёте в Unreal Speccy. По кнопке "5" вы окажетесь в NedoOS, оттуда запустите свою игру из nedogame/ (можно это автоматизировать с помощью autoexec.bat ).Нажмите Shift+F1, чтобы по─ пасть в отладчик. Нажмите Ctrl+L, чтобы увидеть метки (а чтобы развидеть - ещё раз Ctrl+L ). Убедитесь, что текущая задача - именно ваша игра: Tab (в окно дампа), Ctrl+G,0080 - вы должны увидеть somegame.com в дампе. Если это не так, то вернитесь в окно дизассемблера (Shift+Tab), Ctrl+G, 0057 (конец обработчика прерываний), а дальше жмите F4 (выполнение до курсора), пока не увидите somegame.com в дампе. Справа внизу видны текущие включенные страницы во всех четырёх четвертинках. Шагать по программе - F7. Шагать с про─ пуском вызовов - F8. Шагать до выхода по стеку - F11. Можно переставлять текущий адрес исполнения - Z. В ходе исполнения программы можно вруч─ ную исправлять регистры (переход к ним - Shift+Tab, мышка тоже работает).Можно даже исправлять программу. Если другие задачи (особенно term.com ) мешают трассировать вашу программу,их мож─ но закрыть: попав в эту задачу,переставьте адрес исполнения на 0. Посмотреть экран - F9. Сохранить кусок памяти - Alt+W (сохра─ няется в src/ ). Загрузить - Alt+R. Выход из отладчика - Shift+F1. В теку─ щей версии эмулятора это почему-то приво─ дит к залипанию Shift, поэтому надо ткнуть ещё раз Shift. При выходе из отладчика та─ кже отключается Kempston mouse, его надо захватить кликом по окну эмулятора. Загрузка и сохранение файлов из программы Если вам нужно прочитать только какую- нибудь мелочь, типа отгрузки, можно просто набросать: ld de,filename ;"name.ext",0 OS_OPENHANDLE ;открыли файл or a jr nz,ошибка ;не смогли открыть push bc ;b=хэндл открытого файла ld de,SAVEDATA ;адрес,куда грузить ld hl,SAVEDATAsz ;сколько байт OS_READHANDLE ;загрузили pop bc ;b=хэндл открытого файла OS_CLOSEHANDLE ;закрыли Сохранение - аналогично, только вместо OPENHANDLE пишем CREATEHANDLE, а вместо READHANDLE - WRITEHANDLE. Образец можно посмотреть в untangle. Но обычно данные надо грузить в страни─ цы, а эти страницы надо выделить! Изначально ОС выделяет каждой программе 4 страницы,номера которых можно узнать че─ рез OS_GETMAINPAGES (получаем dehl=pages in 0000, 4000, 8000, c000 ). Лучше всего узнать их в самом начале и запомнить, на─ пример, так: OS_GETMAINPAGES ;dehl=pages in ;0000,4000,8000,c000 ld a,e ld (pgmain4000),a ld a,h ld (pgmain8000),a ld a,l ld (pgmainc000),a ;а дальше уже будет загрузка А в конце программы написать удобные процедуры включения этих страниц: setpgmain4000 pgmain4000=$+1 ld a,0 SETPG4000 ret setpgmain8000 pgmain8000=$+1 ld a,0 SETPG8000 ret setpgmainc000 pgmainc000=$+1 ld a,0 SETPGC000 ret Если ваша программа всегда включает экран в 4000 и 8000, то имеет смысл объ─ единить setpgmain4000 и setpgmain8000 в одну процедуру setpgsmain40008000. А теку─ щий экран включать через процедуру setpgsscr40008000. Можно не писать это с нуля, а заимствовать целиком модуль src/ games/sprexamp/mem.asm. Итак, нам надо загрузить сколько-то фа─ йлов в страницы.Возьмём универсальную про─ цедуру загрузки одной страницы из того же sprexamp: loadpage ;заказывает страничку и грузит туда файл ;(имя файла в hl) ;out: hl=после имени файла, a=pg push hl OS_NEWPAGE pop hl ld a,e push af ;pg SETPGC000 push hl ex de,hl OS_OPENHANDLE push bc ld de,0xc000 ;addr ld hl,0x4000 ;size OS_READHANDLE pop bc OS_CLOSEHANDLE pop hl ld b,1 xor a cpir ;after 0 pop af ;pg ret И будем её вызывать так: ld hl,texfilename call loadpage ld (pg0),a call loadpage ld (pg1),a call loadpage ld (pgsfx),a call loadpage ld (pgmusic),a и т.п. В br это вообще делается в цикле, а но─ мера страниц кладутся в таблицу. texfilename db "pg0.bin",0 db "pg1.bin",0 db "sfx.bin",0 db "music.bin",0 Легко переделать loadpage на загрузку с произвольного адреса, который тоже можно взять из texfilename (допустим, перед име─ нем файла). Рисование на экране Есть два способа рисования - в видимом экране или с двойной буферизацией (один экран обновляем, другой виден). Для динамичных игр лучше всего исполь─ зовать второй вариант, иначе возможны про─ блемы с мерцанием и исчезанием спрайтов. Главный цикл игры, работающей на двух эк─ ранах, выглядит примерно так (пример из loadscr ): ld a,(timer) ld (oldtimer),a ;главный цикл mainloop ;вывод фона/восстановить его под спрайтами ;... рекомендую взять из sprexamp! ;вывод спрайтов call setpgsscr40008000 ;включили ;страницы экрана ld iy,spaceship0 ld e,50 ;e=x = -(sprmaxwid-1)..159 ;(кодируется как x+(sprmaxwid-1)) ld c,50 ;c=y = -(sprmaxhgt-1)..199 ;(кодируется как есть) call prspr call setpgsmain40008000 ;включили ;страницы программы в 4000,8000, как было ;закончили рисовать ld a,(timer) push af call changescrpg ;с этого момента ;(точнее,с INT'а) увидим,что нарисовали ;логика ;вызывается столько раз,сколько прошло ;прерываний! mainloop_uvwaittimer0 ld a,(timer) oldtimer=$+1 ld b,0 ld (oldtimer),a sub b ld b,a jr z,mainloop_uvwaittimer0 ;если ;прерываний ещё не было,крутимся тут ;b=сколько прошло прерываний mainloop_uvlogic0 push bc call logic ;свою логику пишем сюда pop bc djnz mainloop_uvlogic0 ;ждём физического переключения экрана! ;можем начать новую отрисовку, только если ;с момента changescrpg прошло хотя бы одно ;прерывание (возможно, внутри logic) pop bc ;b=timer во время changescrpg waitchangescr0 ld a,(timer) cp b jr z,waitchangescr0 ld a,(curkey) cp key_esc jp nz,mainloop ;выход по esc/break Чтобы работал timer, подключите модуль sprexamp/int.asm и используйте swapimer (включение / выключение пользовательского обработчика прерываний) перед и после ва─ шего главного цикла. Обратите внимание, музыка не играется в этом обработчике, для этого есть системный вызов OS_SETMUSIC, который гарантирует ровное проигрывание, даже если ваша задача вытеснена другими задачами! Процедуру prspr возьмите из sprexamp/ prspr.asm. Если у вас спрайты скомпилиро─ ваны не в страницы, а в отдельные файлы, то можно в них определить prsprqwid=0x100, а перед первым вызовом prspr записать в 0x100 команду jp prsprqwid. Вообще можно начинать написание игры с исправления про─ екта sprexamp. Там есть даже два готовых движка - со скроллом фона по двум осям (без скролла фон не перепечатывается) и со скроллом по вертикали (фон перепечатыва─ ется всегда). Причём к первому движку уже прикручено управление и логика в стиле платформера. Стоит прочитать nedoos.txt,api_base.txt и sys_h.asm, чтобы получить представление о других функциях системы.
Other articles:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Similar articles:
В этот день... 21 November