Info Guide
#07
31 мая 2005 |
|
For Coderz - Как делается крупная перемещаемая программа.
Перемещаемость программ Поскольку крупные программы не держатся на одних JR, да и, более того, имеют пере─ менные, то расскажу, как делается крупная перемещаемая программа. Например, это при─ меняется для программирования под кэш:один и тот же фрагмент работает в одном случае в Cache, а в другом - в обычном ОЗУ. 1. С созданием таблицы в полуручном режиме Применяется, например, в Pro Tracker'е при компиляции музыки с плейером. PT хра─ нит плейер, изначально отассемблированный по адресу #c000. Для того, чтобы он рабо─ тал по нужному адресу,содержимые некоторых его ячеек (в которых упоминаются адреса процедур и переменных) пересчитываются.Ад─ реса самих пересчитываемых ячеек хранятся в специальной таблице. Точнее,вместо адре─ сов там содержатся расстояния от предыду─ щей пересчитываемой ячейки до следующей (так решил сэкономить первый автор Pro Tracker'а, потому что таблица постоянно лежит в памяти). LD A,(SNGST+1) ;A=старший байт, ;адреса, по которому будем ;компилировать плейер LD IX,TRELOC ;адрес таблицы ;перемещения (релокации) LD HL,plaer ;где лежит плейер LD D,#C0 ;старший байт адреса, по ;которому в прошлый раз ;компилировали плейер LD ($-1),A LD E,A LD B,L REL0 LD C,(IX) LD A,C AND A RET Z ;код 0 - конец таблицы INC IX ADD HL,BC INC A JR Z,REL0 ;код 255 LD A,(HL) SUB D ADD A,E LD (HL),A JR REL0 Код 255, как видим, особый - он пропускает 255 байт, если до следующей ячейки больше 255 байт (ровно 255 байт нельзя). Таблица релокации составляется путём сравнения двух вариантов плейера: один откомпилирован под #c000, а другой - под #c100. Вот сравнивалка: ORG #A000 P1 INCBIN "PLYC0" ;плейер, ;откомпилированный под #C000 E1 ORG #C100 P2 INCLUDE "playFAST",#C4 ;тот же ;плейер, будет ;откомпилирован под #C100 module ;адрес модуля=адрес конца плейера. ;Тогда адрес модуля в этом экземпляре ;плейера будет сдвинут на #100 байт ;по сравнению с экземпляром "PLYC0" ORG #6000 LD IX,TAB LD HL,P1 LD DE,P2 LD C,0 CP0 LD A,(DE) SUB (HL) JR Z,CPOK ;байты отличаются? DEC A ;байты отличаются на 1? JR NZ,ERR ;НЕТ???->выход по ошибке LD (IX),C INC IX LD C,0 CPOK INC HL INC DE INC C JR NZ,CPNOFF LD (IX),255 INC IX LD C,1 CPNOFF LD A,L CP E1 JR NZ,CP0 LD A,H CP 'E1 JR NZ,CP0 LD (IX),0 INC IX RET ;выход по ошибке:нам подсунули существенно ;РАЗНЫЕ файлы плейеров ERR LD HL,0 LD DE,#5800 LD BC,768 LDIR RET TAB=#7000 Процедуру следует запускать из STS. Адрес конца таблицы увидим в регистре IX. 2. С созданием таблицы автоматически В PT Util для составления таблицы при─ меняется более удобный метод, при котором ассемблировать нужно не 2-3 раза, а всего 1. Происходит это так. Плейер для PT Util сидит в отдельном исходнике, который при INCLUDE'инге его в основную программу ассемблируется как обы─ чный плейер. Но если его попытаться отас─ семблировать как самостоятельную програм─ му, то: 1. Автоопределяется:адрес компиляции ра─ вен #8000, следовательно, нужно произвести компиляцию для создания перемещальной таб─ лицы. 2. Плейер ассемблируется как макрос MACRO pp (весь целиком загоняется в макрос), в па─ мять при этом не кладётся. (То же происхо─ дит и при упомянутом INCLUDE'инге .) 3. Макрос плейера ассемблируется по-нас─ тоящему, с локальными метками, под адрес #8000. (А вот этого при INCLUDE'инге не происходит.) 4. Макрос плейера ассемблируется по-нас─ тоящему ещё раз,уже не с локальными метка─ ми, под адрес #C000. (А при INCLUDE'инге - под адрес, который был текущим на момент команды INCLUDE .) 5. Ассемблируется сравнивалка. Адрес за─ пуска программы - переход на сравнивалку. То есть: запускаем по RUN - составляется таблица. Можно сохранить её вручную. Позже я освоил процедурку SAVEOBJ, её самое мес─ то применить здесь - тогда по RUN таблица не только составится, но и сохранится. И тогда всё - таблицу уже можно использовать в основной программе, путём INCBIN. В про─ цедуру SAVEOBJ из инициализационного куска программы (точнее, из подразумевающегося таковым - например, из нашей сравнивалки) можно выйти через JP nenado. Я имею в виду мою версию SAVEOBJ, а не ту, которую рас- пространял Capry. 3. Через макросы j, c, l В ZXRar я реализовал ещё более удобный способ: таблица перемещения строится прямо на этапе ассемблирования основной програм─ мы, самим аласмом. При этом никаких INCBIN вообще не нужно. Для такого способа требуется определить следующие макросы: MACRO rg CurCa=$ ORG RelCa DW CurCa+ RelCa=$ ORG CurCa ENDM MACRO j rg 2 IFN ?j1-2 ;есть ли 2-й параметр ;макроса? JP ,1 ;если есть, то такой JP ELSE JP ;если нет, то эдакий ENDIF ENDM MACRO c rg 2 IFN ?j1-2 CALL ,1 ELSE CALL ENDIF ENDM MACRO l LD ,1 rg 0-1 ;просто -1 в старых аласмах ;было нельзя, т.к. в макросе ;rg получилось бы CurCa+-1. ;В новых можно. ENDM И они используются в перемещаемом фрагмен─ те вместо команд JP [cc,]nn, CALL [cc,]nn, LD (...),rp, LD rp,(...). Но сначала надо задать начальный адрес, от которого будет строиться таблица: RelCa=#C000 Как видим, здесь на каждый релоцируемый адрес приходится 2 байта в таблице (а не 1, как было в Pro Tracker'е ).Тут экономия памяти ни к чему - ведь таблица нужна то─ лько на этапе запуска ZXRar'а. Вот место процедуры инициализации в ZXRar, которое занимается перекидыванием перемещаемого фрагмента ZXRar в кэш (пред─ варительно выяснив, есть ли на компьютере кэш): DI IN A,(#FB) LD H,0 LD A,(HL) INC (HL) CP (HL) JR Z,ncach LD HL,End ;здесь лежит табл. ;релокации. ;Почему здесь - см.ниже! LD B,RelSz ;длина табл. релокации. ;Как она считается - см.ниже Rel0 LD E,(HL) INC HL LD D,(HL) INC HL LD A,(DE) SUB 'cachecode LD (DE),A DJNZ Rel0 LD HL,cachecode LD D,B,E,L ;младший байт адреса ;не меняем, а старший будет 0 LD B,'cachelen+1 ;вместо ;LD BC,cachelen ;(выигрыш=1 байт) LDIR ncach Перед автосборкой ZXRar'а таблицу рело─ кации надо,естественно,перебросить в хвост программы, чтобы получился один кодовый блок. Вот как для этого оформляются после─ дние строки исходника ZXRar'а: DISPLAY "reloc tab end=",RelCa End=end RelSz=RelCa-#C000/2 end=RelSz*2+end INCLUDE "mrip*",#C0 ;автосборщик ;(см. IG#5) ORG $ LD HL,#C000 LD DE,End LD BC,RelSz*2 LDIR JP nenado С nenado тот же фокус, что был в случае SAVEOBJ. Это переход на сохранялку (если удерживается Caps Shift ) или запуск прог─ раммы по адресу GO (если Caps Shift отпу─ щен). A. Coder
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября