Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





¿Cómo invertir el orden de un byte?

Iniciado por J_F_NASH, 05 de Noviembre de 2006, 08:40:28 PM

« anterior - próximo »

J_F_NASH

¿Alguien tiene idea de cómo hacer esto?
Estoy con ensamblador.


S2.

nostromo

entrada: digamos que el registro AL tiene el byte
salida: bl tendrá el byte invertido


  mov cl,8  ; 8 bits moveremos

next_bit:
  rcr al,1   ; rotacion derecha contando con el acarreo
  rcl  bl,1  ; idem. rot. izquierda

  dec cl       ;  repite 8 veces
  jnz next_bit

J_F_NASH

Se que es mucho pedir pero podrías ponerlo para ensamblador del Z80, me olvidé especificarlo.

"AL" rota a la derecha hasta llegar a 8 y "BL" rota a la izquierda igualmente hasta llegar a 8... ¡el byte a dado una vuelta completa y llega al mismo punto!. El byte sigue igual ¿no?. No entiendo  :oops:

Nota:
Cuando roto entiendo que los bits que salen por la derecha aparecen por la izquierda.


Muchas gracias por responder.

S2.

senior wapo

No, porque usas el flag de carry para guardar el bit que sale y lo usas para meterlo en el otro.

fiero

Cita de: "J_F_NASH"
Nota:
Cuando roto entiendo que los bits que salen por la derecha aparecen por la izquierda.

No, tú te confundes con ROR y ROL, esas instrucciones sí que hacen una rotación sobre el mismo dato.

RCL y RCR utilizan el flag de acarreo (1 bit) para poner el valor que sale por un lado y se mete por el otro. Lo que hace nostromo es utilizar el bit de acarreo como "almacenamiento temporal" del bit que sale de un registro, para meterselo al otro.

un saludo

PS: ups, se me adelantaron XD
www.videopanoramas.com Videopanoramas 3D player

J_F_NASH

¡Entiendo!.
No se si en z80 había alguna instrucción para esto, en la referencia me he encontrado con:
RRA            Rotate right accumulator through carry
RR    r         Rotate right through carry register r.
La del acumulador no me interesa. Pero la otra (RR) parece que hace lo mismo que comentais ¿no?. En cuanto pueda lo pruebo.

En cualquier caso he metido la gamba con la pregunta, mas bien quería decir:
¿Cómo puedo rotar medio byte?
Lo que trataba de hacer exactamente es:
ORIGINAL                     INVERTIDO
1011 0100                     1101 0010
Lo que yo hago es examinar CADA bit y colocarlo en la posición que deseo del nuevo byte pero esta operación es extremadamente lenta (al menos en z80)

Gracias nuevamente por la atención.




S2.




S2.

MrK

uoo... una pregunta tecnica que puedo medio responder! xD

lo mejor para pelearse con el z80 es ir a http://www.z80.info/ , hay
mogollones de informacion sobre el tema, en concreto http://www.z80.info/z80code.htm va muy bien para dudas tecnicas.

Efectivamente RR r y RL r rotan un registro "a traves" del carry metiendo el
carry en el bit que queda libre y expulsando el bit que sobra al carry.
Si mal no recuerdo, RRA era lo mismo que "RR a", solo que gastando 1 byte
menos (y consecuentemente menos ciclos).

La "nueva" rutina que dices parece ser la misma, solo que rotando
4 veces hacia la derecha o izquierda al terminar la operacion (usando
rlca por ejemplo)
En caso de ser muy lenta puedes usar una tabla de 16 bytes para invertir
el nibble alto y nibble bajo (o una de 256, pero siendo un z80 256 bytes
para eso es un lujo dificilmente justificable...)

Si te interesa optimizar alguna cosa en especial, pasate por las newsgroups
es.comp.sistemas.sinclair donde mas de una vez hemos hecho algun "concurso"
de optimizacion de codigo :) Alli hay gente que incluso aun programa
regularmente z80 :)

Cita de: "J_F_NASH"¡Entiendo!.
No se si en z80 había alguna instrucción para esto, en la referencia me he encontrado con:
RRA            Rotate right accumulator through carry
RR    r         Rotate right through carry register r.
La del acumulador no me interesa. Pero la otra (RR) parece que hace lo mismo que comentais ¿no?. En cuanto pueda lo pruebo.

