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

Твердыня модульных языков
Текущее время: 23 ноя 2017, 18:46

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




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

Сообщения: 843
Откуда: Днепропетровская обл.
Вдохновлённый модулем Asm, предложенным Reobne, решил проверить эффективность создания Оберон-бибиотеки без выхода на уровень Си. Вот что получилось. Оригинальный модуль на Modula-2:
Код: "OBERON"
  1. DEFINITION MODULE GRAPH0;
  2. CONST width=256;height=192;
  3. PROCEDURE SCRDOT;
  4. PROCEDURE SCRNAD;
  5. PROCEDURE CLS2;
  6. PROCEDURE GCLS;
  7. PROCEDURE SETATTRS(X,Y:CARDINAL;L,C:SHORTCARD);
  8. END GRAPH0.
  9.  
  10. IMPLEMENTATION MODULE GRAPH0;
  11. PROCEDURE CLS2;HEX
  12. 3A 8D 5C 06 18 D9 21 00 5B CD (@GCLS+20) END CLS2;
  13. PROCEDURE GCLS;HEX
  14. AF 06 BF D9 21 00 58 CD (@GCLS+20) 21 00 40 06 20 77
  15. 2C 10 FC C9 D9 57 5F 21 00 00 39 D9 F9 D9 D5 D5
  16. D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 10 EE
  17. F9 C9 END GCLS;
  18.  
  19. PROCEDURE SETATTRS(X,Y:CARDINAL;L,C:SHORTCARD);HEX
  20. DD E1 C1 E1 D1 7B E6 1F 5F 7D 0F 0F 0F 57 E6 E0
  21. B3 6F 7A E6 03 F6 58 67 04 18 02 71 23 10 FC C5
  22. C5 C5 DD E9 END SETATTRS;
  23.  
  24. PROCEDURE SCRDOT;HEX
  25. 7A E6 07 C6 18 6F 26 BD 7A 56
  26. END SCRDOT;
  27. PROCEDURE SCRNAD; HEX
  28. 0F 0F 0F E6 1F 6F 7B 07 07 E6 E0 B5 6F 7B E6 07
  29. 47 7B 0F 37 1F 37 1F E6 58 B0 67 C9
  30. END SCRNAD;
  31.  
  32. END GRAPH0.
