Лучше сделать и жалеть, чем не сделать и жалеть.
Некоторые из моих поделок тут: https://github.com/serge-404
Вообще, я раньше был фаном си, но когда не смог закончить игру, то начал писать на барсике и все ок! А си для меня стал *****м...))
¡Un momento, señor fiscal!
разобрался с ошибкой. сам виноват, портил в паре место регистр ix, из-за этого местами слетали переменные. а я думал, что компилятор тупо их игнорит.
А я даже не сомневаюсь, что вот такие бочки на Си-компайлер часто катят не разобравшись. И сам грешен тем же)
Да, IX портить нельзя. Там выбрана грамотная стратегия - IX юзается для адресации локальных переменных. Компилер не сохраняет его перед вызовом каждой процедуры, и правильно делает. Считается, что процедура должна сама позаботиться об этом.
Многие встречаемые мною программисты для Z80 не в курсе этого. Так что нелишне напомнить.
Последний раз редактировалось Oleg N. Cher; 21.05.2018 в 20:48.
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
Не согласен. Думаешь, если бы компилер тупо всегда сохранял 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. Дело в том, что лежащие на стеке аргументы в случае стандартной модели вызова лучше вообще не изменять.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)