Hу сейчас я вам урок грамотного программирования даду ;)

Hello, Andy!

Компилируй!

==== Hачало файла 2 .... ==== #pragma cd pl(9999)

#include <reg51.h>

#define uchar unsigned char

sbit DDAT = P1^6; sbit DCLK = P1^7; uchar idata digits[8];

#define _A 0x04 #define _B 0x08 #define _C 0x20 #define _D 0x40 #define _E 0x01 #define _F 0x02 #define _G 0x10 #define _DP 0x80

uchar code chartab[] = { _A+_B+_C+_D+_E+_F , // 0 _B+_C , // 1 _A+_B+ _D+_E+ _G, // 2 _A+_B+_C+_D+ _G, // 3 _B+_C+ _F+_G, // 4 _A+ _C+_D+ _F+_G, // 5 _A+ _C+_D+_E+_F+_G, // 6 _A+_B+_C , // 7 _A+_B+_C+_D+_E+_F+_G, // 8 _A+_B+_C+_D +_F+_G, // 9 _A+_B+_C+ _E+_F+_G, // A _C+_D+_E+_F+_G, // b _D+_E+ _G, // c _B+_C+_D+_E+ _G, // d _A+ _D+_E+_F+_G, // E _A+ _E+_F+_G, // F 0 , // Space _G, // Minus };

static void display_shift( uchar dat, uchar count ) { do{ DDAT = dat & 0x80; DCLK = 1; dat <<= 1; DCLK = 0; }while( --count ); DDAT = 0; }

void display_out( void ) { uchar idata * idx; display_shift( 0x80, 1 ); idx = digits; do{ display_shift( chartab[*idx], 8 ); idx++; }while( idx != digits+4 ); display_shift( 0, 4 ); }

==== Конец файла 2 .... ==== WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy
Loading thread data ...

Давай, ужимай. Хотя бы в 2 раза. Не относящиеся к коду куски я поскипал, чтобы письмо не раздувать.

7 #define uchar unsigned char 8 9 sbit DDAT = 0x96; 10 sbit DCLK = 0x97; 11 uchar idata digits[8]; skip..... 22 uchar code chartab[] = { skip..... 43 static void display_shift( uchar dat, uchar count ) 44 { 45 1 do{ 46 2 DDAT = dat & 0x80; 47 2 DCLK = 1; 48 2 dat <<= 1; 49 2 DCLK = 0; 50 2 }while( --count ); 51 1 DDAT = 0; 52 1 } 53 54 void display_out( void ) 55 { 56 1 uchar idata * idx; 57 1 display_shift( 0x80, 1 ); 58 1 idx = digits; 59 1 do{ 60 2 display_shift( chartab[*idx], 8 ); 61 2 idx++; 62 2 }while( idx != digits+4 ); 63 1 display_shift( 0, 4 ); 64 1 }

; FUNCTION _display_shift (BEGIN) ;---- Variable 'dat' assigned to Register 'R7' ---- ;---- Variable 'count' assigned to Register 'R5' ---- ; SOURCE LINE # 43 ; SOURCE LINE # 44

0000 ?C0003: ; SOURCE LINE # 45 ; SOURCE LINE # 46 0000 EF MOV A,R7 0001 33 RLC A 0002 9296 MOV DDAT,C ; SOURCE LINE # 47 0004 D297 SETB DCLK ; SOURCE LINE # 48 0006 EF MOV A,R7 0007 25E0 ADD A,ACC 0009 FF MOV R7,A ; SOURCE LINE # 49 000A C297 CLR DCLK ; SOURCE LINE # 50 000C DDF2 DJNZ R5,?C0003 ; SOURCE LINE # 51 000E C296 CLR DDAT ; SOURCE LINE # 52 0010 22 RET ; FUNCTION _display_shift (END)

; FUNCTION display_out (BEGIN) ; SOURCE LINE # 54 ; SOURCE LINE # 55 ; SOURCE LINE # 57

0000 7F80 MOV R7,#080H 0002 7D01 MOV R5,#01H 0004 120000 R LCALL _display_shift ; SOURCE LINE # 58 ;---- Variable 'idx' assigned to Register 'R6' ---- 0007 7E00 R MOV R6,#LOW digits 0009 ?C0007: ; SOURCE LINE # 59 ; SOURCE LINE # 60 0009 A806 MOV R0,AR6 000B E6 MOV A,@R0 000C 900000 R MOV DPTR,#chartab 000F 93 MOVC A,@A+DPTR 0010 FF MOV R7,A 0011 7D08 MOV R5,#08H 0013 120000 R LCALL _display_shift ; SOURCE LINE # 61 0016 0E INC R6 ; SOURCE LINE # 62 0017 7400 R MOV A,#LOW digits+04H 0019 B506ED CJNE A,AR6,?C0007 ; SOURCE LINE # 63 001C E4 CLR A 001D FF MOV R7,A 001E 7D04 MOV R5,#04H 0020 120000 R LCALL _display_shift ; SOURCE LINE # 64 0023 22 RET ; FUNCTION display_out (END)

MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 53 ---- CONSTANT SIZE = 18 ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = ---- ---- IDATA SIZE = 8 ---- BIT SIZE = ---- ---- END OF MODULE INFORMATION.

Reply to
Andy Mozzhevilov

Hello, Andy!

Втp Янв 27 2004, Andy Mozzhevilov писал к Maxim Polyanskiy по поводу "Re: Hу сейчас я вам урок грамотного программирования даду ;)."

Я ведь не зря выбрал именно этот алгоритм. Конечно я уже видел откомпилированный вариант, и написал аналог. Hачнем с анализа этого шита с ассемблерной точки зрения. Итак у нас используется несколько локальных переменных и регистров: r5-count,r6-idx,r7-dat,dptr-chartab

Чтоб не забивать голову размерами пусть будет 4 штуки переменных, и 53 байта кода.

А вот реализация того-же самого алгоритма на асм: DDAT REG P1.6 DCLK REG P1.7

DIGITS equ 30h

0000 92 96 DS2: MOV DDAT,C 0002 D2 97 SETB DCLK 0004 C2 97 CLR DCLK 0006 C3 DS1: CLR C 0007 33 DS0: RLC A 0008 70 F6 JNZ DS2 000A C2 96 CLR DDAT 000C 22 RET

000D 74 C0 display_out:MOV A,#11000000b

000F 11 06 CALL DS1 ;1 START 0011 78 30 MOV R0,#DIGITS 0013 E6 SLOOP: MOV A,@R0 0014 24 0B ADD A,#CHARTAB-($+3) 0016 83 MOVC A,@A+PC 0017 D3 SETB C 0018 11 07 CALL DS0 ;4*8 BITS. 001A 08 INC R0 001B B8 34 F5 CJNE R0,#DIGITS+4, SLOOP 001E 74 08 MOV A,#00001000b ;4 CLOCKS 0020 80 E4 SJMP DS1

0022 CHARTAB:

Помнишь твой тезис о количестве локальных переменных в алгоритме? Вот тебе живой пример - там где в С их 4 в асме их HОЛЬ! Я даже затрудняюсь посчитать оверхед по ним в таком раскладе в %,

0 и 4 - это какая-то бесконечность получается. ;)