En cualquier caso he metido la gamba con la pregunta, mas bien quería decir:
¿Cómo puedo rotar medio byte?
Lo que trataba de hacer exactamente es:
ORIGINAL                     INVERTIDO
1011 0100                     1101 0010
Lo que yo hago es examinar CADA bit y colocarlo en la posición que deseo del nuevo byte pero esta operación es extremadamente lenta (al menos en z80)

Gracias nuevamente por la atención.

Siempre es un placer para un viejo responder estas preguntas :)

J_F_NASH

Oye, muchísimas gracias por toda esa información MrK. Un lujo.


S2.

J_F_NASH

Cita de: "MrK"
En caso de ser muy lenta puedes usar una tabla de 16 bytes para invertir
el nibble alto y nibble bajo (o una de 256, pero siendo un z80 256 bytes
para eso es un lujo dificilmente justificable...)

No entiendo esto último ¿una tabla de 16 bytes?... ¿Te refieres a un registro de 16 bits como por ejemplo HL?. ¿Podrías explicar este método?.
He probado con RR y RL y rotando 4 veces tal como comentas aunque he ganado algo de velocidad, no la suficiente.


S2.

MrK

Cita de: "J_F_NASH"
Cita de: "MrK"
En caso de ser muy lenta puedes usar una tabla de 16 bytes para invertir
el nibble alto y nibble bajo (o una de 256, pero siendo un z80 256 bytes
para eso es un lujo dificilmente justificable...)

No entiendo esto último ¿una tabla de 16 bytes?... ¿Te refieres a un registro de 16 bits como por ejemplo HL?. ¿Podrías explicar este método?.
He probado con RR y RL y rotando 4 veces tal como comentas aunque he ganado algo de velocidad, no la suficiente.


S2.

si, me explico:

tu en realidad lo que quieres es invertir los bits 4 a 4, o sea, dos nibbles. en un byte tienes dos nibles, N1 y N2

entonces, para los 16 valores diferentes de cada nibble, seria cuestion de crear una tabla de 16 bytes, de esta forma:

(byte 0 de la tabla) 0000 -> 0000
(byte 1 de la tabla) 0001 -> 1000
(byte 2)0010 -> 0100
(byte 3)0011 -> 1100
...
(byte 15) 1111->1111

etc... (esta en binario, obviamente)

La idea esta en no realizar las rotaciones, sino tenerlas precalculadas para cada uno de los 16 valors de cada nibble. de esta forma, para invertir el el registro A, y en HL la direccion de la table, tendrias que hacer:

ld c,a        ; resguardamos el byte a invertir
and $f    ; ( regA=regA & 0xf ) <--- te quedas con el nibble bajo

add l,a   ; HL = HL + A , acceder al elemento A de la tabla HL
ld b,(HL)  ; cargamos el valor rotado: B ahora contiene la rotacion del primer nibble

sub l,a   ; restauramos HL

ld a,c      ; volvemos a cargar el byte original

rra          ; nos quedamos con el nibble superior
rra
rra
rra

; lo mismo, cargamos HL con la direccion que toca
add l,a                       **** edit: esta instruccion me la he inventado vilmente :P
ld a,(HL)

; este valor lo tenemos que volver a rotar, porque va en el nibble superior
rla
rla
rla
rla

; y hacemos una or con el original
or b

y diria que asi ya tendrias tu valor :) diria que tendria que ser mas rapido que la rutina original (Se tendrian que contar ciclos, pero si metes un djnz para el bucle de 8 gasta una barbaridad)

hay una "guarrada" y es que la tabla no deberia cruzar los 256 bytes (por el add HL+A , sino tendrias que mover A hacia C, meter B a 0 y sumar HL y BC)

y otra cosa, la tabla que calculamos a mano, en vez de poner los nibbles bajos, podriamos llenar los dos nibbles
(o sea
0000 -> 0000 0000
0001 -> 1000 1000
...
)

asi te ahorrarias los cuatro RRL finales, y a cambio meter dos ANDs para descartar los nibbles superior/inferior que antes teniamos a 0


es una explicacion terrible, lo se XD  el codigo no lo he comprobado, se siente, pero diria que funciona :)  en serio, te recomiendo pasar por es.comp.sistemas.sinclair , si quieres pregunto por ti a ver si a alguien se le ocurre algun metodo mejor/mas rapido.

