LD DE, 0000 + ADD HL, DE = 10+4 = 14 тактов
LD A,H + OR L = 5+4 = 9 тактов
Но если DE загружать вне цикла, то покатит.
LD DE, 0000 + ADD HL, DE = 10+4 = 14 тактов
LD A,H + OR L = 5+4 = 9 тактов
Но если DE загружать вне цикла, то покатит.
Последний раз редактировалось vinxru; 13.09.2012 в 16:37.
LXI 10 тактов. DAD тоже. Итого 20.
---------- Post added at 17:37 ---------- Previous post was at 17:36 ----------
Давай будем разговаривать в мнемониках i8080
http://www.emuverse.ru/wiki/Intel_80...B0%D0%BD%D0%B4
DAD = 4 такта
---------- Post added at 15:39 ---------- Previous post was at 15:38 ----------
А в Intel_8080_ASM_Lang_Manual.pdf написано 10
Я тут просматривал код:
И подумал - а не стоит ли переменные засовывать прямо в код, для циклов? Выделенную строчку заменить на две:Код:; for(x=0; x<64; x+=16) { xor a ld (main_x), a l10: ld d, 64 ld a, (main_x) call l_uchar or a jp z, l11 jp l12 l13: ld a, (main_x) add 16 ld (main_x), a jp l10 l12: ; } jp l13 l11:
main_x_var:
ld a,0
нолик, соответственно, место где хранится переменная, она же теперь часть кода. Соответственно, обращаться к переменной теперь не ld a, (main_x), а ld a, (main_x_var+1). Код на байт короче, байт экономится на глобальной переменной, 6 тактов на каждой итерации цикла. Правда 2 минуса - нужно следить за обращением к x, он теперь на новом месте, и такой код нельзя зашить в ROM.
Последний раз редактировалось predatoralpha; 14.09.2012 в 00:42.
Хм, сделаю и такой режим Но когда переменные лежат одним блоком, легко реализовать рекурсию. Просто этот блок переменных копировать в стек.
Выхожу на финишную прямую с кодогенератором. Сделал операции < > <= >= == != для uchar. Сделал #define #undef (как полагается с параметрами).
В этом коде еще убрать дублирующиеся присваивания переменных (ld a, 1 ld (print_x), a ld a, 1) или (ld (atoi_a), hl, ld hl, (atoi_a)) и т.д. Эта уборка будет отключатся словом volatile. Объединить XOR A и LD (HL), A, например (xor a ld hl, (clrscr_dest) ld (hl), a). И убрать лишние переходы, например jp $+3 или jp на другой jp.Код:print_return ds 0 print_x ds 1 print_y ds 1 print_text ds 2 print_dest ds 2 print: push bc ld (print_text), hl ; 10 dest = (uchar*)(0xE1D5 + x + y*78); ld hl, (print_x) ld h, 0 ld de, 57813 add hl, de push hl ld d, 78 ld a, (print_y) call mul_uchar pop de add hl, de ld bc, hl ; 11 while(*text) { *dest = *text; dest++; text++; } l2: ld hl, (print_text) ld a, (hl) or a jp z, l3 ; 11 *dest = *text; dest++; text++; } ld hl, (print_text) ld a, (hl) ld (bc), a ; 11 dest++; text++; } inc bc ; 11 text++; } ld hl, (print_text) inc hl ld (print_text), hl jp l2 l3: l1: pop bc ret ;---------------------------------- clrscr_return ds 0 clrscr_dest ds 2 clrscr_c ds 2 clrscr: push bc ; 17 dest = (uchar*)0xE1D0-1; ld hl, 57807 ld (clrscr_dest), hl ; 18 c = 78*25; ld bc, 1950 ; 19 do *++dest = 0; while(c--); l5: ; 19 *++dest = 0; while(c--); ld hl, (clrscr_dest) inc hl ld (clrscr_dest), hl xor a ld hl, (clrscr_dest) ld (hl), a dec bc ld a, b or c jp nz, l5 l4: pop bc ret ;---------------------------------- get: ; 23 return 23; ld hl, 23 jp l6 l6: ret ;---------------------------------- atoi_return ds 0 atoi_str1 ds 2 atoi_a ds 2 atoi_str ds 2 atoi_c ds 1 atoi: push bc ld (atoi_a), hl ; 31 str = str1; ld hl, (atoi_str1) ld bc, hl ; 32 do { l8: ; 33 c = ((uchar)a & 15) + 48; ld a, (atoi_a) and 15 add 48 ld (atoi_c), a ; 34 if('9' < c) c += 7; ld a, (atoi_c) cp 57 jp c, l10 ; 34 c += 7; ld a, (atoi_c) add 7 ld (atoi_c), a l10: ; 35 *str = c; str++; ld a, (atoi_c) ld (bc), a ; 35 str++; inc bc ; 36 a = a >> 4; ld de, 4 ld hl, (atoi_a) call shr_ushort ld (atoi_a), hl ld hl, (atoi_a) ld a, l or h jp nz, l8 ; 38 *str = 0; xor a ld (bc), a l7: pop bc ret ;---------------------------------- main_return ds 0 main_i ds 1 main_x ds 1 main_buf ds 32 main: push bc ; 47 clrscr(); call clrscr ; 48 print(0, 0, "HELLO"); xor a ld (print_x), a xor a ld (print_y), a ld hl, string0 call print ; 49 atoi(buf, 0x12AB); ld hl, main_buf ld (atoi_str1), hl ld hl, 4779 call atoi ; 51 print(1, 1, buf); ld a, 1 ld (print_x), a ld a, 1 ld (print_y), a ld hl, main_buf call print ; 53 i=5; ld b, 5 ; 55 for(x=0; x<64; x+=XYZ(12)) { ld c, 0 l12: ld a, c cp 64 jp nc, l13 l12: ; 56 print(x, i, "12345678.123"); ld a, c ld (print_x), a ld a, b ld (print_y), a ld hl, string1 call print ld a, c add 14 ld c, a jp l12 l13: ; 59 while(1) { l15: ; 60 if(getch() == '1') clrscr(); call getch cp 49 jp nz, l18 ; 60 clrscr(); call clrscr l18: jp l15 l16: l11: pop bc ret
1888 строк 54 Кб.
---------- Post added at 03:23 ---------- Previous post was at 02:47 ----------
Мне написали, что есть компиляторы Си для 8080.
https://github.com/begoon/smallc-scc3, https://github.com/begoon/smallc-85
и работают они так
Код:main() { static char a; for (a = '\0'; a < '\10'; ++a) { a = a + '\1'; } } (специально использовал char везде) генерит адъ типа: ;main() { main: ; static char a; dseg ?2: ds 1 cseg ; for (a = '\0'; a < '\10'; ++a) { lxi h,?2 push h lxi h,0 pop d call ?pchar ?3: lxi h,?2 call ?gchar push h lxi h,12592 pop d call ?lt mov a,h ora l jnz ?5 jmp ?6 ?4: lxi h,?2 push h call ?gchar inx h pop d call ?pchar jmp ?3 ?5: ; a = a + '\1'; lxi h,?2 push h lxi h,?2 call ?gchar push h lxi h,49 pop d dad d pop d call ?pchar ; } jmp ?4 ?6: ;} ?1: ret мой main: push bc ; 3 for (a = 0; a < 10; ++a) { ld b, 0 l1: ld a, b cp 10 jp nc, l2 l1: ; 4 a = a + 1; ld a, b inc a ld b, a inc b jp l1 l2: l0: pop bc ret
Последний раз редактировалось vinxru; 14.09.2012 в 03:15.
С любовью к вам, Yandex.Direct
Размещение рекламы на форуме способствует его дальнейшему развитию
Ну далеко не всегда нужно все переменные копировать в стек. В идеале нужно вести время жизни переменных. Часть переменных уже не используется, часть ещё не присвоены, часть будут безусловно проинициализированы после вызова, и текущее значение не нужно.
А это зачем?
ld hl, (clrscr_dest)
ld (hl), a
Регистр а можно прямо поместить по нужному адресу.
Кстати, 0xE1D5 + x можно ещё оптимальнее
Вместо
ld hl, (print_x)
ld h, 0
ld de, 57813 // 0xE1D5
add hl, de
Сделать
ld hl, (print_x)
ld de, 0x0СD5 // d=E1-D5=0C
ld h, е // На байт короче, на 3 такта быстрее
add hl, de
А вот здесь у тебя неверный код, вроде
while(c--);
dec bc
ld a, b
or c
jp nz, l5
У тебя код не постдекрементный, а преддекрементный. Т.е. для случая while(--c), а не while(c--).
Переменные на стеке нужны для реентабельности процедур. Это не только рекурсия, но и второе в хождение в ту же процедуру из обработчика перерывания. Соответственно, в случае работы системы с прерываниями, копировать глобальные переменные на стек бессмысленно - остается вероятность что по прерыванию будет повторное вхождение пока переменные еще не скопированы. Ну и если будет такое копирование, всякий выигрыш теряется (что про времени выполнения, что по размеру кода). Тогда уж сразу надо делать на стеке.
Последний раз редактировалось Error404; 14.09.2012 в 14:24.
Лучше сделать и жалеть, чем не сделать и жалеть.
Некоторые из моих поделок тут: https://github.com/serge-404
Насчёт реентабельности по прерываниям - да, абсолютно верно, такие процедуры нереентабельные. А вот с "Ну и всякий выигрыш теряется (что про времени выполнения, что по размеру кода)" я не согласен. Для 8080 (не Z80) операции со стеком весьма и весьма мудоёмкие, сжирающие как минимум одну из трёх регистровых пар (HL), которая весьма незаменима, а это постоянные прологи из двух-пяти команд для каждого обращения к стеку. Выигрыш весьма существенный. Особенно в тех случаях, когда возможен анализ кода, есть ли возможность рекурсии при вызове некой функции.
-
Проблема нереентабельности по прерываниям, как по мне, несущественная. Обработчик обычно пишется на ассемблере, если какие-то сишные функции и будут вызываться - то обычно это не те, что выполняются вне прерывания. Этот факт нужно отразить в документации, и принять его "как есть".
-
Более серьёзная проблема, как по мне - это передача ссылки на локальную переменную в некую функцию. Если создаются копии локальных переменных в стеке, то ссылка на локальную переменную "повиснет". А если ещё добавить, что вызываемая функция эту ссылку может сохранить в глобальной переменной, и другая вызываемая функция (из базовой функции) эту ссылку может оттуда поднять... Тут весьма сложный момент. И врядли он будет сделан в соответствии со стандартами языка. Я не хочу сейчас грузить vinxru этой проблемой. Он и так молодец.
Последний раз редактировалось predatoralpha; 14.09.2012 в 14:58.
В ячейке clrscr_dest хранится адрес, который предыдущей строкой увеличивается.
Нет на 8080 команды ld ((clrscr_dest)), A
А вот на PDP-11 есть.
---------- Post added at 14:31 ---------- Previous post was at 14:30 ----------
Да, я пока одну версию операторов написал. Сегодня поправлю, а то забуду.
---------- Post added at 14:34 ---------- Previous post was at 14:31 ----------
Чисто арифметически выигрыш есть. Копируем мы переменную один раз на входе, один на выходе. Причем, копирование всех переменных можно делать за один присест.
А обращаться к переменной мы будем много раз, может быть что 1000 раз.
---------- Post added at 14:35 ---------- Previous post was at 14:34 ----------
Можно продублировать функцию вызываемую из прерывания и из основного кода.
---------- Post added at 14:37 ---------- Previous post was at 14:35 ----------
Это компромисс между
1) Программой, которая умеет рекурсию.
2) И программой, которая работает в 3 раза быстрее.
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)