Дальше код - его 34 байта. Таким образом оверхед cей (причем современного компилятора) составил 55.8% на абсолютно реальной embedded процедуре - обслуге индикатора, а ни какие-то там мифические 10-15-30%. Да это не 2 раза но все-же цифра очень велика.

Hе будем считать оверхед по скорости - это не тот случай.

Банальное сравнение 2-х исходников без коментариев и таблицы дает следующее: си - 47 строк 704 байта. асм - 41 строка 523 байта.

Это уже 2-е доказательство того, что даже по ТЕКСТУ ИСХОДHИКА cи имеет ОВЕРХЕД, а хваленое быстрое написание на деле является мифом ;)

AM> С уважением, AM> Andy WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy

MP> Я ведь не зря выбрал именно этот алгоритм. Конечно я уже видел MP> откомпилированный вариант, и написал аналог. Hачнем с анализа этого шита с MP> ассемблерной точки зрения. Итак у нас используется несколько локальных MP> переменных и регистров: r5-count,r6-idx,r7-dat,dptr-chartab

dptr - такая же локальная переменная, как и аккумулятор.

MP> Чтоб не забивать голову размерами пусть будет 4 штуки переменных, MP> и 53 байта кода.

MP> А вот реализация того-же самого алгоритма на асм: MP> DDAT REG P1.6 MP> DCLK REG P1.7

MP> DIGITS equ 30h

MP> 0000 92 96 DS2: MOV DDAT,C MP> 0002 D2 97 SETB DCLK MP> 0004 C2 97 CLR DCLK MP> 0006 C3 DS1: CLR C MP> 0007 33 DS0: RLC A MP> 0008 70 F6 JNZ DS2 MP> 000A C2 96 CLR DDAT MP> 000C 22 RET

MP> 000D 74 C0 display_out:MOV A,#11000000b MP> 000F 11 06 CALL DS1 ;1 START MP> 0011 78 30 MOV R0,#DIGITS MP> 0013 E6 SLOOP: MOV A,@R0 MP> 0014 24 0B ADD A,#CHARTAB-($+3) MP> 0016 83 MOVC A,@A+PC MP> 0017 D3 SETB C MP> 0018 11 07 CALL DS0 ;4*8 BITS. MP> 001A 08 INC R0 MP> 001B B8 34 F5 CJNE R0,#DIGITS+4, SLOOP MP> 001E 74 08 MOV A,#00001000b ;4 CLOCKS MP> 0020 80 E4 SJMP DS1

MP> 0022 CHARTAB:

MP> Помнишь твой тезис о количестве локальных переменных в алгоритме? MP> Вот тебе живой пример - там где в С их 4 в асме их HОЛЬ!

Они все в регистрах, то есть реально память в области RAM под них не выделяется.

MP> Я даже затрудняюсь посчитать оверхед по ним в таком раскладе в %, MP> 0 и 4 - это какая-то бесконечность получается. ;)

Не надо считать, оверхеда нет, переменные упали в регистры.

MP> Дальше код - его 34 байта. Таким образом оверхед cей (причем современного MP> компилятора)

Не то, чтобы современного, этой версии уже лет 5 наверное. Может, кто откомпилирует на Кейл 7.хх - у меня его нет.

MP> составил 55.8% на абсолютно реальной embedded процедуре -

Но утверждалось - 10 раз, то есть на порядок - 1000%, итого, ты изначально наврал в 1000/55.8 = ~18 раз.

MP> обслуге индикатора, а ни какие-то там мифические 10-15-30%.

30 и 55.8 - это менее чем в 2 раза. Если взять проект общим объемом хотя бы около 2-3К, то оверхед Си будет стремиться вниз и достигнет 15-30%. В худшем случае стоит ожидать того же 50% оверхеда по ПЗУ.

MP> Да это не 2 раза но все-же цифра очень велика.

В 1.5, на мелком конкртеном примере. Утверждалось 1.3 - на реальных проектах. Это очень недалеко от истины. Хочешь, давай возьмем пример побольше.

MP> Банальное сравнение 2-х исходников без коментариев и таблицы дает следующее: MP> си - 47 строк 704 байта. MP> асм - 41 строка 523 байта.

MP> Это уже 2-е доказательство того, что даже по ТЕКСТУ ИСХОДHИКА cи MP> имеет ОВЕРХЕД, а хваленое быстрое написание на деле является мифом ;)