Портированный вариант:
Код: "OBERON"
  1. MODULE GRAPH0; (* For the ZX Spectrum (c) Mira Software 1991 *)
  2.  
  3. (** This module provides the elementary procedures
  4.   used by theother graphics modules.
  5.  
  6.   CLS2 clears the screen, but not the attributes area, while
  7.   GCLS clears the screen and attributes.
  8.   SETATTRS(X,Y,L,C) sets L character squares to have attribute C
  9.   starting at character position (X,Y).
  10.   SCRDOT and SCRNAD are imported by other graphic modules,
  11.   and are not useable as procedures on their own. *)
  12.  
  13. IMPORT S := SYSTEM, Asm;
  14.  
  15. CONST
  16. width* = 256; height* = 192;
  17.  
  18. PROCEDURE CLS2* ; (** clears the screen, but not the attributes area. *)
  19. BEGIN
  20. Asm.Code("LD A, (#0x5C8D) ;ATTR_P ");
  21. Asm.Code("LD B, #0x18 ");
  22. Asm.Code("EXX ");
  23. Asm.Code("LD HL, #0x5B00 ;SWAP_PAGE");
  24. Asm.Code("JP _GRAPH0_GCLS+20 ");
  25. END CLS2;
  26.  
  27. PROCEDURE GCLS* ; (** clears the screen and attributes. *)
  28. BEGIN
  29. Asm.Code("XOR A ");
  30. Asm.Code("LD B, #0xBF ");
  31. Asm.Code("EXX ");
  32. Asm.Code("LD HL, #0x5800 ");
  33. Asm.Code("CALL _GRAPH0_GCLS+20 ");
  34. Asm.Code("LD HL, #0x4000 ");
  35. Asm.Code("LD B, #0x20 ");
  36. Asm.Code("LD (HL), A ");
  37. Asm.Code("INC L ");
  38. Asm.Code("DJNZ .-2 ");
  39. Asm.Code("RET ");
  40. (*_GRAPH0_GCLS+20:*)
  41. Asm.Code("EXX ");
  42. Asm.Code("LD D, A ");
  43. Asm.Code("LD E, A ");
  44. Asm.Code("LD HL, #0x0000 ");
  45. Asm.Code("ADD HL, SP ");
  46. Asm.Code("EXX ");
  47. Asm.Code("LD SP, HL ");
  48. Asm.Code("EXX ");
  49. Asm.Code("PUSH DE ");
  50. Asm.Code("PUSH DE ");
  51. Asm.Code("PUSH DE ");
  52. Asm.Code("PUSH DE ");
  53. Asm.Code("PUSH DE ");
  54. Asm.Code("PUSH DE ");
  55. Asm.Code("PUSH DE ");
  56. Asm.Code("PUSH DE ");
  57. Asm.Code("PUSH DE ");
  58. Asm.Code("PUSH DE ");
  59. Asm.Code("PUSH DE ");
  60. Asm.Code("PUSH DE ");
  61. Asm.Code("PUSH DE ");
  62. Asm.Code("PUSH DE ");
  63. Asm.Code("PUSH DE ");
  64. Asm.Code("PUSH DE ");
  65. Asm.Code("DJNZ .-16 ");
  66. Asm.Code("LD SP, HL ");
  67. (*Safe RETURN to BASIC:*)
  68. Asm.Code("LD HL, #0x2758 ");
  69. Asm.Code("EXX ");
  70. END GCLS;
  71.  
  72. PROCEDURE SETATTRS* (X, Y: S.CARDINAL; L, C: S.SHORTCARD); (** sets L character
  73.   squares to have attribute C starting at character position (X, Y). *)
  74. BEGIN
  75. Asm.Code("POP BC ");
  76. Asm.Code("POP DE ");
  77. Asm.Code("POP HL ");
  78. Asm.Code("LD A, E ");
  79. Asm.Code("AND A, #0x1F ");
  80. Asm.Code("LD E, A ");
  81. Asm.Code("LD A, L ");
  82. Asm.Code("RRCA ");
  83. Asm.Code("RRCA ");
  84. Asm.Code("RRCA ");
  85. Asm.Code("LD D, A ");
  86. Asm.Code("AND A, #0xE0 ");
  87. Asm.Code("OR E ");
  88. Asm.Code("LD L,A ");
  89. Asm.Code("LD A,D ");
  90. Asm.Code("AND A, #0x03 ");
  91. Asm.Code("OR A, #0x58 ");
  92. Asm.Code("LD H, A ");
  93. Asm.Code("POP DE ");
  94. Asm.Code("PUSH BC ");
  95. Asm.Code("PUSH BC ");
  96. Asm.Code("PUSH BC ");
  97. Asm.Code("PUSH BC ");
  98. Asm.Code("LD B, E ");
  99. Asm.Code("INC B ");
  100. Asm.Code("JR B07E$ ");
  101. Asm.Code("B07C$:");
  102. Asm.Code("LD (HL), D ");
  103. Asm.Code("INC HL ");
  104. Asm.Code("B07E$:");
  105. Asm.Code("DJNZ B07C$ ");
  106. END SETATTRS;
  107.  
  108. PROCEDURE SCRDOT* ; (** imported by other graphic modules. *)
  109. BEGIN
  110. Asm.Code("LD A, D ");
  111. Asm.Code("AND A, #7 ");
  112. Asm.Code("ADD A, #0x18 ");
  113. Asm.Code("LD L, A ");
  114. Asm.Code("LD H, #0xBD ");
  115. Asm.Code("LD A, D ");
  116. Asm.Code("LD D, (HL) ");
  117. END SCRDOT;
  118.  
  119. PROCEDURE SCRNAD* ; (** imported by other graphic modules. *)
  120. BEGIN
  121. Asm.Code("RRCA ");
  122. Asm.Code("RRCA ");
  123. Asm.Code("RRCA ");
  124. Asm.Code("AND A, #0x1F ");
  125. Asm.Code("LD L, A ");
  126. Asm.Code("LD A, E ");
  127. Asm.Code("RLCA ");
  128. Asm.Code("RLCA ");
  129. Asm.Code("AND A, #0xE0 ");
  130. Asm.Code("OR L ");
  131. Asm.Code("LD L, A ");
  132. Asm.Code("LD A, E ");
  133. Asm.Code("AND A, #7 ");
  134. Asm.Code("LD B, A ");
  135. Asm.Code("LD A, E ");
  136. Asm.Code("RRCA ");
  137. Asm.Code("SCF ");
  138. Asm.Code("RRA ");
  139. Asm.Code("SCF ");
  140. Asm.Code("RRA ");
  141. Asm.Code("AND A, #0x58 ");
  142. Asm.Code("OR B ");
  143. Asm.Code("LD H, A ");
  144. END SCRNAD;
  145.  
  146. PROCEDURE- _init* "/*noinit*/";
  147. END GRAPH0.
