Вообще, я раньше был фаном си, но когда не смог закончить игру, то начал писать на барсике и все ок! А си для меня стал *****м...))
Вообще, я раньше был фаном си, но когда не смог закончить игру, то начал писать на барсике и все ок! А си для меня стал *****м...))
¡Un momento, señor fiscal!
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
разобрался с ошибкой. сам виноват, портил в паре место регистр ix, из-за этого местами слетали переменные. а я думал, что компилятор тупо их игнорит.
А я даже не сомневаюсь, что вот такие бочки на Си-компайлер часто катят не разобравшись. И сам грешен тем же)
Да, IX портить нельзя. Там выбрана грамотная стратегия - IX юзается для адресации локальных переменных. Компилер не сохраняет его перед вызовом каждой процедуры, и правильно делает. Считается, что процедура должна сама позаботиться об этом.
Многие встречаемые мною программисты для Z80 не в курсе этого. Так что нелишне напомнить.
Последний раз редактировалось Oleg N. Cher; 21.05.2018 в 20:48.
Не согласен. Думаешь, если бы компилер тупо всегда сохранял IX, было бы лучше? Уж лучше умная ф-ция сама об этом позаботится.
alloca, насколько мне известно, в Си для Z80 нет. А если бы была, она была бы конечно написана в машкоде и могла бы в начале своей работы положить в стек дополнительный адрес возврата, который бы при выходе из функции вызвал освобождение памяти, как и задумано.
Раз уж об этом зашла речь, SfS, уж не обессудь, я всё-таки скажу то, что собирался. В твоём проекте SDCC noinit очень топорно устроена работа с аргументами функций. Вот это нехорошо:
Надо так:Код:void pt3Init(void* mod_adress)__naked{ __asm; ld hl,#2 add hl,sp ld e,(hl) inc hl ld d,(hl) inc hl ex de,hl push ix call pt3xplayer_init+3 pop ix ret __endasm; }
И если бы это был единичный случай. А вот это ещё хуже:Код:void pt3Init(void* mod_adress)__naked __z88dk_callee{ __asm pop hl ex (sp),hl push ix call pt3xplayer_init+3 pop ix ret __endasm; }
Надо так:Код:void spr0_out0(const Sprite0* adr, BYTE x, BYTE y)__naked{ __asm; push ix ld ix,#4 add ix,sp ;// adr ld e,0(ix) ld d,1(ix) ;// x ld l,2(ix) ;// y ld h,3(ix) ... __endasm; }
- - - Добавлено - - -Код:void spr0_out0(const Sprite0* adr, BYTE x, BYTE y)__naked __z88dk_callee{ __asm pop hl ; Адрес возврата pop de ; Если порядок регистров при снятии аргументов не совсем подходящий ; Всё равно пересылки между регистрами очень дёшевы, в отличие от индексных ex (sp),hl ; Возвращаем адрес возврата на стек ; Сейчас у нас в hl и de все аргументы ... __endasm; }
Кстати, вот это:
Можно переписать ещё короче:Код:void pt3Init(void* mod_adress)__naked __z88dk_callee{ __asm pop hl ex (sp),hl push ix call pt3xplayer_init+3 pop ix ret __endasm; }
Код:void pt3Init(void* mod_adress)__naked __z88dk_fastcall{ __asm ; Аргумент уже в HL push ix call pt3xplayer_init+3 pop ix ret __endasm; }
это легко меняется на это:И если бы это был единичный случай. А вот это ещё хуже:
Код:
void spr0_out0(const Sprite0* adr, BYTE x, BYTE y)__naked{
__asm;
push ix
ld ix,#4
add ix,sp
;// adr
ld e,0(ix)
ld d,1(ix)
;// x
ld l,2(ix)
;// y
ld h,3(ix)
...
__endasm;
}
И вообще, подобные вещи лучше сразу на асме писать и заворачивать в lib файл. если хочется указать компилятору, что функция naked, то в прототипе это можно указать, а можно не указать, что при написании функции на асме является не обязательным (или не является обязательным).Код:ld hl,#2 add hl,sp ld e,(hl) inc hl ld d,(hl) inc hl ld a,(hl) inc hl ld h,(hl) ld l,a push ix
Олег, не рекомендуй человеку багованные конструкции. обрати внимание, что твои конструкции вида pop hl:ex (sp),hl не работают с однобайтными переменными/аргументами.
Последний раз редактировалось Sayman; 24.05.2018 в 06:38.
В SDCC нет отличий - в отдельном файле делать функции на асме или делать __naked-функцию.
Я много чего в рамках освоения SDCC делал и переписать все либы разом врядли смогу. Хотя много чего требует оптимизации.
Примеры с ex (sp),hl будут работать некорректно, так как вызывающая функция будет думать, что на стеке 4 байта, а не два (параметр мы сняли). И освободит 4 байта. Будет плохо. Пробовал.
В языке С при вызове функций память резервируется и освобождается вызывающей функцией. И ей всё равно, что происходит в вызываемой. Запихала параметры, (SP=SP+размер параметров) вызвала функцию, сняла параметры (SP=SP-размер параметров). Всё.
В вызывающую функцию ты вернёшься после pop hl: ex (sp),hl. А вот потом начнутся чудеса![]()
Последний раз редактировалось SfS; 24.05.2018 в 09:38.
Sayman, вот это:
легко меняется на это:Код:ld hl,#2 add hl,sp ld e,(hl) inc hl ld d,(hl) inc hl ld a,(hl) inc hl ld h,(hl) ld l,a push ix
Посчитай такты сам. И то, если лениво по каким-то причинам юзать модель __z88dk_callee, которая заслуживает всяческого уважения.Код:pop bc pop hl pop de push de push hl push bc push ix
SDCC юзает для выравнивания стека в подобных случаях INC SP/DEC SP. Поэтому я против термина "багованные конструкции", он тут абсолютно неприменим. А если ты не снимаешь аргументы со стека, то и это без разницы. Просто аргумент ляжет в другой регистр из пары.
Юзать IX в качестве указателя на аргументы иногда тоже есть смысл, но только если обращение к ним происходит глубоко в теле подпрограммы помногу раз. Как правило, такие случаи встречаются крайне редко. Например, я юзаю подобную адресацию в процедуре NewSupercode.LITERY(SHORTCARD x, SHORTCARD y, SHORTCARD xs, SHORTCARD ys, SHORTCARD wdth, CHAR *str) - здесь много параметров, для них явно не хватает регистров общего назначения.
- - - Добавлено - - -
Для стандартной модели вызова - всё так. Но если ты укажешь в прототипе функции атрибут __z88dk_callee, компилятор будет знать, что функция сама снимает свои аргументы со стека. А в случае атрибута __z88dk_fastcall, компилятор вообще не будет использовать стек, только регистр L (или пару HL в случае двухбайтового аргумента).
Всё нормально будет. Читай в доках про флажки __z88dk_callee и __z88dk_fastcall, они реально помогают ускорить работу с аргументами.
- - - Добавлено - - -
Кстати, я действительно не рекомендую (и не рекомендовал) использовать ex (sp),hl для стандартной модели вызова. Только для __z88dk_callee. Дело в том, что лежащие на стеке аргументы в случае стандартной модели вызова лучше вообще не изменять.
а в чём вообще смысл использования этой модели? я засунул эту модель в код, собрал. смотрю, результат вообще ничем не отличается от того, что было до этой модели. т.е. передача аргументов такая же. как и до этого. байт в байт, строка в строку. зачем мне лишние записи в исходнике тогда? может и есть какие то особенности использования этой модели, я об этом не знаю, оно не очевидно и в целом мало полезно.
именно из-за этого стек и уплывает при использовании "pop hl:ex (sp),hl ". я не поленился и для теста поменял пару функций на "это". в результате второй вызов функции привёл к зависанию программы.SDCC юзает для выравнивания стека в подобных случаях INC SP/DEC SP.
эээх. ну понятно. что все аргументы лягут на стек, далее конечно можно и наверно было бы удобнее гонять индексные регистры, однако, переключиться на альтернативный набор регистров религия не позволяет?здесь много параметров, для них явно не хватает регистров общего назначения.
а ты точно проверял как это работает? оно хорошо, когда передать нужно 1 аргумент в 1 байт или 2 байта или два аргумента по 1 байту. как только данных становится больше, чем 2 байта, эта модель перестаёт работать.__z88dk_fastcall, компилятор вообще не будет использовать стек, только регистр L (или пару HL в случае двухбайтового аргумента).
насколько я вижу по коду, эта модель не работает с аргументами, не кратными 2 байтам. 1 лишний байт снимается со стека, из-за этого стек уплывает. всё потому, что компилятор юзает лишние inc sp/dec sp. но про это я уже когда то давно говорил (в сравнении с хайтехом).Только для __z88dk_callee.
Как-то ты ограничено и предвзято подошёл к этому вопросу.
Смотри. С моделью __z88dk_callee вызывающей стороне не нужно вытаскивать аргументы из стека. Если ты этого у себя не воспроизвёл, значит мало и по верхушкам ковырялся. То есть имеем профит на вызывающей стороне.
На вызываемой стороне с моделью __z88dk_callee профит есть для кодовых процедур. Я тебе показывал как двумя-тремя командами вытаскивать аргументы. Это кардинально отличается от того, что предлагал ты.
Я говорю об очень очевидных вещах. Если есть желание спорить дальше, тут медицина бессильна.
Мне всё труднее сдерживаться от ругательств. Ну ассемблерщики, хоть вы ему скажите?
Всё говорит о том, что ты менял на "это" без должного понимания того, что ты делаешь. А в ZXDev такой код много лет уже работает. И тебе любой ассемблерщик на пальцах это докажет. Вернее, не тебе, а кому-то умному. :-)
Что ты, моя религия не настолько строга. Ты опять придрался к частностям, а я всего лишь утверждал, что индексные регистры тоже можно использовать там, где в этом есть смысл. А чаще всего для получения аргументов смысла в этом мало.
Я точно проверял как это работает.
Мда, доказывать сишнику преимущества Оберона после того, как ему нельзя доказать преимуществ Си...
Опять же, всякая модель хороша для своей цели. А там, где у тебя перестаёт работать или работает плохо, у кого-то другого поумнее - всё хорошо. Например, я умею передавать два однобайтовых аргумента под видом двухбайтового и в модели __z88dk_fastcall.
Работает с одним лишненьким inc sp. Который выполняется быстро.
А твой тупой хайтех вообще неэкономно использует и стек, и регистры.
И вообще жалею, что с тобой разговор затеял. Вот ей-богу, некоторых лучше вообще игнорить, пусть несут пургу сколько угодно.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)