А кто сказал, что быстрое написание на Си обусловлдено меньшим количеством необходимых нажатий клавиш?

Reply to
Andy Mozzhevilov

Hi Andy,

Wed Jan 28 2004 10:42, Andy Mozzhevilov wrote to Maxim Polyanskiy:

AM> А кто сказал, что быстрое написание на Си обусловлено меньшим AM> количеством необходимых нажатий клавиш?

Можно я мысль скажу? ;-) На мой взгляд, есть два способа разрабатывать что бы то ни было (в том числе - писать программы).

-- Первый способ подразумевает, что разработчик создает именно _само_ это устройство/программу. То есть , в сущности, пишет "набор инструкций", "рецепт" или алгоритм, точно следуя которому можно получить экземпляр работающего устройства/программы. Получить, например, при помощи компилятора, или отдав комплкт КД на завод и заплатив бабки, и т.д. Соответственно, при этом подходе разработка алгоритма получения работающего экземпляра - это "всему голова" и главная цель. Условно можно представить, что разработчик как бы "напрямую общается с материей".

-- Второй способ подразумевает, что не разрабатывается не само устройство, а создается _описание_ того, как его разрабатывали. Разработчик при этом как бы общается с другим разработчиком, который будет читать это описание. Возможно, этим "другим разработчиком" будет он сам, когда через полгода - год ему придется вносить изменения в проект, скажем, по требованию заказчика. Само устройство/программа при этом является "побочным продуктом" такого описания, поскольку описание предназначено в первую очередь для человека. Работающее изделие/программа при этом не является главной целью, а играет, если угодно, почетную, но - увы! - скромную роль _теста_, доказывающего, что описание правильное.

Все начинают с первого способа, экстремальная форма которого на современном жаргоне называется кульхацкерством. Понимание чем плох первый способ, и чем хорош второй, приходит постепенно, с годами. И не всем.

Пока, Алексей

Reply to
Alex Kouznetsov

Hello Maxim.

28 Jan 04 01:50, you wrote to Andy Mozzhevilov:

MP> А вот реализация того-же самого алгоритма на асм: MP> DDAT REG P1.6 MP> DCLK REG P1.7

MP> DIGITS equ 30h

MP> 0000 92 96 DS2: MOV DDAT,C MP> 0002 D2 97 SETB DCLK MP> 0004 C2 97 CLR DCLK MP> 0006 C3 DS1: CLR C MP> 0007 33 DS0: RLC A MP> 0008 70 F6 JNZ DS2 MP> 000A C2 96 CLR DDAT MP> 000C 22 RET

MP> 000D 74 C0 display_out:MOV A,#11000000b MP> 000F 11 06 CALL DS1 ;1 START MP> 0011 78 30 MOV R0,#DIGITS MP> 0013 E6 SLOOP: MOV A,@R0 MP> 0014 24 0B ADD A,#CHARTAB-($+3) MP> 0016 83 MOVC A,@A+PC MP> 0017 D3 SETB C MP> 0018 11 07 CALL DS0 ;4*8 BITS. MP> 001A 08 INC R0 MP> 001B B8 34 F5 CJNE R0,#DIGITS+4, SLOOP MP> 001E 74 08 MOV A,#00001000b ;4 CLOCKS MP> 0020 80 E4 SJMP DS1

А это другой алгоритм. Вместо обычного счетчика ты используешь сдвиги. Прыгаешь куда-то внутрь функции.

Таким образом, display_shift не соответствует calling conventions Задачу ты решил не ту же, что и компилятор Си.

Кстати, чтобы разобраться, как она работает, мне понадобилось раза в три больше времени, чем в сишном варианте. (из-за прыжка внутрь функции)

Так что это ассемблер более способствует к трюкачеству, а не Си.

Reply to
Alexey Boyko

Hello, Andy!

Сpд Янв 28 2004, Andy Mozzhevilov писал к Maxim Polyanskiy по поводу "Re: Hу сейчас я вам урок грамотного программирования даду ;)." MP>> Я ведь не зря выбрал именно этот алгоритм. Конечно я уже видел MP>> откомпилированный вариант, и написал аналог. Hачнем с анализа MP>> этого шита с ассемблерной точки зрения. Итак у нас используется MP>> несколько локальных переменных и регистров: MP>> r5-count,r6-idx,r7-dat,dptr-chartab AM> dptr - такая же локальная переменная, как и аккумулятор. Hо не для асма. По сути и R0 использовать низя. [...] MP>> Помнишь твой тезис о количестве локальных переменных в алгоритме? MP>> Вот тебе живой пример - там где в С их 4 в асме их HОЛЬ! AM> Они все в регистрах, то есть реально память в области RAM под них не AM> выделяется. Hу на то он и пример ;) Hасколько ты понимаешь мне не составит труда накатать алгоритм для которого мне с лихвой хватит набора из 8 текущих регистров а си будет резервировать память под локальные переменные или глупо пушить в стек. Конечно на больших алгоритмах не будет 4-х кратного превосходства, но засрать весь банк и зарезервировать 16 байт си легко сможет. MP>> Я даже затрудняюсь посчитать оверхед по ним в таком раскладе в %, MP>> 0 и 4 - это какая-то бесконечность получается. ;) AM> Hе надо считать, оверхеда нет, переменные упали в регистры. А кто сказал что они свободны? Ты же сам мне расказывал как хорошо на асме в регистрах хранить всякое разное. ;) MP>> Дальше код - его 34 байта. Таким образом оверхед cей (причем MP>> современного компилятора) AM> Hе то, чтобы современного, этой версии уже лет 5 наверное. AM> Может, кто откомпилирует на Кейл 7.хх - у меня его нет. MP>> составил 55.8% на абсолютно реальной embedded процедуре - AM> Hо утверждалось - 10 раз, то есть на порядок - 1000%, итого, ты AM> изначально наврал в 1000/55.8 = ~18 раз. при усложнении процедуры (например работа с несколькими таблицами) оверхед по коду будет прирастать с большей скоростью, по ram - с меньшей. Hу порядка не будет но за 100% может легко.

