La reunión requiere: llamadas de subrutina y el desafío 1K

La primera computadora que poseía personalmente tenía 256 bytes de memoria. Bytes. El procesador de mi mouse y teclado tienen más memoria que eso. Mucho más. De acuerdo, 256 bytes era un poco extremo, pero incluso los sistemas integrados que construí como parte de mi trabajo en ese entonces generalmente tenían una pequeña porción de los 64K bytes de memoria que podían manejar.

Algunas personas probablemente se alegran de no tener que preocuparse más por esas cosas. Yo lo extraño un poco. A menudo era como un rompecabezas tratando de extraer diez bytes más de EPROM para corregir errores o insertar una nueva función. Sin embargo, con el desafío 1K, podría compartir algunos de los trucos que usamos en esos días para trabajar. alrededor de los pequeños problemas de memoria.

No puedo ayudarte ...

Desafortunadamente, este nivel de optimización a menudo requiere soluciones específicas y nadie puede ayudarlo a menos que sepa exactamente lo que está haciendo. A menudo, las mejores formas de ahorrar memoria implican cambiar su algoritmo o utilizar funciones específicas de la CPU. Por ejemplo, si tiene muchas cadenas pero no necesita muchos caracteres, tal vez pueda empaquetar sus cadenas. A la derecha de una CPU, puede gastar dos bytes escribiendo:

MOV B,#0

Esto supuestamente vacía un registro hipotético B y generalmente toma dos bytes de codificación (un byte para el MOV con un campo de bits que indica el registro B y otro byte para el cero literal). Sin embargo, si está disponible, una instrucción XOR probablemente ocupa un byte:

XOR B,B

Esto también pone a cero los registros B porque el XOR de cualquier cosa consigo mismo es cero. La resta podría hacer lo mismo, si está disponible.

Sin embargo, todos estos son específicos de su proyecto y plataforma. Así que para esas cosas estás solo.

Pero, algunas cosas son universales

Una de las formas más fáciles de cambiar su programa es sobre programas. La mayoría de las CPU tienen algún tipo de facilidad para llamar y devolver (aunque mi computadora de 256 bytes no lo hizo, por extraño que parezca). La primera regla es usarlos. Si tiene cuatro o cinco instrucciones para repetir, es un buen candidato para un trabajo. Sentido común, ¿verdad? Pero hay algunos otros trucos sobre las subrutinas que debe recordar.

La primera idea es buscar artículos que pueda mover a una función, incluso si requiere un poco de adaptación en algún lugar del código. Para ilustrar esto (y algunas otras ideas) fui a este simulador de lenguaje ensamblador en línea. Tiene un lenguaje ensamblador simple que se parece a las CPU reales. Además, la opción de poder navegar por el código en su navegador web es buena. Por supuesto, tendrá que aplicar los conceptos a su CPU específica.

A continuación se muestra un programa simple para leer una cadena ASCII de cuatro caracteres, que representa un número decimal y lo coloca en un registro de 16 bits. Entonces, la cadena se convertirá en 00FF en el registro.

; Simple example
; Convert decimal # at istring into 16-bits in B:C
   JMP start

start:
   CALL convert
; more interesting things happen here
   HLT
convert:
   MOV B,0
   MOV C,0  ; answer in B:C
   MOV D, istring    ; Point to var
   CALL decdig  ; convert each digit
   INC D
   CALL decdig
   INC D
   CALL decdig
   INC D
    CALL decdig
    RET

shift16:
   MOV A,0
   SHL C,1
   JNC shift16a
   INC A
shift16a:
   SHL B,1
   ADD B,A   ; output carry is meaningless
   RET

decdig:
   CALL shift16; *2
   PUSH B
   PUSH C
   CALL shift16; *4
   CALL shift16    ; *8
   POP A
   ADD C,A   ; 8X+2X=10X!
   JNC decdig0
   INC B

decdig0:
   POP A
   ADD B,A
   MOV A,[D]
   SUB A,'0'
   ADD C,A
   JNC xret
   INC B
xret:
   RET

istring: DB "1924" ; input
         DB 0 ; String terminator

end:

