|
Не удается повторить сишный код в асме АРМ., контроллер at91sam7s |
|
|
|
Nov 23 2009, 06:15
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
мне необходимо реализовать на асм-е следующий сишный код: Код if(datA&0x80000000) regA = 0x20000; else regA = 0x0; Но операнд в ARM-команде может иметь макс длину 12 бит, поэтому в асм-е я поступаю следующим образом: Код ;r1 = datA, regA = r6 mov r6, r1 mov r6, r6, lsr #28 and r6, r6, #0x8 ldrne r6, =0x20000 ;if(datA&0x80000000) regA = 0x20000 ldreq r6, =0 ;else regA = 0x0 это правильно? Заранее благодарен.
|
|
|
|
|
Nov 23 2009, 06:34
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
мне необходимо реализовать на асм-е следующий сишный код - обработчик прерывания таймера: Код __ramfunc void timer0_irq_handler() { ii--; if(ii==0) {MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS;} MipsTimerBase->TC_RA = 30; MipsTimerBase->TC_RB = MipsTimerBase->TC_RC = 60; if(datA&0x80000000) regA = 0x20000; else regA = 0x0; regs->PIOA_ODSR = regA|front; datA = datA<<1; dummy = MipsTimerBase->TC_SR; } Этот код рабочий, благодаря ему я получаю необходимую последовательность импульсов на выходе. Так я повторил этот код на асме АРМ: При прирывании вызываетя следующая функция: __ramfunc void ASM_timer0_irq() { timer0_irq_ASM(ii,datA,front); } которая в свою очередь вызывает асм-функциюи сообщает туда 3 параметра. Код IO_base DEFINE 0xFFFFF400 ODSR DEFINE 0x38 TC_base DEFINE 0xFFFA0000 TC0_CCR DEFINE 0x0 TC0_RA DEFINE 0x14 TC0_RB DEFINE 0x18 TC0_RC DEFINE 0x1C TC0_SR DEFINE 0x20 TC_CLKDIS DEFINE 0x2
PUBLIC timer0_irq_ASM timer0_irq_ASM ;r0 = ii, r1 = dataA, r2 = front
ldr r12,=TC_base ;смещение для TC ldr r11,=IO_base ;смещение для PIO sub r0, r0, #1 ;ii-- beq Stop_TC0 bne Work_TC0
Stop_TC0: ldr r7, =TC_CLKDIS str r7,[r12,#TC0_CCR] ;MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS b timer0_irq_ASM_end Work_TC0: ldr r7, =30 str r7,[r12, #TC0_RA] ;MipsTimerBase->TC_RA = 30 ldr r7, =60 str r7, [r12, #TC0_RB] ;MipsTimerBase->TC_RB = 60 str r7, [r12, #TC0_RC] ;MipsTimerBase->TC_RC = 60 mov r6, r1, lsr #28 ;смещаем содержимое r1 (datA) вправо на 28 бит, так как операнд не может быть больше 12 бит в длину, а мне необходимо анализировать состояние 32-бита r1 and r6, r6, #0x8 ldrne r6, =0x20000 ;if(datA&0x80000000) regA = 0x20000 ldreq r6, =0 ;else regA = 0x0 orr r6, r6, r2 str r6, [r11, #ODSR] ;regs->PIOA_ODSR = regA|front mov r0, r0, lsl #1 ;datA = datA<<1 ldr r6, [r12, #TC0_SR] ;dummy = MipsTimerBase->TC_SR
timer0_irq_ASM_end: bx lr асм-код не работает так же, как и сишный. то есть таймер запускается, импульсы нужной частоты идут, но таймер не останавливается при обнулении счетчика ii и не меняет ldrne r6, =0x20000 или ldreq r6, =0 в зависимости от содержимого r1. Заранее благодарен.
Сообщение отредактировал Bulat - Nov 23 2009, 07:05
|
|
|
|
|
Nov 23 2009, 06:50
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Bulat @ Nov 23 2009, 09:34)  это правильно? Нет, правильно будет так: Код ;r1 = datA, regA = r6 ANDS r6,r1,#0x80000000 MOVNE r6,#0x20000 Числа вида "константа со сдвигом" можно загружать командой MOV. Ну а вообще в таких конструкциях бесполезно пытаться переплюнуть C-компилятор.
|
|
|
|
|
Nov 23 2009, 07:30
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Bulat @ Nov 23 2009, 09:34)  асм-код не работает так же, как и сишный Для начала стоит ознакомится с тем кодом, который был сгенерирован компилятором - на 100% уверен, что он компактнее и быстрее приведенного ассемблерного фрагмента (пожалуй, даже при выключенной оптимизации). Кроме того, если уж хотите использовать ассемблер, стоит почитать стандарт AAPCS - ваш код может быть неработоспособен хотя бы потому, что с регистрами R4-R11 так обращаться нельзя. Да, ну и логика работы C и asm программ у вас отличаются - первая не вываливается по условию "if(ii==0)".
|
|
|
|
|
Nov 23 2009, 09:13
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(aaarrr @ Nov 23 2009, 13:30)  Да, ну и логика работы C и asm программ у вас отличаются - первая не вываливается по условию "if(ii==0)". Почему не выходит по условию ii==0? Код sub r0, r0, #1 ;ii-- beq Stop_TC0 ;r0 == 0 bne Work_TC0 ;r0 !=0 где тут ошибка?
|
|
|
|
|
Nov 23 2009, 09:27
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Bulat @ Nov 23 2009, 15:13)  Почему не выходит по условию ii==0? Код sub r0, r0, #1 ;ii-- где тут ошибка? sub не устанавливает флаги. Нужно SUB S
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Nov 23 2009, 09:44
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(GetSmart @ Nov 23 2009, 15:27)  sub не устанавливает флаги. Нужно SUBS вроде все исправил. но картинка на осциллографе без изменений. таймер запускается с нужной частотой, но не останавливается когда нужно и данные не передаются: Код IO_base DEFINE 0xFFFFF400 ODSR DEFINE 0x38 TC_base DEFINE 0xFFFA0000 TC0_CCR DEFINE 0x0 TC0_RA DEFINE 0x14 TC0_RB DEFINE 0x18 TC0_RC DEFINE 0x1C TC0_SR DEFINE 0x20 TC_CLKDIS DEFINE 0x2
PUBLIC timer0_irq_ASM timer0_irq_ASM ;r0 = ii, r1 = dataA, r2 = front
ldr r12,=TC_base ;смещение, для обращения к регистрам TC subs r0, r0, #1 ;ii-- bne Work_TC0 beq Stop_TC0 Stop_TC0: ldr r3, =TC_CLKDIS str r3,[r12,#TC0_CCR] ;MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS b timer0_irq_ASM_end Work_TC0: ldr r3, =30 str r3,[r12, #TC0_RA] ;MipsTimerBase->TC_RA = 30 ldr r3, =60 str r3, [r12, #TC0_RB] ;MipsTimerBase->TC_RB = 60 str r3, [r12, #TC0_RC] ;MipsTimerBase->TC_RC = 60 ands r3, r1, #0x80000000 movne r3, #0x20000 ;if(datA&0x80000000) regA = 0x20000 moveq r3, #0 ;else regA = 0x0 orr r3, r3, r2 ldr r12,=IO_base str r3, [r12, #ODSR] ;regs->PIOA_ODSR = regA|front mov r0, r0, lsl #1 ;datA = datA<<1 ldr r12,=TC_base ldr r3, [r12, #TC0_SR] ;dummy = MipsTimerBase->TC_SR
timer0_irq_ASM_end: bx lr
|
|
|
|
|
Nov 23 2009, 10:18
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(aaarrr @ Nov 23 2009, 16:02)  Bulat, вы с дизассемблированным кодом C-программы ознакомились? От этого надо начинать. Более того, могу с уверенностью сказать, что руками оптимизировать там нечего. В дизассемблированном коде программы на одну операцию сдвига datA = datA<<1 приходится 5 асм-команд, в то время, как у меня в асм-коде на это тратится одна команда mov r0, r0, lsl #1. А можно в Си-коде, допустим, в качестве сдвиговой переменной datA назначить один из регистров r0,r1,... и напрямую к нему обращаться из сишного когда?
|
|
|
|
|
Nov 23 2009, 10:30
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(GetSmart @ Nov 23 2009, 16:23)  А вот это что за ерунда? R2 это что? r2 - это регистр, через который передается значение третьего аргумента функции timer0_irq_ASM, вызываемой из Си-кода при приходе прирывания: __ramfunc void ASM_timer0_irq() { timer0_irq_ASM(ii,datA,front); }
|
|
|
|
|
Nov 23 2009, 10:41
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Bulat @ Nov 23 2009, 13:18)  В дизассемблированном коде программы на одну операцию сдвига datA = datA<<1 приходится 5 асм-команд, в то время, как у меня в асм-коде на это тратится одна команда mov r0, r0, lsl #1. Не верю. Листинг приложите. Цитата(Bulat @ Nov 23 2009, 13:18)  А можно в Си-коде, допустим, в качестве сдвиговой переменной datA назначить один из регистров r0,r1,... и напрямую к нему обращаться из сишного когда? Да компилятор сам все замечательно сделает, если только вы ему мешать не будете. Где, например, в вашей C-программе локальные переменные?
|
|
|
|
|
Nov 23 2009, 11:06
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(aaarrr @ Nov 23 2009, 16:41)  Не верю. Листинг приложите.
Да компилятор сам все замечательно сделает, если только вы ему мешать не будете. Где, например, в вашей C-программе локальные переменные? Дизассемблерный код для функции: Код void timer0_irq_handler() { ii--; if(ii==0) {MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS;} MipsTimerBase->TC_RA = 30; MipsTimerBase->TC_RB = MipsTimerBase->TC_RC = 60; if(datA&0x80000000) regA = 0x20000; else regA = 0x0; regs->PIOA_ODSR = regA|front; datA = datA<<1; dummy = MipsTimerBase->TC_SR; } Код timer0_irq_handler: 0000083C E59F041C LDR R0, [PC, #+1052] ; [0xC60] =ii (0x2001B0) 00000840 E59F1418 LDR R1, [PC, #+1048] ; [0xC60] =ii (0x2001B0) 00000844 E5911000 LDR R1, [R1, #+0] 00000848 E2511001 SUBS R1, R1, #0x1 0000084C E5801000 STR R1, [R0, #+0] if(ii==0) {MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS;} 00000850 E59F0408 LDR R0, [PC, #+1032] ; [0xC60] =ii (0x2001B0) 00000854 E5900000 LDR R0, [R0, #+0] 00000858 E3500000 CMP R0, #0x0 0000085C 1A000003 BNE 0x000870 if(ii==0) {MipsTimerBase->TC_CCR = AT91C_TC_CLKDIS;} 00000860 E59F03FC LDR R0, [PC, #+1020] ; [0xC64] =MipsTimerBase (0x17B4) 00000864 E5900000 LDR R0, [R0, #+0] 00000868 E3A01002 MOV R1, #0x2 0000086C E5801000 STR R1, [R0, #+0] MipsTimerBase->TC_RA = 30; MipsTimerBase->TC_RB = MipsTimerBase->TC_RC = 60; 00000870 E59F03EC LDR R0, [PC, #+1004] ; [0xC64] =MipsTimerBase (0x17B4) 00000874 E5900000 LDR R0, [R0, #+0] 00000878 E3A0101E MOV R1, #0x1E 0000087C E5801014 STR R1, [R0, #+20] MipsTimerBase->TC_RA = 30; MipsTimerBase->TC_RB = MipsTimerBase->TC_RC = 60; 00000880 E3A0003C MOV R0, #0x3C 00000884 E59F13D8 LDR R1, [PC, #+984] ; [0xC64] =MipsTimerBase (0x17B4) 00000888 E5911000 LDR R1, [R1, #+0] 0000088C E581001C STR R0, [R1, #+28] 00000890 E59F13CC LDR R1, [PC, #+972] ; [0xC64] =MipsTimerBase (0x17B4) 00000894 E5911000 LDR R1, [R1, #+0] 00000898 E5810018 STR R0, [R1, #+24] if(datA&0x80000000) regA = 0x20000; 0000089C E59F03B8 LDR R0, [PC, #+952] ; [0xC5C] =datA (0x2001A0) 000008A0 E5900000 LDR R0, [R0, #+0] 000008A4 E3100480 TST R0, #0x80000000 000008A8 0A000003 BEQ 0x0008BC if(datA&0x80000000) regA = 0x20000; 000008AC E59F03A0 LDR R0, [PC, #+928] ; [0xC54] =regA (0x2001AC) 000008B0 E3A01B80 MOV R1, #0x20000 ; 0x208B8 000008B4 E5801000 STR R1, [R0, #+0] 000008B8 EA000002 B 0x0008C8 else regA = 0x0; 000008BC E59F0390 LDR R0, [PC, #+912] ; [0xC54] =regA (0x2001AC) 000008C0 E3A01000 MOV R1, #0x0 ; 0x8C8 000008C4 E5801000 STR R1, [R0, #+0] regs->PIOA_ODSR = regA|front; 000008C8 E59F0380 LDR R0, [PC, #+896] ; [0xC50] =regs (0x200000) 000008CC E5900000 LDR R0, [R0, #+0] 000008D0 E59F137C LDR R1, [PC, #+892] ; [0xC54] =regA (0x2001AC) 000008D4 E5911000 LDR R1, [R1, #+0] 000008D8 E59F2378 LDR R2, [PC, #+888] ; [0xC58] =front (0x200108) 000008DC E5922000 LDR R2, [R2, #+0] 000008E0 E1921001 ORRS R1, R2, R1 000008E4 E5801438 STR R1, [R0, #+1080] datA = datA<<1; 000008E8 E59F036C LDR R0, [PC, #+876] ; [0xC5C] =datA (0x2001A0) 000008EC E59F1368 LDR R1, [PC, #+872] ; [0xC5C] =datA (0x2001A0) 000008F0 E5911000 LDR R1, [R1, #+0] 000008F4 E1B01081 MOVS R1, R1, LSL #1 000008F8 E5801000 STR R1, [R0, #+0] dummy = MipsTimerBase->TC_SR; 000008FC E59F0120 LDR R0, [PC, #+288] ; [0xA24] =dummy (0x2001C8) 00000900 E59F135C LDR R1, [PC, #+860] ; [0xC64] =MipsTimerBase (0x17B4) 00000904 E5911000 LDR R1, [R1, #+0] 00000908 E5911020 LDR R1, [R1, #+32] 0000090C E5801000 STR R1, [R0, #+0] } 00000910 E12FFF1E BX LR обратите внимание на: Код datA = datA<<1; 000008E8 E59F036C LDR R0, [PC, #+876] ; [0xC5C] =datA (0x2001A0) 000008EC E59F1368 LDR R1, [PC, #+872] ; [0xC5C] =datA (0x2001A0) 000008F0 E5911000 LDR R1, [R1, #+0] 000008F4 E1B01081 MOVS R1, R1, LSL #1 000008F8 E5801000 STR R1, [R0, #+0] переменный datA,ii,front, используемы в обработчике прерывания, глобальные, так как они используются еще и в другой функции
|
|
|
|
|
Nov 23 2009, 11:16
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Bulat @ Nov 23 2009, 17:06)  переменный datA,ii,front, используемы в обработчике прерывания, глобальные, так как они используются еще и в другой функции Ну и кто их будет в раме-то менять когда функция на асме? В случае плохого владения асмом всё делается так: ставится максимальная (spd/size) оптимизация и полученный листинг тупо копируется на уровне асм-команд  После этого ничего уже от оптимизации не зависит. В некоторых случаях удаётся ещё оптимизировать листинг, но надо хорошо владеть асмом.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Nov 23 2009, 11:51
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
я имел в виду лишние обращения к памяти, которых в моем коде нет: 000008E8 E59F036C LDR R0, [PC, #+876] ; [0xC5C] =datA (0x2001A0) 000008EC E59F1368 LDR R1, [PC, #+872] ; [0xC5C] =datA (0x2001A0) 000008F0 E5911000 LDR R1, [R1, #+0]
000008F4 E1B01081 MOVS R1, R1, LSL #1 - собственно само смещение.
000008F8 E5801000 STR R1, [R0, #+0]
|
|
|
|
|
Nov 23 2009, 12:19
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(sergeeff @ Nov 23 2009, 14:10)  Совет: плюньте вы на ассемблер, ничего вы с бухты-барахты там не наоптимизируете, по сравнению с С/С++ компилятором. Или ... Используйте FIQ конкретно для одного только этого прерывания, храните свои переменные в R8, R9, R10. R11, R12 можете пользовать как рабочие регистры. R0...R7 по возможности не трогайте, чтобы их не надо было сохранять. Цитата Код beq Stop_TC0 bne Work_TC0
Stop_TC0: здесь инструкция beq лишняя, т.к. и без нее выполнение перейдет на Stop_TCO когда рез-тат==0.
|
|
|
|
|
Nov 23 2009, 12:46
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Bulat @ Nov 23 2009, 14:06)  переменный datA,ii,front, используемы в обработчике прерывания, глобальные, так как они используются еще и в другой функции А RegA и dummy - просто под горячую руку попали? Цитата(Bulat @ Nov 23 2009, 14:51)  я имел в виду лишние обращения к памяти, которых в моем коде нет Ну, оптимизатор явно выключен. Для нормально откомпилированной функции дизассемблер будет выглядеть примерно так: Код 0x00000000: e59fc168 h... LDR r12,[pc,#360] ; [.data$0 = 0x170] = 0 0x00000004: e59c0004 .... LDR r0,[r12,#4] 0x00000008: e2501001 ..P. SUBS r1,r0,#1 0x0000000c: e28c0000 .... ADD r0,r12,#0 0x00000010: e58c1004 .... STR r1,[r12,#4] 0x00000014: e5900010 .... LDR r0,[r0,#0x10] 0x00000018: 03a01002 .... MOVEQ r1,#2 0x0000001c: 05801000 .... STREQ r1,[r0,#0] 0x00000020: e3a0101e .... MOV r1,#0x1e 0x00000024: e5801014 .... STR r1,[r0,#0x14] 0x00000028: e3a0103c <... MOV r1,#0x3c 0x0000002c: e580101c .... STR r1,[r0,#0x1c] 0x00000030: e5801018 .... STR r1,[r0,#0x18] 0x00000034: e59c100c .... LDR r1,[r12,#0xc] 0x00000038: e59c3008 .0.. LDR r3,[r12,#8] 0x0000003c: e2112102 .!.. ANDS r2,r1,#0x80000000 0x00000040: 13a02802 .(.. MOVNE r2,#0x20000 0x00000044: e1822003 . .. ORR r2,r2,r3 0x00000048: e59c3014 .0.. LDR r3,[r12,#0x14] 0x0000004c: e5832038 8 .. STR r2,[r3,#0x38] 0x00000050: e1a01081 .... LSL r1,r1,#1 0x00000054: e58c100c .... STR r1,[r12,#0xc] 0x00000058: e5900020 ... LDR r0,[r0,#0x20] 0x0000005c: e12fff1e ../. BX r14 Так что попробуйте сначала освоить инструмент.
|
|
|
|
|
Nov 23 2009, 12:49
|
Местный
  
Группа: Участник
Сообщений: 206
Регистрация: 12-10-06
Из: ufa
Пользователь №: 21 241

|
Цитата(sergeeff @ Nov 23 2009, 18:10)  У вас в С-ой программе сплошь глобальные переменные, а в ASM варианте вы с ними работаете, как с локальными (т.е. вы как-то манипулируете значениями в регистрах, но не значениями в памяти). Конечно все получается короче, но неправильно.
Совет: плюньте вы на ассемблер, ничего вы с бухты-барахты там не наоптимизируете, по сравнению с С/С++ компилятором. тогда у меня вопрос, из-за которого я и взялся за оптимизацию. но его я задам в следующей теме, так как тут уже слишком много ответов.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|