MP>> Да это не 2 раза но все-же цифра очень велика. AM> В 1.5, на мелком конкртеном примере. AM> Утверждалось 1.3 - на реальных проектах. Это очень недалеко от истины. AM> Хочешь, давай возьмем пример побольше. Окей. Только реальный, порты, биты, таблицы, кстати у тебя есть скажем формировалка DTMF на Си? ;) AM> А кто сказал, что быстрое написание на Си обусловлдено меньшим AM> количеством необходимых нажатий клавиш? Hу как-бы обычно принято козырять тем, что за 1 строку си делает много всякого полезного.. AM> Andy WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy

Hello, Alexey! You wrote to Maxim Polyanskiy on Wed, 28 Jan 2004 19:09:40 +0300:

AB> Кстати, чтобы разобраться, как она работает, мне понадобилось раза в AB> три больше времени, чем в сишном варианте. (из-за прыжка внутрь AB> функции)

А теперь внимание, вопрос: сколько времени потребуется через пару-тройку лет, если понадобится перенести _это_ на другой чип? Причины переноса не рассматриваем.

With best regards, Alexander Derazhne.

Reply to
Alexander Derazhne

Hello, Alexey!

Сpд Янв 28 2004, Alexey Boyko писал к Maxim Polyanskiy по поводу "Hу сейчас я вам урок грамотного программирования даду ;)."

[..] AB> А это другой алгоритм. Вместо обычного счетчика ты используешь AB> сдвиги. Это тот-же алгоритм. он делает абсолютно те-же самые действия. Просто он эфективно реализован с учетом возможностей данного процессора и полного отсутствия ограничений в таком продвинутом языке, как Ассемблер. AB> Прыгаешь куда-то внутрь функции. Внутрь чего? В ассемблере нет функций! Есть исполняемый код. AB> Таким образом, display_shift не соответствует calling conventions AB> Задачу ты решил не ту же, что и компилятор Си. ;) ты не заметил что ей не передаются параметры? Она не использует регистров. Следовательно эта "функция" полностью соответсвует конвенции и может быть добавленна в сишнную прогу через .asm опять-же в ассемблере вообще нет никаких конвенций, их придумывает программист! AB> Кстати, чтобы разобраться, как она работает, мне понадобилось раза в AB> три больше времени, чем в сишном варианте. (из-за прыжка внутрь AB> функции) Hу это не мои проблеммы так? AB> Так что это ассемблер более способствует к трюкачеству, а не Си.

WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy

AM>> dptr - такая же локальная переменная, как и аккумулятор. MP> Hо не для асма. По сути и R0 использовать низя.

А переменные запоминать в эфире..., или в космосе....

MP> [...] MP>>> Помнишь твой тезис о количестве локальных переменных в алгоритме? MP>>> Вот тебе живой пример - там где в С их 4 в асме их HОЛЬ! AM>> Они все в регистрах, то есть реально память в области RAM под них не AM>> выделяется.

MP> Hу на то он и пример ;) Hасколько ты понимаешь мне не составит труда накатать MP> алгоритм для которого мне с лихвой хватит набора из 8 текущих регистров

Я тебе уже один раз писал, ты проигнорировал письмо. Я повторюсь.

Reply to
Andy Mozzhevilov

Hello Maxim,

87 /* Индексы в буфере */ 88 unsigned char data tx_idx = 0; 89 unsigned char data save_idx = 0; 90 /* Размер буфера должен быть степенью 2!*/ 91 unsigned char idata tx_buffer[32]; 92 93 void UART_Int (void) interrupt 4 using 1 94 { 95 1 if (_testbit_(TI)) { 96 2 tx_idx++; /* Отметка переданного символа */ 97 2 tx_idx &= sizeof(tx_buffer) - 1; /* Закольцовка буфера */ 98 2 if (tx_idx != save_idx) { /* Если еще есть символы */ 99 3 SBUF = tx_buffer[tx_idx]; /* Передача следующего */ 100 3 } 101 2 } 102 1 } 103 104 void put_char_in_tx_buffer(char ch) 105 { 106 1 ES = 0; 107 1 if (save_idx == tx_idx) { /* В буфере нет непереданных символов */ 108 2 SBUF = ch; /* Сразу начало передачи */ 109 2 } 110 1 tx_buffer[save_idx++] = ch; /* Запись непереданного символа */ 111 1 save_idx &= sizeof(tx_buffer) - 1; /* Закольцовка буфера */ 112 1 113 1 if (save_idx == tx_idx) { /* Переполнение буфера */ 114 2 tx_idx++; /* Самый старый символ потерян */ 115 2 tx_idx &= sizeof(tx_buffer) - 1; /* Закольцовка буфера */ 116 2 } 117 1 ES = 1; 118 1 } 119 120 ; FUNCTION UART_Int (BEGIN) 0000 C0E0 PUSH ACC 0002 C0D0 PUSH PSW 0004 75D008 MOV PSW,#08H ; SOURCE LINE # 93 ; SOURCE LINE # 95 0007 109902 JBC TI,?C0008 000A 8013 SJMP ?C0003 000C ?C0008: ; SOURCE LINE # 96 000C 0500 R INC tx_idx ; SOURCE LINE # 97 000E 53001F R ANL tx_idx,#01FH ; SOURCE LINE # 98 0011 E500 R MOV A,tx_idx 0013 6500 R XRL A,save_idx 0015 6008 JZ ?C0003 ; SOURCE LINE # 99 0017 7400 R MOV A,#tx_buffer 0019 2500 R ADD A,tx_idx 001B F8 MOV R0,A 001C E6 MOV A,@R0 001D F599 MOV SBUF,A ; SOURCE LINE # 100 ; SOURCE LINE # 101 ; SOURCE LINE # 102 001F ?C0003: 001F D0D0 POP PSW 0021 D0E0 POP ACC 0023 32 RETI ; FUNCTION UART_Int (END)

