30 августа 2017 |
|
Работа с глобальными переменными в Evo SDK by Hippiman Итак, ребята, сегодня мы снова будем расширять возможности Evo SDK. Изначально SDK имел довольно ограниченные возможности и по функционалу был близок к популярным редакторам на ZX Spectrum. Тут и невозможность работы с диском и расширенной памятью, и ужасное ограничение на размер кода в 32K. В своих предыдущих статьях я описал способы обхождения этих ограничений. Однако способ увеличения объёма кода путём разделения его на модули был не очень удобен из-за невозможности работы с глобальными переменными из модулей. Приходилось городить монструозные функции-менеджеры, которые передавали необходимые параметры в модуль или записывали их в расширенную память. В принципе, с этим можно было жить, однако необходимость лишних телодвижений сильно снижала скорость вызова модуля, а значит, и ограничивала варианты их применения. В этой статье я расскажу, как можно подружить модули и глобальные (и статические) переменные основной программы. * * * Первым делом идём в подпапку_temp_ в директории нашего проекта (если её нет, читай ACNews #59 ) и открываем файлout.map. Листаем примерно до середины файла и ищем там вот такие строки: Area Addr Size Decimal Bytes (Attributes) --------------------------------------------------------------- _DATA 00005322 000007C9 = 1993. bytes (REL,CON) Где 00005322 - это начало области данных. (Естественно, в разных проектах адрес может меняться.) Закрываемout.map, нам он больше не интересен, и открываем out.asm. В начале этого файла идёт список функций, его пролистываем. Ищем ;-------------------------------------------------------- ; ram data ;-------------------------------------------------------- .area _DATA После этих строк идёт список глобальных и статических переменных такого вида: _curtime: .ds 2 _nexttime: .ds 2 _nextid: .ds 2 _nextglobid: .ds 2 _bullet1: .ds 1 _roadpos: .ds 1 Как видно, никаких адресов тут нет, что сначала сбивает с толку. Зато есть вот это:.ds 2. Эти строки есть не что иное, как смещение в байтах между переменными. Путём простых вычислений получаем адреса: _curtime 0x00005322 (начало области данных) _nexttime 0x00005322+0x2 = 0x00005324 _nextid 0x00005324+0x2 = 0x00005326 _nextglobid 0x00005326+0x2 = 0x00005328 _bullet1 0x00005328+0x2 = 0x0000532A _roadpos 0x0000532A+0x1 = 0x0000532B и т.д. Теперь мы знаем адреса всех глобальных переменных. Осталось добавить их в модуль. Например, так: static u8 *maxhealth; maxhealth=(u8*)_plmaxhealth; *maxhealth=15; На всякий случай напомню, что после любого изменения в основном модуле и его перекомпиляции все адреса могут поменяться. Следовательно, каждый раз вручную высчитывать все ссылки - дело неблагодарное, и лучше его поручить скрипту. Далее я приведу полный листинг своего perl скрипта, который обрабатывает исходники основного модуля и генерирует два хедера: pointers.h - с указателями на функции; variables.h - с указателями на переменные. ┌──────────────────────────────────────────────────────────────┐ #!/usr/bin/perl use strict; my $flag; my $str; my @arr; my $databegin; my $tmp; open FIL,"_temp_\out.map"; open OUT,">pointers.h"; open VAR,">variables.h"; $databegin=0; while($str=<FIL>) { chomp $str; $str=~s/s*//; if(length($str)>0) { @arr=split(/ /,$str); if(substr($arr[2],0,1) eq "_") { print "#define " .$arr[2]." 0x". $arr[0]."n"; print OUT "#define " .$arr[2]." 0x". $arr[0]."n"; } if($arr[0]eq"_DATA" && $databegin==0) { $databegin= hex($arr[31]);#вот тут мы получаем адрес #области данных и конвертируем его в десятичную систему #счисления. } } } close FIL; open FIL,"_temp_\out.asm"; #открываем основной исходник. $flag=0; while($flag==0) #пролистываем до начала описания переменных { if(!($str=<FIL>)) { $flag=1; } chomp $str; #print $str."n"; if($str eq "; ram data") { $flag=1; } } $str=<FIL>; $str=<FIL>; $flag=0; while($flag==0)#обрабатываем область с переменными { if(!($str=<FIL>)) { $flag=1; } chomp $str; if($str eq ";--------------------------------------------------------") #это конец области, дальше нам ничего не нужно. { $flag=1; } else { $str=~s/t//g;#уберём всякий мусор $str=~s/://g; $tmp="#define ".$str." ".sprintf ("0x%x",$databegin)."n"; $str=<FIL>;#читаем ещё одну строку, в которой записано #смещение chomp $str; $str=~s/t//g; @arr=split(/ /,$str); $databegin+=$arr[1];#получим новое смещение print $tmp; print VAR $tmp; #выведем результат в хедер } } └──────────────────────────────────────────────────────────────┘ Вот и всё. Теперь можно добавить вызов этого скрипта к bat-файлу компиляции основного модуля, и у вас всегда будут верные сведения об адресах функций и переменных.
Other articles:
|
|
|
|
|
|
|
Similar articles:
В этот день... 21 November