Скрипт Obj/GRAPH0.bat выглядит так:
Код: "WINBATCH"
@SET Lib=z80\MiraMod2.lib
@IF EXIST ..\%Lib% DEL ..\%Lib%
 
@CALL ..\Bin\smart %Lib% GRAPH0 -noinit
  1. Устанавливаем путь и имя библиотеки, в которую будет добавлен наш модуль.
  2. Если библиотека уже существует, удалим старый файл во избежание накладывания новых сущностей поверх старых. У меня были с этим проблемы, пэотому рекомендую всегда так делать.
  3. Вызов скрипта smart, которому передаются путь-имя библиотеки, название модуля и ключик, который отказывается от добавления в библиотеку инициализатора модуля. Соответственно модуль библиотеки описывает процедуру PROCEDURE- _init* "/*noinit*/", которая транслируется Ofront'ом в макрос-пустышку #define GRAPH0__init() /*noinit*/. Это для эффективности, чтобы не включать в библиотеку лишний код.

Теперь опишем скрипт Bin/smart:
Код: "WINBATCH"
@REM args:
@REM LibName ModName [PartName] [-noinit] [-nocut]
@CD ..
@SET RootBin=..\..\Bin
@COPY Obj\%2.h
 
%RootBin%\smartlib Obj\%2.c %3 %4 %5
@FOR %%i IN (%2_0??.c) DO (
..\Bin\sdcc -c %%i -mz80 --opt-code-size --disable-warning 59 --disable-warning 85 -I "." -I include -I Obj
@IF errorlevel 1 PAUSE
)
@FOR %%i IN (%2_0??.rel) DO ..\Bin\sdar -rc %1 %%i
@CALL Bin\clear
@CD Obj
@CD .. - выйти из папки Lib/Obj на уровень выше — в Lib.
@SET RootBin=..\..\Bin - задаётся путь к корневой папке Bin (в ней находится утилита smartlib).
@COPY Obj\%2.h - копируется заголовок Obj\Модуль.h в Модуль.h. Это наша традиционная папка, в которой ищутся библиотечные хидеры (а почему они не ищутся в Lib/Obj? Да просто потому, что хидеры могут быть написаны вручную и отличаться от автоматически сгенеренных Ofront'ом).
%RootBin%\smartlib Obj\%2.c %3 %4 %5 - вызов smartlib с параметрами, полученными из вызывающего скрипта. Это могут быть имя части и ключи -noinit и -nocut (для использования этих ключиков пришлось доработать утилиту smartlib).

Далее описан цикл, который вызывает последовательно компиляцию каждого фрагмента исходника, разрезанного smartlib. Если в результате компиляции фрагмента будет найдена ошибка, компиляция будет остановлена командой @IF errorlevel 1 PAUSE.

Далее тоже в цикле осуществляется упаковывание оттранслированных объектных файлов в библиотеку с помощью утилиты sdar.

@CALL Bin\clear - чистит рабочую папку от временных файлов, нарезанных фрагментов и объектников.

@CD Obj - входим в папку Obj. Именно в этой папке мы были перед вызовом скрипта.

Пара комментариев напоследок.

  • Оверхед в CLS2. Процедура завершается командой:

    JP _GRAPH0_GCLS+20

    после которой SDCC конечно же генерирует ret. Оверхед размером в 1 байт, не снижающий скорость работы процедуры, ибо управление до него не доходит. Решается выходом на уровень Си и использованием тега __naked.

  • Вызов части другой процедуры по смещению. Успешно работает, в т.ч. и с "умной" линковкой. Т.е. процедура CLS2 зависима от GCLS, поскольку вызывает её. В случае использования только GCLS процедура CLS2 не включается в целевой бинарник. Если же использовать CLS2, то включаются обе.

  • Я, помнится, утверждал, что для Оберон-процедуры всегда генерируется фрейм входа и выхода. Оказалось, что это неверно. Мне не удалось установить закономерность в этом вопросе, да я особенно и не рылся, но действительно сейчас для процедуры void GRAPH0_SETATTRS (CARDINAL X, CARDINAL Y, SHORTCARD L, SHORTCARD C) фреймы входа и выхода не генерируются. Что не может нас не радовать. :) Кстати, в этой процедуре интересно устроен способ получения из стека параметров, я такого ранее не использовал, но теперь буду иметь его ввиду.