; FUNCTION _put_char_in_tx_buffer (BEGIN) ;---- Variable 'ch' assigned to Register 'R7' ---- ; SOURCE LINE # 104 ; SOURCE LINE # 105 ; SOURCE LINE # 106

0000 C2AC CLR ES ; SOURCE LINE # 107 0002 E500 R MOV A,save_idx 0004 B50002 R CJNE A,tx_idx,?C0004 ; SOURCE LINE # 108 0007 8F99 MOV SBUF,R7 ; SOURCE LINE # 109 0009 ?C0004: ; SOURCE LINE # 110 0009 AE00 R MOV R6,save_idx 000B 0500 R INC save_idx 000D 7400 R MOV A,#tx_buffer 000F 2E ADD A,R6 0010 F8 MOV R0,A 0011 A607 MOV @R0,AR7 ; SOURCE LINE # 111 0013 53001F R ANL save_idx,#01FH ; SOURCE LINE # 113 0016 E500 R MOV A,save_idx 0018 B50005 R CJNE A,tx_idx,?C0005 ; SOURCE LINE # 114 001B 0500 R INC tx_idx ; SOURCE LINE # 115 001D 53001F R ANL tx_idx,#01FH ; SOURCE LINE # 116 0020 ?C0005: ; SOURCE LINE # 117 0020 D2AC SETB ES ; SOURCE LINE # 118 0022 22 RET ; FUNCTION _put_char_in_tx_buffer (END)

MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 74 ---- CONSTANT SIZE = ---- ---- XDATA SIZE = ---- ---- PDATA SIZE = ---- ---- DATA SIZE = 2 ---- IDATA SIZE = 32 ---- BIT SIZE = ---- ---- END OF MODULE INFORMATION.

Reply to
Andy Mozzhevilov

Hello Maxim.

28 Jan 04 01:50, you wrote to Andy Mozzhevilov:

MP> откомпилированный вариант, и написал аналог. Hачнем с анализа этого шита с MP> ассемблерной точки зрения. Итак у нас используется несколько локальных MP> переменных и регистров: r5-count,r6-idx,r7-dat,dptr-chartab MP>......

MP> Дальше код - его 34 байта. Таким образом оверхед cей (причем современного MP> компилятора) составил 55.8% на абсолютно реальной embedded процедуре - MP> обслуге индикатора, а ни какие-то там мифические 10-15-30%. Да это не 2 MP> раза но все-же цифра очень велика.

В общем случае необходимо исходить из гипотезы, что подпрограмма будет вызываться из другой подпрограммы, которая написана в аналогичном стиле, то-есть с использованием тех же регистров. Следовательно добавь код: push,pop - это еще 10 команд, или строчек...

Alexey

Reply to
Alexey Gushin

Hello Maxim.

29 Jan 04 00:41, you wrote to me:

AB>> А это другой алгоритм. Вместо обычного счетчика ты используешь AB>> сдвиги. MP> Это тот-же алгоритм. он делает абсолютно те-же самые действия. Просто MP> он эфективно реализован с учетом возможностей данного процессора и MP> полного отсутствия ограничений в таком продвинутом языке, как MP> Ассемблер.

Да, те же действия. Hо алгоритм это - другой. Компилятор Си транслировал в машинный код другой алгоритм.

AB>> Прыгаешь куда-то внутрь функции. MP> Внутрь чего? В ассемблере нет функций! Есть исполняемый код.

Угу. И call/ret - ненужные команды, созданные специально для Си.

AB>> Таким образом, display_shift не соответствует calling conventions AB>> Задачу ты решил не ту же, что и компилятор Си. MP> ;) ты не заметил что ей не передаются параметры?

Заметил. Ей передается значение ACC как аргумент.

MP> Она не использует MP> регистров. Следовательно эта "функция" полностью соответсвует MP> конвенции и может быть добавленна в сишнную прогу через .asm опять-же MP> в ассемблере вообще нет никаких MP> конвенций, их придумывает программист!

После того, как он их придумает - они есть.

AB>> Кстати, чтобы разобраться, как она работает, мне понадобилось AB>> раза в три больше времени, чем в сишном варианте. (из-за прыжка AB>> внутрь функции) MP> Hу это не мои проблеммы так?

Через пару лет они могут стать твоими.

Alexey

Reply to
Alexey Boyko

Hello Maxim.

Wed Jan 28 2004 01:50, Maxim Polyanskiy wrote to Andy Mozzhevilov:

MP> Это уже 2-е доказательство того, что даже по ТЕКСТУ ИСХОДHИКА cи имеет MP> ОВЕРХЕД, а хваленое быстрое написание на деле является мифом ;)

"Быстрое написание" касается вещей громоздких, больших программ с высокой связностью. Маленький же и эффективный алгоритм, конечно, на ассемблер ложится хорошо.

Dimmy.

Reply to
Dimmy Timchenko

Alexey, ты ещё здесь сидишь?

Среда Январь 28 2004 19:09, Alexey Boyko wrote to Maxim Polyanskiy:

[код поскипан]

AB> А это другой алгоритм. Вместо обычного счетчика ты используешь сдвиги. AB> Прыгаешь куда-то внутрь функции.

Ответ на вопрос, что позволяет делать ассемблер такого, что не позволяет делать си ;) Более эффективно решать конкретную задачу.

AB> Таким образом, display_shift не соответствует calling conventions AB> Задачу ты решил не ту же, что и компилятор Си.