ya como curiosidad, se puede saber para que es la rutina esta y que maquina? :)

senior wapo

Si te lo puedes permitir por el espacio, usa una tabla precalculada de 256 bytes y compruebas directamente el byte sin hacer ningun tipo de calculo.

J_F_NASH

Cita de: "MrK"en serio, te recomiendo pasar por es.comp.sistemas.sinclair , si quieres pregunto por ti a ver si a alguien se le ocurre algun metodo mejor/mas rapido.

Te lo agradecería mucho. Siempre es bueno saber que hace la gente por ahí.
La técnica que has explicado no he llegado a ponerla en práctica pero es que veo casi tantas operaciones de cálculo como  en la anterior (ADD, SBC, RRA, RRA, RRA,... ). No veo muy claro porqué decis que es mas rápida, quizás tendría que ponerme con ella.


Cita de: "MrK"
ya como curiosidad, se puede saber para que es la rutina esta y que maquina? :)

Estoy tratando de hacer un juego para el viejo AMSTRAD CPC 664... ya me dirás ¡menos de 64k... todo un reto!... Aunque todavía no he empezado a tener problemas serios de espacio en memoría. Veo como esta se agota a pasos de gigante.
Respecto al Amstrad en la actualidad parece mentira pero empiezan a salir juegos (buenos 1 por año) como el "Phantomas Saga : Infinity", una pequeña obra de arte que puede ser jugada en cualquier emulador de Amstrad o Spectrum. Te dejo un enlace:
http://cezgs.computeremuzone.com/ficha.php?id=10

Gracias de nuevo por currarte esas respuestas.



S2

MrK

Cita de: "J_F_NASH"
Cita de: "MrK"en serio, te recomiendo pasar por es.comp.sistemas.sinclair , si quieres pregunto por ti a ver si a alguien se le ocurre algun metodo mejor/mas rapido.

Te lo agradecería mucho. Siempre es bueno saber que hace la gente por ahí.
La técnica que has explicado no he llegado a ponerla en práctica pero es que veo casi tantas operaciones de cálculo como  en la anterior (ADD, SBC, RRA, RRA, RRA,... ). No veo muy claro porqué decis que es mas rápida, quizás tendría que ponerme con ella.

Normalmente se llega a un compromiso entre tamanyo y velocidad, la ventaja
de la rutina con la tabla es que se ahorra saltos (que son muy lentos, si
haces servir la rutina inicial sin loop unroll), y se ahorra bytes (si usas
la funcion con el loop unroll, pues expandes el bucle metiendo 16 instrucciones)

En cuanto llegue a casa cuento el tiempo que gasta cada rutina, quizas estoy
equivocado con los ciclos que gasta, y meto un post en las news preguntando
a ver si a alguien se le ocurre algun metodo mejor/mas rapido, y en cuanto
lea resultados los posteo aqui :)


Cita de: "MrK"
ya como curiosidad, se puede saber para que es la rutina esta y que maquina? :)

Estoy tratando de hacer un juego para el viejo AMSTRAD CPC 664... ya me dirás ¡menos de 64k... todo un reto!... Aunque todavía no he empezado a tener problemas serios de espacio en memoría. Veo como esta se agota a pasos de gigante.
Respecto al Amstrad en la actualidad parece mentira pero empiezan a salir juegos (buenos 1 por año) como el "Phantomas Saga : Infinity", una pequeña obra de arte que puede ser jugada en cualquier emulador de Amstrad o Spectrum. Te dejo un enlace:
http://cezgs.computeremuzone.com/ficha.php?id=10

[/quote]

Lo conozco, lo conozco, no esta nada mal! :) Por desgracia desconozco como esta
la scene del cpc, pero la de spectrum que es la que sigui, esta bastante activa
, supongo que deben andar a la par :)
Me imagino que lo sabras, pero el fuente (al menos la version de spectrum) es
publico y esta escrito practicamente todo en C (me parece que incluso el .c
esta en el mismo fichero que te descargas con el juego), con lo que se puede
aprender mucho de ahi, y despues optimizar las rutinas que necesiten velocidad
extra :)

Ei, en serio, me alegro que estes con este tipo de proyectos, y gracias a ti
por hacer la vida de los jugadores de 8 bits mas agradable ;)