Esto se junta en 89 bytes. No mucho, pero podemos hacerlo mejor. Lo primero que hay que tener en cuenta es que el registro D contiene la dirección de la cadena. El programa lo carga inicialmente y después de cada llamada a la subrutina de conversión digital, hay un incremento para indicar el siguiente carácter. Una forma obvia de ahorrar espacio es tener en cuenta la instrucción incremental en la función. Puede ponerlo al final o, si tiene más sentido, cargar la dirección menos uno (la mayoría de los ensambladores pueden resolver esto durante el ensamblaje). En este caso no importa, pero en ambos casos llegará a 85 bytes. Puse la declaración POP D después de la etiqueta xret y la rutina de conversión ahora se ve así:

convert:
MOV B,0
MOV C,0 ; answer in B:C
MOV D, istring ; Point to var
CALL decdig ; convert each digit
CALL decdig
CALL decdig
CALL decdig
RET

Note esas dos últimas líneas. Puede recortar un byte cambiando la CALL final a JMP. La devolución al final de decdig volverá a la persona que llamó originalmente. Puede ahorrar aún más espacio reorganizando el código para que aparezca una decodificación exactamente en ese lugar:

CALL decdig
CALL decdig
CALL decdig
decdig: ...

Puedes aplicar esto aún más. Tenga en cuenta que tiene 4 llamadas para descifrar que podrían considerarse dos grupos de dos. Entonces podrías escribir:

CALL decdig2
decdig2:
CALL decdig
decdig: ....

Puede que tengas que pensar en eso por un minuto. La primera llamada realiza dos operaciones y la devolución vuelve a decdig2 donde realiza dos operaciones adicionales. Al final, la devolución vuelve al llamante original.

Legibilidad

Eso no es muy legible, lo admito. Los comentarios son gratuitos, por lo que debe utilizarlos si no está escribiendo una publicación de blog sobre el código. Especialmente cualquier código de tiempo depende de estar en un lugar específico, debe documentarlo:

CALL decdig2:
; **** FALL THROUGH
decdig2:

Esto evita que lo mueva accidentalmente o ingrese un código y rompa cosas. Ahora estamos en 80 bytes. Puede hacer el mismo truco con el programa de cambio Shift16, pero como se llama solo una vez, no hay ahorros reales en este caso.

Ahorrar 9 bytes no parece mucho, pero es aproximadamente el 10% del código original. A veces eso es todo lo que necesitas. Probablemente también podría optimizar el algoritmo.

Conversiones de devolución

En algunas CPU, puede realizar un retorno condicional (es decir, como un retorno en cero o RZ). Pero en otros procesadores, puede simplemente hacer una condición de salto o salto. Esto conduce a dicho código:

JNZ nextinst
RET
nextinst:

Sin embargo, probablemente tenga un retorno en algún lugar de su código (como la etiqueta xret en el programa de muestra). Eso significa que puedes escribir:

JZ xret

Allí guardó otro byte. Como monedas de un centavo, todas se suman.

Tu turno

