tutorial raspberry instruction ensamblador data assembly arm

assembly - instruction - ensamblador en raspberry pi



FunciĆ³n ASM de C ARM incrustado (2)

Estoy usando STM32F4 y tratando de escribir una función ASM desde llamada desde C. La función debe ser llamada dentro de una función C y que también está en una interrupción. Estoy presionando y haciendo estallar r4-r7. ¿Debo hacer algo más? Mi suposición es r0-r3 no es necesario presionar. También estoy modificando variables globales dentro de la función ASM. Mi conjetura es que estos deberían declararse volátiles. Cualquier consejo sería bienvenido. También me he dado cuenta de que el conjunto de instrucciones Cortex M4 descrito por ARM no es lo mismo que las instrucciones que parecen estar disponibles para el compilador GCC. Por ejemplo, no hay escritura atrás, es decir, r0, [r1], # 4 para el incremento posterior es ilegal. ¿Hay una lista de las instrucciones de ASM permitidas? Asumo que STM32F4 usa thumb2

Hasta el momento, parece que no funciona y me pregunto cuáles podrían ser los posibles problemas. Además de los errores en el ensamblaje.


¿No pude responder mi propia pregunta hasta que esperé 8 horas? de todos modos aquí es lo que tengo y ¡funciona! Está sucediendo bastante en esta función. Básicamente es un oscilador de onda sinusoidal que utiliza una LUT para valores sinusoidales. También usa una tabla de valores exponenciales que se asignan usando ADC conectado a un pot para control. Hay un acumulador de fase de 32 bits que crea una rampa que luego se escala para buscar. La tabla sinusoidal (que no incluí mucho) es un valor de 16 bits truncado a un tamaño de tabla de 14 bits. Estoy seguro de que hay muchas optimizaciones para hacer en este código, pero al menos me ayuda a comenzar. Estoy generando 16 muestras de onda sinusoidal a 48 k con cada pasada de esta función y llenando un buffer que (fuera de esta función) se transfiere a DMA y se envía a través del códec de Discovery incorporado. Es un sonido muy suave, debo decir. Los ciclos totales de instrucción parecen ser alrededor de 1200 hasta ahora. Tengo hasta 56000 ciclos si los necesito así que esto es bastante bueno. Una cosa con la que estoy teniendo problemas es escalar la salida del seno. La tabla senoidal es int16_t valores y quiero poder multiplicarla por una fracción para obtener control de volumen. Hasta ahora, nada de lo que he intentado funciona usando smul, mul etc.

@ void get_sine(void) .align 2 @ Align to word boundary .global get_sine @ This makes it a real symbol .thumb_func .type get_sine STT_FUNC @ Declare get_sine to be a function. get_sine: @ Start of function definition push {r4-r7} ldr r0,=pitch @ get pitch address ldr r1,=expoLUT @ expo_tab address ldr r7,[r0,#0] @ pitch val into r7 lsl r7,r7,#2 ldr r7,[r1,r7] @ move lookup expo tab value with r7 into r7 ldr r2,=sineLUT @ sine_tab base addy ldr r4,=WaveBuffer @ storage array addy ldr r5,=writePos @ get writepos addr mov r6,#0 @ clear increment r6 outloop: ldr r3,=phase @ phase address to r3 ldr r1,[r3,#0] @ get current phase add r1,r1,r7 @ add current phase and ph_inc str r1,[r3,#0] @ store phase lsr r0,r1,#18 @ shift it right by 18 into r0 for sine_tab lookup lsl r0,r0,#2 @ align it ldr r0,[r2,r0] @ lookup sine val with r0 into r1 lsl r1,r0,#16 @ shift to left channel add r0,r0,r1 @ add right channel ldr r1,[r5,#0] @ get writePos push {r1} @ push it before align lsl r1,r1,#2 @ align address 4 str r0,[r4,r1] @ store sine to WaveBuffer pop {r1} @ pop writepos back add r1,r1,#1 @ increment array pointer writepos ldr r3,=1024 @ load BUFFERSIZE compare cmp r1,r3 @ skip if less than BUFFERSIZE bne skip mov r1,#0 @ clr writepos if >=BUFFERSIZE skip: str r1,[r5,#0] @ store writepos value add r6,r6,#1 @ increment loop counter ldr r0,=dataSize @ get datasize counter addr ldr r1,[r0,#0] @ get val add r1,r1,#1 @ increment datasize counter str r1,[r0,#0] @ store counter cmp r6,#16 @ compare with 16 (i=0;i<16;i++) bne outloop pop {r4-r7} bx lr .section .rodata sineLUT: @ Array goes in here. Type can be .byte, .hword or .word @ NOTE! No comma at the end of a line! This is important .word 0x0000,0x000c,0x0018,0x0024,0x0030,0x003c,0x0048,0x0054 .word 0x0064,0x0070,0x007c,0x0088,0x0094,0x00a0,0x00ac,0x00bc .word 0x00c8,0x00d4,0x00e0,0x00ec,0x00f8,0x0104,0x0114,0x0120 .word 0x012c,0x0138,0x0144,0x0150,0x015c,0x016c,0x0178,0x0184 .word 0x0190,0x019c,0x01a8,0x01b4,0x01c4,0x01d0,0x01dc,0x01e8 .word 0x01f4,0x0200,0x020c,0x021c,0x0228,0x0234,0x0240,0x024c .word


Algunas respuestas a sus preguntas se encuentran en el libro "Procedimiento de llamada estándar para la arquitectura ARM". Aquí está el enlace .

El libro dice que los primeros cuatro registros r0-r3 (y s0-15 para FPU) se utilizan para pasar valores de argumento a una subrutina y para devolver un valor de resultado de una función. También se pueden usar para mantener valores intermedios dentro de una rutina (pero, en general, solo entre llamadas de subrutina). Los registros r4-r8, r10 y r11 (y s16-s31 para FPU) se utilizan para contener los valores de las variables locales de una rutina. Una subrutina debe preservar el contenido de estos registros.

Ahora sobre volatile . Creo que sí, debes usarlo para evitar optimizaciones del compilador que puedan "frenar" tu lógica de programación.

Y sobre tu seno. El inglés no es mi lenguaje natural, por lo que no entiendo muy bien lo que necesita, pero si necesita una aproximación sine rápida y precisa como parte de su problema, puede que le interesen estos artículos: http://devmaster.net/forums / topic / 4648-fast-and-accurate-sinecosine / http://www.coranac.com/2009/07/sines/.

Y el último. Casi he terminado mi función de aproximación sinusoidal para Cortex-M4. Utiliza FPU, toma alrededor de 30 ciclos y trae el resultado de error de zerro en un rango de coma flotante simple.