Так что попытка разработать библиотеку без выхода на уровень Си увенчалась вполне успешно. Имеем только один камешек в огород — оверхед в 1 байт, но, большей частью, это не так страшно, ведь решение всё равно есть. Можно даже разработать системный тег, который будет генерировать __naked, только вот эти вот все пляски с бубном для экономии одного байта выглядят слишком уж наивными, я предпочитаю сконцентрироваться на других, более важных направлениях.

Ну и маленькая демонстрационная программа, использующая нашу библиотеку.


Вложения:
MiraTest.tap [837 байт]
Скачиваний: 212
Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 04 июл 2014, 22:05 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
А вот для такой процедуры фреймы генерятся. Кто подскажет в чём здесь отличие по сравнению с предыдущим вариантом? :)
Код: "OBERON"
  1. MODULE AsmTest;
  2. IMPORT Asm;
  3.  
  4. PROCEDURE Border* (color: SHORTINT);
  5. BEGIN
  6. Asm.Code("LD A,4(IX)");
  7. Asm.Code("CALL 0x229B ");
  8. END Border;
  9.  
  10. BEGIN (*$MAIN*)
  11. Border(2);
  12. END AsmTest.
Код: "ASM"
;AsmTest.c:13: void AsmTest_Border (SHORTINT color)
; ---------------------------------
; Function AsmTest_Border
; ---------------------------------
_AsmTest_Border_start::
_AsmTest_Border:
push ix
ld ix,#0
add ix,sp
;AsmTest.c:15: Asm_Code((CHAR*)"LD A,4(IX)", (LONGINT)13);
LD A,4(IX)
;AsmTest.c:16: Asm_Code((CHAR*)"CALL 0x229B ", (LONGINT)13);
CALL 0x229B
pop ix
ret
_AsmTest_Border_end::


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 16 окт 2017, 11:47 
Не в сети
Администратор
Аватара пользователя

Сообщения: 22
Очень подозрительно выглядит мухлёж с SP. Такое ощущение, что он сбивается.

_________________
Действия профессионала предсказуемы. Но в мире полно любителей!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 16 окт 2017, 12:26 
Не в сети
Аватара пользователя

Сообщения: 843
Откуда: Днепропетровская обл.
Если бы он сбивался, процедура по RET возвращалась бы фиг знает куда.

Это обычный стандартный для SDCC способ получить параметры со стека, не снимая их. Не я придумал. :-) SP здесь вообще не трогается. IX делают равным SP и через него косвенной адресацией берут параметры. Можно их брать иначе, например, так:
Код: "ASM"
 POP  HL ; Адрес возврата
POP DE ; Два байта параметра
PUSH DE ; Восстанавливаем назад стек, как было
PUSH HL


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

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


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

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


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

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Тех.поддержка phpBB