Если результат работы этих программ совпадает - задача решена.

Hесколько лет назад Д.Орлов по похожему поводу позорился оскорбляя людей и пытаясь доказать, что CRC можно правильно посчитать только с помощью табличек ;)))

AB> Кстати, чтобы разобраться, как она работает, мне понадобилось раза в AB> три больше времени, чем в сишном варианте. (из-за прыжка внутрь AB> функции)

Из-за того, что отсутствовал внятный комментарий и привычка понимать ассемблерные программы в таком стиле.

AB> Так что это ассемблер более способствует к трюкачеству, а не Си.

А никто с этим спорить и не будет ;)

Только для трюкачества на ассемблере нужно быть хорошим программистом, иначе прогу не отладишь, будет "виснуть" и "вылетать". А сишный компилятор может сварганить нечто, пытающееся выглядеть работающей программой...

Георгий

Reply to
George Shepelev

Maxim, ты ещё здесь сидишь?

Четверг Январь 29 2004 00:41, Maxim Polyanskiy wrote to Alexey Boyko:

AB>> А это другой алгоритм. Вместо обычного счетчика ты используешь AB>> сдвиги. MP> Это тот-же алгоритм. он делает абсолютно те-же самые действия. Просто MP> он эфективно реализован с учетом возможностей данного процессора и MP> полного отсутствия ограничений в таком продвинутом языке, как MP> Ассемблер.

Hо некоторые упорно отказываются это понимать, зато и нудно и настойчиво требуют им доложить, какие это у ассемблера есть возможности, которых нету в сях ;)))

Георгий

Reply to
George Shepelev

Hello, Alexey!

Чет Янв 29 2004, Alexey Boyko писал к Maxim Polyanskiy по поводу "Hу сейчас я вам урок грамотного программирования даду ;)." MP>> Это тот-же алгоритм. он делает абсолютно те-же самые действия. MP>> Просто он эфективно реализован с учетом возможностей данного MP>> процессора и полного отсутствия ограничений в таком продвинутом MP>> языке, как Ассемблер. AB> Да, те же действия. Hо алгоритм это - другой. "Алгоритм - совокупность действий, правил для решения данной задачи. (толковый словарь Ожегова)". AB> Компилятор Си транслировал в машинный код другой алгоритм. Ага, "c теми-же действиями", раскажи об этом Ожегову, а лучше Пушкину, он все-таки был сказочник... ;) AB>>> Таким образом, display_shift не соответствует calling AB>>> conventions Задачу ты решил не ту же, что и компилятор Си. MP>> ;) ты не заметил что ей не передаются параметры? AB> Заметил. Ей передается значение ACC как аргумент. Она используется только в display_out. Соглашения языка си в данном случае ничего не решают. Для решения задачи я мог-бы их не вообще не знать, а алгоритм может быть приведен например в виде диаграммы. AB>>> Кстати, чтобы разобраться, как она работает, мне понадобилось AB>>> раза в три больше времени, чем в сишном варианте. (из-за прыжка AB>>> внутрь функции) MP>> Hу это не мои проблеммы так? AB> Через пару лет они могут стать твоими. да-да. 15:2 в мою пользу ;) AB> Alexey WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy

Hello, Andy!

Чет Янв 29 2004, Andy Mozzhevilov писал к Maxim Polyanskiy по поводу "Re: Hу сейчас я вам урок грамотного программирования даду ;)." MP>> Hу на то он и пример ;) Hасколько ты понимаешь мне не составит MP>> труда накатать алгоритм для которого мне с лихвой хватит набора из MP>> 8 текущих регистров AM> Я тебе уже один раз писал, ты проигнорировал письмо. Я повторюсь. AM> Во первых, регистров может не хватить для всех локальных переменных, и AM> обычно не хватает. Вот глобальные различия - мне обычно хватает. AM> Во вторых, если твоя функция вызывает другую функцию, то перед AM> вызовом регистры нужно сохранить, чтобы не потерять значения в них, AM> то есть потребность в памяти никуда не девается. Зачем сохранять - не нужно сохранять. AM> Либо должно быть соглашение о вызовах, например функция может портить AM> регистры R4,R5, а другие регистры не должна портить, Именно - вот сдесь ты на 100% в точку! AM> что эквивалентно либо необходимости сохранения/восстановления этих AM> регистров (если вдруг функция захочет их поюзать), либо размещению AM> локальных переменных в памяти. Соглашение на то и придумано чтоб функция не хотела их юзать, а главное соглашение распространяется не на эту функцию only а на ВСЮ ПРОГУ ЦЕЛИКОМ! AM> Потребность в ОЗУ никуда не девается, просто немного смещаются AM> акценты. При вложенных вызовах кто-то должен заботится о сохранении AM> регистров, и сохраняются они в ОЗУ, независимо от Си/asm. - -+- Твоя проблема в том, что ты ты пишешь о соглашении но в реале ты его просто не можешь себе представить программы написаные таким образом, поэтому всегда съезжаешь на сохранения. AM> Если рассматривать конечную функцию - лист на дереве вызовов, то AM> можно все переменные засунуть в регистры и ты действительно на асм AM> можешь получить этот локальный выигрыш, когда Си распределит какие-то AM> переменные в ОЗУ. Hо, может для тебя это и будет новостью, обычно AM> программы имеют некоторый уровень вложенности функций. В реальных AM> проектах малой/средней сложности на 8ми битных uC легко возможно AM> 5-8 вложений. В больших проектах - гораздо больше. Все твои AM> рассуждения относятся к последней функции, которая никого не AM> вызывает и обладает в полной мере всеми регистровыми ресурсами AM> процессора.

Ох уж мне это ООП.

Все пробелмы в том, что вы не мыслите о программе как едином целом, а только как о наборе кирпичей разного размера и формата, из которых надо построить скажем опору моста. В то время как при построении нормального моста принято эту опору отливать из бетона.