¿Cuál es tu ahorrador de espacio favorito? Compártelo en los comentarios a menos que quieras mantenerlo como tu salsa secreta para el desafío 1K. Tienes hasta el 5 de enero para exprimir esos bytes adicionales.

  • Jacques1956 dice:

    En un procesador que solo cambia 1 bit a la vez, cuando desea cambiar 4 bits, se necesitan 4 instrucciones

    Ejemplo de rango medio mejorado de PIC:
    “Lslf WREG
    lslf var1
    lslf var1
    lslf var1 "`
    Esto se puede reducir a
    "" Swapf WREG
    andlw 0xf0; aguanta un bocado alto "
    El mismo truco se puede usar cuando se cambia a la derecha 4 veces:
    "` Lsrf WREG
    andlw 0xf; mantener un bocado bajo "

    • Jacques1956 dice:

      ¡Ooop! debería ser:
      lslf WREG
      lslf WREG
      lslf WREG
      lslf WREG

  • Mike Bradley dice:

    Cuando codifico un microcontrolador, tiendo a usar c, luego miro mi archivo de lista, reescribo las secciones para ver cómo se traducen.

    Para mí, en uC, es dual, acelera el programa y ahorra espacio en el programa.

    Como les digo a las personas, guardar 1 instrucción en un ciclo que se ejecuta 1 millón de veces por segundo significa que 1 millón de otras instrucciones funcionan al mismo tiempo.

    • ruedas dice:

      En uno de los viejos boletines 'DTACK Grounded', Hal Hardenberg argumentó que hacerlo era el enfoque equivocado, ya que comenzar con C (o cualquier otro lenguaje avanzado) imponía límites a las estructuras de datos y la organización del código, que el uso de lenguaje ensamblador no debería 'T trudi. Es por eso que usar el montaje desde cero le ha permitido encontrar formas más efectivas de hacer las cosas que lo que permitiría un lenguaje de alto nivel.

      Dicho esto, probablemente sea una forma más eficiente de hacer las cosas que codificar todo desde cero en el ensamblaje.

      • treinta y uno dice:

        Es un gran argumento en los años 80, pero descubrí que muchos compiladores modernos básicamente adivinarán lo que estás haciendo y optimizarán basándose en eso en lugar de suposiciones del lenguaje. Por supuesto, puede volver a hacer un uso excesivo de un compilador moderno en una plataforma moderna. Pero hombre, mi código es mucho más manejable ahora que no escribo todo en una línea de montaje para el PIC ... De hecho, no puedo tener que empezar desde (casi) cero cada vez que cambio MCU con C.

        Desafortunadamente, bastantes plataformas integradas tienen compiladores escritos como si vinieran directamente de los años 80, por lo que hay bastantes plataformas en las que este consejo sigue siendo completamente cierto (* ver PIC8 *).

      • Dr.Tune dice:

        Haciendo cosas desde ARM (Cortex), siempre miro el producto del ensamblador; casi siempre se puede masajear un poco la C para ayudar al compilador; cosas como copiar cosas en variables locales son geniales; de hecho, vale la pena mencionar tan bueno; el caso es que cuando tienes una función (digamos) que toma algunos punteros estructurales y los repite, el compilador no puede garantizar absolutamente que esos punteros en tiempo de ejecución no muestren realmente lo mismo en la memoria (aunque normalmente sabes por seguro que no harán eso) por lo que el compilador tiene que ser súper paranoico acerca de recargar cosas de la memoria en lugar de cachear en los registros; esto también sucede mucho cuando uno llama a una función y le da un puntero en un bucle. La solución aquí es (a) usar punteros "const *" siempre que sea posible y copiar cosas como cálculos de bucle en variables locales (que el compilador puede asumir legalmente que ningún puntero modificará). Recuerdo que en los días de PSX discutía con los compiladores que su tonto compilador no hacía optimizaciones obvias y me lo explicaron. Es bastante sutil y realmente un poco débil en el lenguaje C.
        Ejemplo;
        blanco vacío (alguna estructura * s1, alguna estructura * s2)
        {
        por (int t = 0; tsomeCount; t ++) {
        s2-> someArray[t]= 0;
        }
        }
        En este caso, el compilador tendrá que volver a cargar "s1-> someCount" cada vez que rodee el bucle porque es posible que s2 se superponga a s1-> someCount. Prácticamente nunca lo es, pero el compilador no puede asumir eso. Una solución es copiar s1-> someCount en una variable local. La otra forma de hacerlo sería invertir el ciclo e inicializar t contando y contando hacia atrás. A veces, en compiladores muy inteligentes (y si es legal) invertirá el ciclo porque mantiene la instrucción comparativa. Hay muchos más consejos, pero saber cómo un posible cambio de nombre de puntero puede estropear la optimización del compilador C es genial.

        • Dr.Tune dice:

          meh rompió mi código; obviamente, el ciclo es "for (int t = 0; t someCount; t ++)"

          • Dr.Tune dice:

            ho ffs. Sabes a lo que me refiero. someCount es un miembro de la estructura mostrada por s1 y usted compara t con él. k? :-PAG

          • notarealemail dice:

            Usar
            Utilice> para>
            O puede escribirlo primero en un sitio de este tipo:
            http://www.accessify.com/tools-and-wizards/developer-tools/quick-escape/default.php

          • ROBÓ dice:

            Y

            como ...

            También puede usar> en lugar de> pero no es necesario

          • notarealemail dice:

            Jaja, tengo que usar un atajo en el teclado de mi teléfono o de lo contrario los cambio de la manera incorrecta.
            Veamos si las etiquetas de código aún convierten html, no lo recuerdo.

            italic tag?

        • ruedas dice:

          Este no es realmente un hilo sobre las mejoras del compilador, pero, dado que lo creó, es posible que deba mirar el resultado del compilador por muchas razones.

          Una vez tuve que escribir un módulo completo para el 68332 en ensamblador porque manejaba registros de TPU, y el compilador que usamos era bastante inteligente para optimizar cualquier operación que pudiera realizar con operaciones de bytes. Desafortunadamente, se debe acceder a muchos de los registros de TPU como palabras de 16 bits; escribir solo un bit provoca el descarte del otro.

          Algunos de los únicos ensamblajes recientes que escribí para PIC fueron para eludir el hecho de que el compilador que usé escribió las mitades de un valor de 16 bits en la memoria en el orden incorrecto para un par de registros específico al que debía acceso. Estoy muy contento de poder usar C para casi todo el procesamiento de PIC en este momento, pero todavía tengo que profundizar en él de vez en cuando.

  • AndreN dice:

    Un truco que vi utilizado en el montaje 6809 saltó a la mitad de una instrucción. No recuerdo un buen ejemplo de ello, pero fue para guardar un byte de código. Básicamente, si desea restar 1 del registro D, el código de operación se ve así:
    83 01 SUBD # 1
    por lo que el código de pirateo en realidad tendría
    10 83 01 CMPD # 1
    y en otros lugares había código que saltaba a los 2 bytes de esa instrucción para restar 1 de D, mientras que otra ruta de código "atravesaba" y ejecutaba la instrucción CMPD que establecía de forma segura códigos / banderas condicionales. Esto ahorró un byte, ya que de lo contrario necesitarían 2 bytes de código para omitir la instrucción SUBD.

  • topógrafo dice:

    Un gran ahorro de espacio es copiar una máquina virtual más eficiente en cuanto al espacio. Esto se hizo en el 1K BASIC original lanzado en DDJ, y nuevamente en el Apple-2 (es decir, "SWEET-16"). Ahorrador de espacio enorme. Y en una escala más pequeña, uso prudente del direccionamiento relativo (como saltos relativos y llamadas relativas), ordenando que su código coincida dentro de esa distancia de dirección relativa limitada. Luego exprima hasta el último byte, reemplazando las constantes con bytes del mismo valor que "por casualidad" se encuentran en algún lugar de su código (incluso como parte de una instrucción). Luego, puede hacerlo como TI en su computadora personal y almacenar sus programas BÁSICOS en la RAM de video (aunque acceda muy lentamente a través de los puertos de E / S de un controlador de video).

    • Jason Dorie dice:

      Escribo el firmware para un dron de hélice, y esto se usa ampliamente. Mi "FPU" integrada maneja el flujo de instrucciones, donde cada operación es de 4 bytes: Código de operación, FuenteA, FuenteB, Dest. Los 3 valores de "registro" son índices en una matriz de flotantes. El propio flujo de instrucciones lo genera C a partir de un compilador. Esto me ahorra varios kilobytes de espacio y, de hecho, funciona más rápido que el código original, porque tengo algunos códigos que C no tiene, como un operador de pala deslizante.

  • Halcón Estelar dice:

    Oye [Al] (¿Puedo llamarte Al? y estoy usando los corchetes correctamente, ahí ...?) - ¿Qué tipo de computadora era esa, con solo 256B de RAM ...? Me tienes curiosidad.

    Si tuviera que adivinar ... algo basado en Signetics 2650. Su ROM de aficionado disponible públicamente fue codificada para un sistema que usa chips Intel 2112, que son chips de 1024 bits, organizados como 4 x 256 bits, o 256 nybbles, para aquellos que no hablan SRAM;)

    Curiosamente, esta ROM mencionada todavía está un poco disponible. Se llama PIPBUG, y parece haber estado rondando (puede descargarlo aquí en la 'Red si sabe dónde buscar) porque había algunas máquinas de pinball basadas en 2650 de las cuales alguien leyó la ROM desde ... y esa ROM resultó ser PIPBUG. (¿Cómo sé todo esto ...? Estoy pensando en construir una puerta trasera basada en 2650 con la ROM PIPBUG. Tengo algunas otras ideas para que las computadoras retroiluminadas reboten, así que tal vez, tal vez no, ya veremos, pero Es una idea genial. Los 2650 años tienen algunas características interesantes, por ejemplo, una interfaz final en serie ligeramente tocada que está exactamente lista, por ejemplo. Ahora es una CPU poco común, pero tengo una: $ 10 en eBay, IIRC .)

    El signetismo, sin embargo, ha desaparecido. Se convirtieron en parte de Philips Semi en 1975, justo en el momento del lanzamiento de la CPU 2650, que se creó como NXP en 2005 ... que, como [la-tecnologia.com] informó en octubre, ahora es parte de Qualcomm.

    Probablemente también debería mencionar ... Signetics es notable por otra contribución (bastante significativa, de hecho) a la electrónica. En 1971, un diseñador de chips suizo llamado Hans Camenzind, inventó el temporizador 555. Trabajaba bajo contrato con Signetics en ese momento, por lo que era su chip para comercializar.

    • Al Williams dice:

      Yo respondo a [Al]. Homebrew 1802 ... de hecho, mis primeros artículos informáticos fueron en QuestData sobre 1802. Hace muchos años 😉

      • Halcón Estelar dice:

        Sly, otra CPU bastante extraña ... hombre, el 1802 es extraño (bueno, bueno, todo es relativo), pero también es muy bueno porque estaba en spaaaaaaaaaace.

        COSMAC ELF? u otro sistema? Las imágenes serían buenas si las tiene (y tiempo para publicarlas). Lo siento si tengo demasiada curiosidad, realmente me gustan las herramientas viejas como esa.

        • Halcón Estelar dice:

          Ho, duh. ¡Dijiste cerveza casera! (Lo siento, soy un "profesor distraído". Bueno, excepto que no enseño nada).

          me gustaría amor mira fotos si puedes hacer eso. El equipo casero es un equipo increíble.

    • Halcón Estelar dice:

      De hecho ... corrección, la ROM PIPBUG está esperando Intel 2114 SRAM, que son de 4096 bits, organizados como 4 x 1024, también conocidos como nimbuses de 1k en un chip. Si alguien quiere construir una computadora basada en PIPBUG, existe un plan de Electronic Australia en la edición de mayo de 78. Subí un archivo JPEG aquí -> http://i.imgur.com/nZMQ8ql.jpg

    • Chris Burrows dice:

      Si aún planea construir una computadora de red basada en 2650, consulte la sección "Firmas basadas en 2650" del foro de Microbee Software:
      https://microbee-mspp.org.au/forum/viewforum.php?f=75
      Reconstruí el proyecto de Electronic Australia de 1978 hace unos años. ¡RCS Radio en Sydney todavía vende las placas de circuito originales!
      http://www.cfbsoftware.com/S2650/s2650.jpg
      También hay mucha documentación y software sobre S2650 en el sitio web de Amerson Software Emerson Arcadia 2001 Central:
      https://amigan.yatho.com/

  • ruedas dice:

    En los procesadores PIC16, tuve que organizar qué subrutinas van en páginas de códigos específicas, por lo que no tengo que cambiar bits en el registro de la página de códigos para llamar a varias subrutinas seguidas. También definí un conjunto de macros para que el código para configurar los bits de la página de códigos solo se genere si es necesario. Básicamente, esto involucró macros para llamadas entre páginas y una macro de "sincronización" para establecer el registro de la página de códigos en la ubicación actual. Significaba que no tenía que rastrear eso manualmente.

    Otro truco, usado en una interfaz de comando, cuando tuve que comparar el registro W con varias letras (para elegir uno de varios comandos especificados por letras simples), fue "encadenar" las comparaciones para no tener que recargar el carácter de entrada como este:

    sublw 'D'; comprobar el comando 'D'
    ESTADO btfss, Z
    iru ne_D
    ; El código de manejo para el comando 'D' va aquí

    ne_D:
    sublw 'D' - 'G'; marque el comando 'G'
    ESTADO btfss, Z
    iru ne_G
    ; El código del identificador para el comando 'G' va aquí

    ne_G:
    … Y así.

    Para las tablas de salto en los procesadores PIC, coloco el código de la última entrada en la tabla directamente después de la tabla, para poder eliminar la instrucción de salto para esa entrada.

  • Unferio dice:

    Esto está fuera de mi enlace, en términos de programación.

    Para tu entretenimiento:
    Pensé que algo era fácil, luego me topé con un obstáculo (mental) o simplemente lo olvidé,
    Tenía muchos proyectos que abandoné (o simplemente olvidé),
    La mayoría de mis programas C / C ++ solo contienen int main (); antes de ser abandonado,
    He completado un programa para iniciar sesión en cierta información que necesita un acceso más directo.
    No completé la temperatura para la velocidad del ventilador de mi servidor Pi2.

    Una vez intenté desmontar un BIOS de HUDL2, pero encontré un salto en un bucle muy temprano. Después de una limpieza de caché, se ejecutan las instrucciones FPU-init y SSE2, hay una prueba que salta a un interminable ciclo de interrupción y bucle (todo en código de 16 bits de f000: fff0).
    Así que reemplacé la primera instrucción de la prueba con un salto al ciclo.

    Soldar la ROM de nuevo y encenderla. Esperaba calor de la CPU y no tenía ninguno, tampoco tenía voltaje en la CPU. Rehizo el cuadro original y la cosa vivida.

    Obtenga más información sobre Intel Boot Guard.

    Menciono mis experiencias a: apesto programar.

    Aquí hay ideas para aquellos que tienen tiempo / recursos / etc:
    La única posibilidad de este desafío es si tuviera:
    algunos discos de vinilo y reproductores con samples,
    Proyector rotatorio de películas fotográficas o más.
    etc.
    es decir, mueva el código + datos y transfórmelo en una acción automática externa eléctrica / mecánica (es decir, un conjunto de batería direccionable con lógica discreta conectada a los pines GPIO) y lance un espectáculo de luces.
    Entonces solo necesita preocuparse por el tiempo GPIO (no se necesitan datos de imagen o muestras de audio)
    Si bien es mecánico o analógico, no se puede medir con ningún número de bits (hasta que, por supuesto, se convierte a digital)

  • Sidra de pera dice:

    Dios, me gustaría recordar del 1 al 100 de lo que sabía cuando era más joven.

    Comencé a programar con 6809 home brewing, luego ZX81, ligeramente crecido, a COCO y luego a IBM masivo con 256 m de RAM y pantalla EGA.
    Ahora mi reloj es más potente.

    ME ENCANTA !!!!!!
    Y ahora empiezo a usar clones Arduinos, ESP8266 y Raspberry PI. Todavía me encanta el clon de Orange PI evan con sus defectos. Pero el precio es correcto.

    Les deseo a todos buena suerte. Sin embargo, estoy triste porque ya no estoy en este juego.

    • ley canalla dice:

      Estaba pensando en obtener un pi naranja, pero había oído hablar de bastantes problemas de compatibilidad, así que decidí no hacerlo, tal vez era hora de que mirara otro.

  • David Maunder dice:

    ... código auto modificable. Salva multitudes.
    Regrese a los concursos de demostración de computadoras de optimización de 64 y 256 bytes. Concursos HUGI. etc., etc. Fueron divertidos.

    Pouet tiene algunas demostraciones increíbles de 1k que superan los límites de optimización para plataformas.

    Un poco de tiempo libre: una demostración abierta cuesta 180k, eche un vistazo a lo que obtiene: https://www.youtube.com/watch?v=wqu_IpkOYBg

    • Dissy dice:

      Farbrausch tiene un trabajo increíble, fr-08 “el producto” (demostración de 64k) fue mi primera exhibición y tiene una duración sorprendentemente larga de 11 minutos.

  • Lobo dice:

    En PIC, Bit Toggle es tu amigo:
    BTG PORTX, 0, 1

  • danjovic dice:

    BST y BLD en AVR son increíbles para intercambiar bits de forma arbitraria y mucho más legibles que un conjunto de rotaciones y OR y AND, sin mencionar que no es necesario involucrar otro registro o dirección de memoria.

    En cuanto a Z80, puede poner el valor de cualquier bit en el puerto con nuestra rotación combinando las instrucciones AND y NEG. Usé esto en la biblioteca SPI para joystick en computadoras MSX http://hotbit.blogspot.com.br/2008_02_01_archive.html

    En cuanto a PIC, mi favorita es la secuencia de

    BTFSC f, b
    BTFSC f, b

    después de una operación lógica para probar un bit mientras se mantiene un tiempo de instrucción constante para un bitbang en serie. También funciona en Z80
    LLAME C, xxxx
    VOKU NC, xxxx
    como se usa en la impresión en serie en el joystick: https://la-tecnologia.io/project/18552-joy232

  • ROBÓ dice:

    El aumento de la profundidad de recursividad también ayuda siempre que recuerde que cada nivel cuesta dos bocados en la pila como dirección de retorno.

    Otro método es buscar matrices que incluyan una ubicación CALL -
    LD BC, (DE)
    PUSH BC
    RETIRADO

    Lo que encontré mejor fue tener varios puntos de entrada a una subrutina que hacía cosas similares:


    wait_65536_clocks:
    LD C,0 // or XOR C,C
    wait_C_times_256_clocks:
    LD B,0 // or XOR B,B
    wait_BC_clocks:
    DEC B
    JRNZ wait_BC_clocks
    DEC C
    JRNZ wait_C_times_256_clocks
    RET
    wait_B_clocks:
    LD C,1
    JR wait_BC_clocks

    4 rutinas, 13 bytes

  • drenehtsral dice:

    Un truco útil para condensar muchos cálculos matemáticos de enteros comunes en una sola declaración de objeto x86 / x86_64 es usar la declaración LEA (cargar dirección efectiva). No existe una ley estricta que diga que el cálculo que realiza representa una dirección.

    En realidad, le da una constante irregular o base de registro, y un movimiento de registro con signo, que se escala por un valor inmediato de 1, 2, 4 u 8, por lo que en pseudocódigo es:
    dest = X + (Y

  • Ben Hencke dice:

    Algunos de los favoritos utilizados en OKOS en PIC18:

    De lo contrario, si hay controles de estilo encadenados, similares a los que usaría un interruptor para:
    xorlw CHAR_A
    bz cliAssembler
    xorlw CHAR_E ^ CHAR_A
    bz cliEditor
    xorlw CHAR_R ^ CHAR_E
    bz cliRun

    (similar a ruedas)

    Acepta el intercambio xor, reutilizado para cambiar la memoria. Menos instrucciones que mover copias
    primero:
    ; cargar el primer carácter, apuntar al siguiente
    movf POSTINC1, w
    círculo:
    xorwf INDF1, w; W: = A ^ B; X = B
    xorwf INDF1, f; W = A ^ B, X: = B ^ (A ^ B) = A
    xorwf POSTINC1, w; W: = (A ^ B) ^ A = B; X = A

  • Biomed dice:

    Tendrás que perdonarme. ¿Desafío 1k? Imagina que todo es lo que obtienes ... porque en él no hay Mount, ni compilador de C, ni carga de paquetes en tiempo de ejecución cuando ejecutas. Solo código compilado a mano que se ejecuta directamente, tal vez incluso manualmente de la forma en que todos teníamos que hacerlo cuando comenzó este pasatiempo. Anteriormente MS Basic integrado en una EEPROM. ¿Qué tipo de ventilador funcionaría si se reescribiera en lenguaje de máquina en lugar de en un compilador? Pensar que el concurso va más en esa línea. ¿Cuál es el código más estricto y rápido que USTED puede escribir que coincida con 1k ... es decir, NO lo que C puede escribir desde su archivo de texto? USTED escribe el código.

  • Lucas dice:

    En 6809 (y algunos otros chips de 8 bits) había dos formas de desconectar: ​​una dirección de 16 bits o un desplazamiento de 8 bits. Por supuesto, el desplazamiento de 8 bits significaba que la dirección de destino tenía que ser +/- 256 de la llamada. Para ahorrar un byte por llamada, codifiqué un programa con el inicio en el medio de la memoria (solo 750B disponibles) y lo ramifiqué hacia arriba / abajo desde allí.

  • Alan Cox dice:

    En los viejos tiempos de los 8 bits tampoco desperdiciamos memoria de variables. En lugar de tener dos bytes de memoria que contienen alguna variable, seleccionó la carga más crítica del registro y la convirtió en una carga inmediata. Los dos últimos bytes de la instrucción (al menos en Z80) se convierten en la variable.

    es decir, en cambio

    LD HL, (foo)
    bla bla
    LD (foo), HL
    RETIRADO
    foo: DEFW 0

    _vfoo: LD HL, # 0
    foo .equ _vfoo + 1
    bla bla
    LD (foo), HL
    RETIRADO

    Más pequeño y más rápido

Alberto Gimenez
Alberto Gimenez

Deja una respuesta

Tu dirección de correo electrónico no será publicada.