Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 17 июн 2025, 14:37

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ Сообщений: 2 ] 
Автор Сообщение
СообщениеДобавлено: 16 май 2014, 14:27 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
Разработка программ и игр для такого довольно чувствительного к эффективности кода компьютера как ZX Spectrum имеет свои особенности. Существующие технологии для высокоуровневой разработки под Z80 вообще предоставляют очень мало возможностей для оптимизации. Посмотрим что может нам предложить в этом смысле среда ZXDev. Возьмём маленькую программу и попробуем её оптимизировать.

Это будет незабвенная LaserDemo, переведённая с ZX-Basic. Оберон-вариант выглядит так:
Код: "OBERON"
  1. MODULE LaserDemo; (*$MAIN*)
  2.  
  3. (* Laser Basic Demo for Sinclair ZX Spectrum, 48 Kb. *)
  4. (* Copyright (C) 2012 Oleg N. Cher, VEDANTA software. *)
  5.  
  6. IMPORT L := Laser, B := Basic, Rsrc := LaserSprite2B;
  7.  
  8. (* Пример взят из книги "Как написать игру для ZX Spectrum" *)
  9.  
  10. (*
  11. 10 BORDER 0: PAPER 0:INK 5
  12. 20 CLS: LET S=-2
  13. 30 FOR N=7 TO 10
  14. 40 .R0W=5:.C0L=S:.SPN=N
  15. 50 .PTBL
  16. 60 PAUSE 5
  17. 70 NEXT N
  18. 80 LET S=S+2
  19. 90 IF S<32 THEN GO TO 30
  20. *)
  21.  
  22. PROCEDURE Main* ;
  23. VAR
  24. n, s: SHORTINT;
  25. BEGIN
  26. B.Init; L.InitSprites(Rsrc.SprStart, Rsrc.SprSize);
  27. B.BORDER(B.Black); B.PAPER(B.Black); B.CLS;
  28. FOR s := -2 TO 30 BY 2 DO
  29. FOR n := 7 TO 10 DO L.PTBL(s, 5, n); B.PAUSE(5) END;
  30. END;
  31. B.Quit;
  32. END Main;
  33.  
  34. END LaserDemo.
Сейчас LaserDemo.tap занимает 10090 байт. Оптимизировать мы будем по размеру кода, потому что быстродействия нам хватает — и так приходится затормаживать бег чудика паузой.

Такой действительно огромный по меркам Спектрума размер вызван двумя моментами.

  1. Код использует спрайты с номером от 7 до 10 (получается 4 фазы бега), включен же весь набор Sprite2B.
  2. К коду подключен весь рантайм Laser Basic'а, т.е. все неспользуемые процедуры. Это не неизлечимый диагноз, а просто ещё не сделанный кусок работы.

По первому пункту мы можем сделать набор спрайтов "смартлинкуемым". Но поскольку ни компилятор, ни линкер никак не могут догадаться по номерам спрайтов какие именно включать, а какие нет. Это никак нельзя сделать. Это можно было бы сделать, если бы процедура Laser.PTBL принимала на вход не номер спрайта, а адрес, но не будем сейчас менять логику её работы. Мы просто вручную выдерем нужные нам спрайты чудика (7-10) и включим в модуль только их.

Это можно сделать, подготовив "пустой" модуль, тело которого будет написано на Си (так сейчас устроен модуль LaserSprite2B). Либо же опишем данные прямо из Оберон-модуля с помощью процедуры Basic.DATA. Мне больше нравится второй способ, хотя он немного (на несколько байт) больше по размеру — за счёт "перепрыгивающей данные" процедуры Baisc.DEFDATA — чтобы данные не начали исполняться как код. Так что здесь самая большая трудность — найти в LaserSprite2B где именно в спрайт-данных находятся спрайты чудика.

Нам поможет знание формата хранения спрайтов. Первым идёт номер спрайта (1-255), потом адрес (два байта), второй (старший) из которых должен быть от #C6 до #DC. Дальше идут ширина и высота в знакоместах. Значит ищем в файле LaserSprite2B.c спрайт №7 по шаблону "0X07", после которого через байт должно быть число от #C6 до #DC. Ага, между прочим, нашли. Это байты:

0X07,0XFE,0XCB,0X05,0X04,0X00,0X00,0X00,0X00 ...

Добавим их в нашу программу. Теперь мы можем отказаться от использования модуля LaserSprite2B и всего набора спрайтов из него.

Я тут хотел сэкономить немножко байт за счёт отказа от атрибутов (всё равно чудик весь жёлтый), но Laser Basic хранит адреса, и их приходится настраивать процедурой инициализации спрайтов. А процедура расчёта адресов конечно ориентируется только на спрайты с атрибутами. Так что упс.

Суть сделанной оптимизации показывает этот коммит. LaserDemo.tap похудел до 4617 байт, из которых чудик занимает 740.


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 17 июн 2014, 22:40 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
Оптимизацию имеет смысл проводить по самому первостепенному направлению. Второстепенная оптимизация может не иметь смысла без первичной. В случае с LaserDemo мы знаем, что добрая половина кода сейчас — это не используемые процедуры из библиотеки Laser Basic, не готовые к смартлинковке. Мы видим, что LaserDemo использует только две процедуры из Laser: это InitSpritesEx (она адаптирована для смартлинковки) и PTBL.

Я всё-таки проделал эту большую по объёму и скучную работу — расчленил библиотеку Laser Basic на фрагменты, готовые для смартлинковки. В итоге LaserDemo.tap сократился с 4617 до 2889 байт. Я рассчитывал на ещё меньший размер, но не получилось — из-за того, что одна PTBL тянет за собой очень много кода.

Возможна ли дальнейшая оптимизация примера с чудиком? Конечно. Для начала — путём небольшого изменения формата хранения спрайтов (заменить адреса следующих друг за другом спрайтов на смещения) можно отказаться от процедуры настройки адресов Laser.InitSprites. PTBL тоже можно оптимизировать.

Именно с этой целью я предполагаю начать проект Laser2, который будет являться тотальным пересмотром внутреннего устроения процедур Laser Basic с целью их оптимизации и большей отвязки друг от друга.


Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 2 ] 

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
© VEDAsoft Oberon Club