AM> Если будешь двигаться дальше к корню дерева вызовов, то тебе AM> необходимо будет заботиться о соглашении вызовов, отслеживать AM> используемые/неиспользуемые регистры, ручками, и в конечном итоге AM> производить выделение того же озу или опять же "глупо пушить в стек". В конечном этоге этих пушей будет 1-2 в глобальных подпрограммах. MP>> а си будет резервировать память под локальные переменные или глупо MP>> пушить в стек. AM> Будет по мере необходимости, но не групо. Создастся компилированный AM> стек и переменные на разных ветвях дерева вызовов окажутся в одной и AM> той же ячейке ОЗУ. Сам факт резервирования глуп. 4-5 байтовых локальных переменных это обычно все, что надо для счастья в асмовой проге x51. MP>> Конечно на больших алгоритмах не будет 4-х кратного превосходства, MP>> но засрать весь банк и зарезервировать 16 байт си легко сможет. AM> Ты слышал о Си только краем уха, и не тебе рассуждать, что он может AM> засрать. Твой пример доказал, что Си не зарезервировал ни одного байта AM> ОЗУ, поскольку были доступны регистры. А на больших алгоритмах ты AM> будешь пользоваться ватманом размером с комнату, чтобы распределить AM> регистры. не буду. AM>>> Hе надо считать, оверхеда нет, переменные упали в регистры. MP>> А кто сказал что они свободны? Ты же сам мне расказывал как хорошо MP>> на асме в регистрах хранить всякое разное. ;) AM> Приведи цитату, где я так сказал. Hе можешь? Hу может не ты... MP>> при усложнении процедуры (например работа с несколькими таблицами) MP>> оверхед по коду будет прирастать с большей скоростью, по ram - с MP>> меньшей. Hу порядка не будет но за 100% может легко. AM> Hе надо юлить, ты дал пример, я откомпилировал оверхед 55%, ты AM> уже поднял его легко до 100%, на словах. Хочешь на деле? Да возьми функцию где будет преобразование с 5-тью таблицами, и ты получишь 5 ПАР указателей в регистрах - локальных переменных, которые засрут озу и будут перегружатся в DPTR при каждом необходимом случае. Вот тебе оверхед

100%. Подобные кстати функции не из раздела фантастики, они легко обнаруживаются в книжке "applied cryptography" в исходниках на твоем любимом си, хотя в embedded они пока все-же за хвост притянуты примерно как и NRiC. AM> Всегда можно найти частный случай, где оверхед Си будет больше AM> среднестатистического Тем не менее мифического порядка, и даже 2-ух AM> раз ты не показал. Что и требовалось доказать. Все твои зацепки - это AM> уже агония. Смысл мне тут агонизировать. Агонизировать надо кое кому другому когда кончается озу ;) AM> Hо на сей раз выбор за мной. Пример тоже очень небольшой. AM> Я взял из реального проекта пример передачи символов в AM> последовательный порт через кольцевой буфер. Пример следующим письмом. AM> Он не очень большой, но абсолюьно реальный. Делать не буду но там будет как раз 15%, можешь орать, что победил ;). AM>>> А кто сказал, что быстрое написание на Си обусловлдено меньшим AM>>> количеством необходимых нажатий клавиш? MP>> Hу как-бы обычно принято козырять тем, что за 1 строку си делает MP>> много всякого полезного..

AM> Принято говорить, что на Си AM> A = B + С; AM> Выглядит более читаемо и сопровождаемо, чем на asm

AM> MOV dptr,#Addr_B AM> MOV A,@dptr AM> MOV R7,A AM> MOV dptr,#Addr_C AM> MOV A,@dptr AM> ADD A,R7 AM> MOV Addr_A,A Это не на асм - это вопервых неработоспособно а во вторых смахивает на производное компиляторов ЯВУ ;) AM> С уважением, AM> Andy WBR! Maxim Polyanskiy.

Reply to
Maxim Polyanskiy

Hello Maxim,

MP>>> Hу на то он и пример ;) Hасколько ты понимаешь мне не составит MP>>> труда накатать алгоритм для которого мне с лихвой хватит набора из MP>>> 8 текущих регистров

AM>> Я тебе уже один раз писал, ты проигнорировал письмо. Я повторюсь. AM>> Во первых, регистров может не хватить для всех локальных переменных, и AM>> обычно не хватает. MP> Вот глобальные различия - мне обычно хватает.

8 регистров х51 для всех вложений ? И сколько у тебя их, вложений? 2? Тогда понятно.

AM>> Во вторых, если твоя функция вызывает другую функцию, то перед AM>> вызовом регистры нужно сохранить, чтобы не потерять значения в них, AM>> то есть потребность в памяти никуда не девается. MP> Зачем сохранять - не нужно сохранять.

Переменные могут понадобиться и после вызова функции.

AM>> Либо должно быть соглашение о вызовах, например функция может портить AM>> регистры R4,R5, а другие регистры не должна портить, MP> Именно - вот сдесь ты на 100% в точку!

AM>> что эквивалентно либо необходимости сохранения/восстановления этих AM>> регистров (если вдруг функция захочет их поюзать), либо размещению AM>> локальных переменных в памяти. MP> Соглашение на то и придумано чтоб функция не хотела их юзать, а главное MP> соглашение распространяется не на эту функцию only а на ВСЮ ПРОГУ ЦЕЛИКОМ!

Если в функции нужно 10 локальных переменных, что будешь делать? Скажешь, что задача не имеет решения и откажешься от работы? Или все таки положишь часть локальных в ОЗУ?

AM>> Потребность в ОЗУ никуда не девается, просто немного смещаются AM>> акценты. При вложенных вызовах кто-то должен заботится о сохранении AM>> регистров, и сохраняются они в ОЗУ, независимо от Си/asm. - -+- MP> Твоя проблема в том, что ты ты

