А если написать так
int i; int ccc; unsigned char* ptr; int ddd; ptr = 0x4000;
он сделает так
PUSH BC PUSH BC PUSH BC PUSH BC LD HL,16384 POP BC POP DE PUSH HL PUSH BC
чёт совсем грустно,... если бы он тупо LD (ADDR) делал, быстрее в 2 раза получилось бы
0iStalker
> Неужели на Си'шечке для Z80 нельзя получить вменяемый код, который не будет 90%
> времени дрючить стек?
Ежели ортодоксально следовать Ц-конвенции вызовов и локальных переменных, то, очевидно, нет. Кстати, раз он под CP/M, значит, исходно был не под Z80, а под 8080, что частично объясняет неподдельность ужаса.
> PUSH BC
> LD HL,16384
> POP BC
ммм да... но частично, только частично.
=A=L=X=
> Т.е. сам производитель зарабатывающий на микроконтроллерах деньги не способен
> сделать интенсивную регистровую оптимизацию,
А какую регистровую оптимизацию тут можно наоптимизировать? Аккумулятор, по сути, только один, так шо... Хотя в твоём примере, конечно,
> 00026A DD0709 LD BC,(IX+%9) > 00026D 03 INC BC > 00026E DD0F09 LD (IX+%9),BC
при наличии команды INC (IX+d) - это шыдевръ. Но, с другой стороны, если у них компилятор растёт из легаси от тех седых времён, когда в компилятор и оптимизаций-то было не запихнуть, то тогда понятно.
Sbtrn. Devil
> Кстати, раз он под CP/M, значит, исходно был не под Z80, а под 8080, что
> частично объясняет неподдельность ужаса.
Да, там в исходниках об этом сказано
Оказывается вся быстрота сишного кода заключается не в школьно-хацкерской "близости к железу", а в наличии оптимизирующих компиляторов.
Sbtrn. Devil
> А какую регистровую оптимизацию тут можно наоптимизировать?
LD HL, source LD DE, destination LOOP: LD a, (HL) LD (DE), a INC HL INC DE OR A JNZ LOOP
BC вообще не задействован даже
Sbtrn. Devil
> при наличии команды INC (IX+d) - это шыдевръ
Тут нет - eZ80 это довольно кособокое расширение команд Z80 под 24-битность и INC (IX+d) это не то - он способен инкрементировать только байт. Поэтому ему приходится 24-битно загружать, 24-битно инкрементировать и 24-битно сохранять. Но само перекладывание конечно просто излишне и ручной код намного производительнее.
=A=L=X=
> он способен инкрементировать только байт.
Кстати, да - упустил этот момент. Тогда, конечно, только трудным путём. Недружественна сишечка к 8-битному мейнстриму. Немудрено, что компиляторописатели норовили придумывать свои диалекты с урезаниями и ограничениями.
1 frag / 2 deaths
> Оказывается вся быстрота сишного кода заключается не в школьно-хацкерской
> "близости к железу", а в наличии оптимизирующих компиляторов.
Процессоры тоже стали делать как можно более простыми для компиляторов.
Сильная ортогональность регистров и большое их количество сильно помогает.
1 frag / 2 deaths
> в наличии оптимизирующих компиляторов.
зачастую они помогают, но они в любом случае не справятся со сложной задачей, сложные задачи должен решать человек, если умеет. Я даже не знаю сколько проходов надо иногда сделать, чтоб оптимизировать код, который подают на компиляцию. 50? 100? Больше?
Хорошо что это не про Спектрум. Иначе бы совсем всё плохо было.
Встретился конвертер с 8080-Z80 в x86 в репозитории шахмат Saron описанных в книге на Z80
https://github.com/billforsternz/retro-sargon
P.S, Был (NEC_V20) процессор x86 имеющий режим переключения в исполнение 8080 (Z80) кода.
А как правильно удалить IM2 прерывание?
Сделал отрисовку через прерывание, чистыми 50FPS как завещал дядя Синклер:
Start:
.model Spectrum48
.org #8000
__APP_CONSTANTS:
SCREEN_BEGIN_ADDR EQU 4000h ;16384
SCREEN_END_ADDR EQU 57FFh ;22527
SCREEN_SIZE EQU 1800h ;6144
SCREEN_SIZE_HALF EQU 0C00h ;3072
SCREEN_ATTR_BEGIN_ADDR EQU 5800h ;22528
SCREEN_ATTR_END_ADDR EQU 5AFFh ;23295
SCREEN_ATTR_SIZE EQU 300h ;768
;ATTR=Y*32+X+#5800.
;+-+-+-+-+-+-+-+-+
;|7|6|5|4|3|2|1|0|
;+-+-+-+-+-+-+-+-+
;bits 0..2 - draw color (INK)
;bits 3..5 - back color (PAPER)
;bit 6 - (BRIGHT)
;bit 7 - (FLASH)
EMPTY_PXL EQU 00h
EMPTY_PXL_W EQU 0000h
FILL_PXL EQU 0FFh
FILL_PXL_W EQU 0FFFFh
FILL_PXL_W_COUNTER EQU 003E9h ;1001 iterations
IM2_I_REG EQU 7Bh ;high interrupt address: I * 256 = #7B00
IM2_F_REG EQU 0FFh ;low interrupt offset: I * 256 + F = #7BFF
__APP_DATA:
STACK_ADDR DW 0
__APP_BEGIN:
;------ Setup Interrupt: Screen update -------
push af;
push de;
push hl;
di;
ld h, IM2_I_REG;
ld l, IM2_F_REG; HL - IM2 address;
ld a, h;
ld i, a;
ld de, IM2;
ld (hl), e;
inc hl;
ld (hl), d; IM2 - de;
im 2;
ei;
pop hl;
pop de;
pop af;
;------ Clear Screen: Stack -------
ClearScreen_FirstCall:
ld de, FILL_PXL_W_COUNTER;
ClearScreen_EntryPoint:
halt; waiting IM2 interrupt call;
jp NextScreen;
;------ Interrupt Function: Update Screen -------
IM2:
di;
;change border color
push af;
ld a, 2;
out (0xfe), a;
pop af;
;Store stack pointer
ld hl, 0;
add hl, sp;
ld (STACK_ADDR), hl;
;Clear screen
ld sp, SCREEN_ATTR_BEGIN_ADDR;
.loop SCREEN_SIZE_HALF
push de;
.endl
;Restore stack pointer
ld hl, (STACK_ADDR);
ld sp, hl;
;change border color
push af;
ld a, 0;
out (0xfe), a;
pop af;
ei;
reti;
;---------------------------------
SaveNewDE:
ld d, b;
ld e, c;
jp ClearScreen_EntryPoint;
NextScreen:
ld b, d;
ld c, e;
dec bc;
ld a, b;
or c;
jr nz, SaveNewDE;
__APP_END:
Exit:
ret
gamedevfor
> А как правильно удалить IM2 прерывание?
im 1 выполнить. это режим прерываний в спектруме по умолчанию. Он как бы исполняет команду $FF при наступлении прерывания, т.е. RST $38, где в ПЗУ бейсика располагается обновление системных переменных таких как код последней нажатой клавиши (сканируется клавиатура) и таймер отсчитывающий время от запуска компьютера.
=A=L=X=
> im 1 выполнить.
Без ничего? Не нужно восстанавливать регистр I например?
P.S. Сейчас при завершении программы происходит какая то дичь. )))
gamedevfor
> Сейчас при завершении программы происходит какая то дичь. )))
Завершай программу ресетом
gamedevfor
> Без ничего? Не нужно восстанавливать регистр I например?
Режим IM 1 как раз не использует I. Его использует только IM 2.
Болезненны для возврата в режим бейсика изменение жизненно важных регистров - типа SP, но еще и IY и просто порча мест в которых бейсик что-то держит типа системных переменных, кода программы и тому подобное.
У тебя тут таблица из 257 байт прерываний размещается в $7B00, а сам код сидит в $8000, здесь ничего криминального нет. Бейсик до этих адресов если программа в нём небольшая никак не может доходить (середина адресного пространства).
Но код тут довольно сумбурный и при входе в обработчик прерывания не сохраняет регистры которые портит. Это вообще неправильно. Обработчик прерывания должен начинаться с push af как минимум и по всем регистрам которые использует и потом pop в обратном порядке на выходе.
Как минимум в этом есть косяк.