J_F_NASH

1) Se me olvidó comentarte que la rutina de invertir un byte finalmente era para invertir la posición de un sprite y ahorrarme la mitad de movimientos del personaje.

2) La scene del cpc es bastante mediocre a diferencia que la del spectrum pero estoy seguro que en unos años las cosas van a cambiar, quien sabe, quizás hasta tengamos otra "época de oro Español" en cuanto a 8 bits se refiere.

3) Cierto!, el Phantomas : Infinity esta hecho en C, aunque... un cierto a medias, como seguro te has dado cuenta, pues no es el C que todos conocemos sino uno que se le parece bastante. Bienvenido sea, claro.

4) No hombre, las gracias a ti por todos esos ánimos e información. Confio en tener algo mas pronto que tarde... aunque... lo bueno de lo retro es que no hay prisa alguna :D .



S2.

MrK

Cita de: "J_F_NASH"1) Se me olvidó comentarte que la rutina de invertir un byte finalmente era para invertir la posición de un sprite y ahorrarme la mitad de movimientos del personaje.

vaya :) buff, pues asi quizas si es mejor tener una tabla de 256 bytes y usarla cada vez , puesto que va a ser una rutina critica, sino cuando imprimas sprites del derecho tardara poco, y si todos se giran la cosa ira lenta :)  En fin, ya veras

Citar
2) La scene del cpc es bastante mediocre a diferencia que la del spectrum pero estoy seguro que en unos años las cosas van a cambiar, quien sabe, quizás hasta tengamos otra "época de oro Español" en cuanto a 8 bits se refiere.

pues ya nos gustaria a mas de uno, pero me parece que la cosa esta chunga ;)

Citar
3) Cierto!, el Phantomas : Infinity esta hecho en C, aunque... un cierto a medias, como seguro te has dado cuenta, pues no es el C que todos conocemos sino uno que se le parece bastante. Bienvenido sea, claro.

cierto, es un C un poco "risc", con muchos shifts, pocas multiplicaciones y te cortan los dedos si divides, pero a parte de eso...

Citar
4) No hombre, las gracias a ti por todos esos ánimos e información. Confio en tener algo mas pronto que tarde... aunque... lo bueno de lo retro es que no hay prisa alguna :D .

bueno, eso, y que siempre puedes poner una rutina y despues sustituirla por otra de mas rapida :)


te pongo el miniestudio para la rutina, si no me he colado, las rutinas y los tiempos son estos:

(rutina original)
   ld b,8         ; 4t,1b  (4 t-estados, 1 byte)

lab:
   rra         ; 4t,1b
   rl c         ; 8t,2b
   djnz lab      ; 13/8t, 2b

   ld a,c         ; 4t,1b
   
   rrca         ; 4t,1b
   rrca
   rrca
   rrca

que hacen 11 bytes y 4+(4+8+13)*7+(4+8+8)+4+4*4 = 219 t-estados si no me he equivocado.
Si se hace loop unroll (quitar el djnz y meter 7 rra, rl c) se queda en 120 t-estados y 30 bytes

con la rutina de tabla de nibbles

   ld h,tabla/256      ; 4t, 2b

   ; resguardamos el valor a rotar
   ld c,a         ; 4t,1b
   and $f         ; 7t,2b

   ld l,a         ; 4t,1b
   ld b,(hl)      ; 7t,1b

   ; tenemos en b el nibble bajo

   ; recuperamos valor inicial
   ld a,c         ; 4t,1b

   ; obtenemos nibble alto
   rra         ; 4t,1b
   rra
   rra
   rra

   ld l,a         ;4t,1b
   ld a,(hl)      ;7t,1b

   rla         ; 4t,1b
   rla
   rla
   rla

   or b         ;4t,1b

   ; diria que ya ta :)   

total, 35 bytes (16 de tabla) y 4+4+7+4+7+4+4*4+4+7+4*4+4= 81 t-estados. La tabla debe empezar en un multiplo de 256 bytes.
En la otra rutina, me invente por la cara el add l,a :) con el z80 solo
puedes usar el acumulador como destino en las operaciones aritmeticas, se siente (por eso lo de que la tabla empiece en multiplo de 256)

en cuanto se mueva el post de las newsgroups te digo algo :)






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.