La forma más eficiente de cambiar el orden en el que se leen los datos en el ensamblaje

0

Tengo una asignación de ensamblaje que me obliga a poder almacenar un número y, a través de una tabla de búsqueda, genera el número en una pantalla de 7 seg, tanto en orden directo como inverso, según el estado de un interruptor de entrada. Si bien no es un requisito, me gustaría usar la menor cantidad de ciclos y códigos que pueda y seguir las buenas prácticas de codificación.

Mi idea actual es almacenar el número dos veces (una vez en cualquier dirección) y elegir la dirección de memoria de inicio según el estado del interruptor. De esta manera, solo necesito una rutina de búsqueda que esencialmente lea cualquiera de los números en la dirección de fwd.

Una alternativa que he considerado es tener dos rutinas de búsqueda. Uno que incluye Z y otro que lo decrementa. Esto tiene la ventaja obvia de que solo requiere un número almacenado a expensas de líneas adicionales de código.

¿Alguno de estos enfoques es aceptable o hay otros métodos que no he considerado?

Tiendo a pensar que lo primero es más efectivo pero menos flexible que lo segundo.

    
pregunta BenG

2 respuestas

2

le recomiendo encarecidamente que no intente " utilizar el menor número de ciclos y el código que pueda ".

Esto hará que sea inútilmente difícil tener éxito.

Le recomiendo que primero haga funcionar el programa, usando el enfoque técnico con el que se sienta más cómodo.

Luego, si tienes tiempo restante, pule el código de la forma que quieras.

Los desarrolladores profesionales con experiencia llaman a esfuerzos como " usar la menor cantidad de ciclos y código que puedo " optimización prematura .

Es una de las principales causas de falla en entregar el software adecuado a tiempo.

Personalmente, primero encuentro que las soluciones funcionan, con el objetivo de que funcionen principalmente en aproximadamente el 40% del tiempo, generalmente me da una idea de las mejores estrategias para resolver el problema.

Una buena comprensión del problema y un 'banco de pruebas' operativo que resuelve el problema, que puedo manipular y ejecutar la prueba en contra, generalmente superan las tácticas de pequeña escala como centrarse en las instrucciones mínimas o en la menor cantidad de ciclos cada vez.

Si desea crear un programa que sea óptimo de alguna manera, cree un programa simple que comprenda primero.

Hacer un programa que funcione, funcione mejor es casi siempre más fácil que intentar que un programa restringido (el más pequeño, el más rápido, ...) funcione en absoluto.

Estoy muy familiarizado con C, y bastante bien con AVR. Así que probablemente lo escribiría primero en C, tan simple como pudiera, y luego leería la salida del ensamblador del compilador. No escribirá código como un aprendizaje humano para codificar. Probablemente será mucho mejor. Sin embargo, proporcionará la mayoría de las instrucciones necesarias y un objetivo para vencer.

Creo que tener el número almacenado una vez, y usar el interruptor para decidir dos cosas:

  1. qué extremo comenzar, y
  2. qué agregar a la dirección de la posición de inicio (-1)

puede ser bastante sencillo. La rutina de visualización tomará esos dos valores como parámetros (-1 en el registro y la dirección de inicio en otro par)

Editar:
AFAIK, el procesador AVR fue diseñado deliberadamente para ser un objetivo para los compiladores de C (lo que hace que su asignación parezca un poco extraña, pero es probable que sea eficaz para ayudar a entender lo que está sucediendo "debajo de las portadas"). Así que puedes hacerlo mejor, pero gcc debería ser razonablemente bueno, y una coincidencia relativamente fácil con la C

Puede hacer algunos trucos extraños, porque, AFAIK, se ha pulido durante más de 15 años, por lo que puede tener trucos astutos para afeitar un ciclo o una instrucción aquí y allá

    
respondido por el gbulmer
1

No todo el lenguaje ensamblador se crea de la misma manera. Voy a utilizar el ensamblaje ARM, compatible con GCC 4.8, para esta respuesta.

Si me pidieran que hiciera esto en C, casi seguro que comenzaría en la parte superior de una matriz y luego disminuiría a través de ella. Esta selección podría realizarse mediante algún tipo de sentencia if, lo que sea deseable en su código.

Algo como esto:

int sumListBackward(int *numPtr, int listLen) { int acc = 0; int i; for(i = (listLen - 1); i >= 0; i--) { acc += *(numPtr+i); } return acc; }

Produce una salida de ensamblaje de algo como esto (nuevamente, ARM gcc 4.8.2)

sumListBackward(int*, int):
    push    {r7}
    sub sp, sp, #20
    add r7, sp, #0
    str r0, [r7, #4]
    str r1, [r7]
    movs    r3, #0
    str r3, [r7, #8]
    ldr r3, [r7]
    subs    r3, r3, #1
    str r3, [r7, #12]
    b   .L8
.L9:
    ldr r3, [r7, #12]
    lsls    r3, r3, #2
    ldr r2, [r7, #4]
    add r3, r3, r2
    ldr r3, [r3]
    ldr r2, [r7, #8]
    add r3, r3, r2
    str r3, [r7, #8]
    ldr r3, [r7, #12]
    subs    r3, r3, #1
    str r3, [r7, #12]
.L8:
    ldr r3, [r7, #12]
    cmp r3, #0
    bge .L9
    ldr r3, [r7, #8]
    mov r0, r3
    adds    r7, r7, #20
    mov sp, r7
    ldr r7, [sp], #4
    bx  lr

Joder, probablemente podrías hacerlo más eficiente si quisieras. Sin embargo, es exactamente el mismo número de instrucciones que para resumir la lista, así que creo que ganaría eficiencia en general al hacerlo de esta manera: tener dos arreglos en la memoria implica que tiene que hacer ambos arreglos, lo que requiere ciclos de reloj.

Si estamos hablando de ciclos de reloj sin formato, tener una matriz e iterar sobre ella de dos maneras probablemente será más rápido.

    
respondido por el Ken

Lea otras preguntas en las etiquetas