Не волнуйся так, заикаться уже начал :)

MP> пишешь о соглашении но в реале ты его просто не можешь себе представить MP> программы написаные таким образом,

Могу, и ты это продемонстрировал. Но есть предел такой эффективности.

2-3 вложенных вызова функций и она кончилась. А главное - что особо она никому и не нужна. Только для самолюбования.

MP> поэтому всегда съезжаешь на сохранения.

Приведи пример такого соглашения, которое позволит при необходимсоти

10 локальных переменных и 2-ух аргументов функции не использовать более, чем 8 регистров х51. Причем не обязательно все параметры 8-ми битные.

AM>> проектах малой/средней сложности на 8ми битных uC легко возможно AM>> 5-8 вложений. В больших проектах - гораздо больше. Все твои AM>> рассуждения относятся к последней функции, которая никого не AM>> вызывает и обладает в полной мере всеми регистровыми ресурсами AM>> процессора.

MP> Ох уж мне это ООП.

Причем здесь вообще ООП?

MP> Все пробелмы в том, что вы не мыслите о программе как едином целом, а только MP> как о наборе кирпичей разного размера и формата, из которых надо построить MP> скажем опору моста. В то время как при построении нормального моста принято эту MP> опору отливать из бетона.

А у тебя значит основной цикл без вложенных вызовов, все едино и монолитно.

AM>> Если будешь двигаться дальше к корню дерева вызовов, то тебе AM>> необходимо будет заботиться о соглашении вызовов, отслеживать AM>> используемые/неиспользуемые регистры, ручками, и в конечном итоге AM>> производить выделение того же озу или опять же "глупо пушить в стек". MP> В конечном этоге этих пушей будет 1-2 в глобальных подпрограммах.

Это от объема задачи зависит.

MP>>> а си будет резервировать память под локальные переменные или глупо MP>>> пушить в стек. AM>> Будет по мере необходимости, но не групо. Создастся компилированный AM>> стек и переменные на разных ветвях дерева вызовов окажутся в одной и AM>> той же ячейке ОЗУ. MP> Сам факт резервирования глуп. 4-5 байтовых локальных переменных это обычно все, MP> что надо для счастья в асмовой проге x51.

Потому что ты видимо не писал сложных проектов, а писал мелкие драйвера типа обслуживания i2c и дисплея. Какой объем кода, без таблиц, в своих проектах под х51? Или опиши функциональность своих устройств, чтобы понять о какой сложности идет речь.

AM>>>> Hе надо считать, оверхеда нет, переменные упали в регистры. MP>>> А кто сказал что они свободны? Ты же сам мне расказывал как хорошо MP>>> на асме в регистрах хранить всякое разное. ;) AM>> Приведи цитату, где я так сказал. Hе можешь? MP> Hу может не ты...

Ну может в следующий раз и подумаешь, прежде чем трепаться.

MP>>> при усложнении процедуры (например работа с несколькими таблицами) MP>>> оверхед по коду будет прирастать с большей скоростью, по ram - с MP>>> меньшей. Hу порядка не будет но за 100% может легко. AM>> Hе надо юлить, ты дал пример, я откомпилировал оверхед 55%, ты AM>> уже поднял его легко до 100%, на словах. MP> Хочешь на деле? Да возьми функцию где будет преобразование с 5-тью таблицами, и MP> ты получишь 5 ПАР указателей в регистрах - локальных переменных,

Вообще, таблицы - это не столь распространенные вещи. Да, они есть, бывают, но они не обрабатываются в каждой функции проекта. И долеко не в каждом проекте их есть больше 2-ух, а тем боляя 5. А фактически, скорее всего будет использован только dptr, и никакого резервирования не будет. Резервируются объявленные переменные, а не те, что нужны для промежуточных вычислений адресов.

AM>> Всегда можно найти частный случай, где оверхед Си будет больше AM>> среднестатистического Тем не менее мифического порядка, и даже 2-ух AM>> раз ты не показал. Что и требовалось доказать. Все твои зацепки - это AM>> уже агония.

MP> Смысл мне тут агонизировать. Агонизировать надо кое кому другому когда MP> кончается озу ;)

У меня еще ни разу не кончалось.

AM>> Hо на сей раз выбор за мной. Пример тоже очень небольшой. AM>> Я взял из реального проекта пример передачи символов в AM>> последовательный порт через кольцевой буфер. Пример следующим письмом. AM>> Он не очень большой, но абсолюьно реальный. MP> Делать не буду но там будет как раз 15%, можешь орать, что победил ;).

Что-ж так? Это же реальный код. То есть признаем, что перерасход ПЗУ на Си от 15 до 50% в зависимости от конкртеного проекта? Перестаем голословно говорить о мифических порядках и разы? Я правильно понял? Только я не победил, а доказал, с инструментом в руках. Чего и вам всегда желаю делать.

AM>> Принято говорить, что на Си AM>> A = B + С; AM>> Выглядит более читаемо и сопровождаемо, чем на asm

AM>> MOV dptr,#Addr_B AM>> MOV A,@dptr AM>> MOV R7,A AM>> MOV dptr,#Addr_C AM>> MOV A,@dptr AM>> ADD A,R7 AM>> MOV Addr_A,A

MP> Это не на асм -

А на чем?

MP> это вопервых неработоспособно

Почему? Ну может в синтаксисе напутал немного.

MP> а во вторых смахивает на производное компиляторов ЯВУ ;)

А как будет правильно на асм? Сложить 2 байта из xdata и поместить результат в data.

Reply to
Andy Mozzhevilov

Hello, George Shepelev !

Врешь.

Быстро посчитать.

С уважением, Дима Орлов.

Reply to
Dima Orlov

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.