merodeando por paginas web de desarrollo he encontrado a alguien
haciendo preguntas de Z80, y
se me ha ocurrido que seguro que entre todos podemos ayudarle y
desenpolvar los apuntes de
z80 como haciamos hace tiempo :)
La idea es que tiene un byte "abcdefgh" , y quiere rotar los bits 4
a 4, o sea, que quede
"dcbahgfe", por ejemplo, 00101101 pasaria a 01001011.
Al principio se propuso hacer la rotacion normal usando rotaciones
(obtener hgfedcba), y al final rotar 4 veces hacia cualquier lado
(dcba-hgfe)
(a contiene el byte a girar)
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.
Haciendo loop unroll, serian 4+(4+8)*8+4+4*4 = 120 t-estados, y 19
bytes mas
despues pensamos que podriamos usar una tabla de 16 bytes con los
nibbles rotados, o sea:
tabla:
db 0000b ; el nibble 0000 rotado
db 1000b ; el nibble 0001 rotado
db 0100b ; el nibble 0010 rotado
db 1100b ; el nibble 0011 rotado
db 0010b ; el nibble 0100 rotado
etc...
y hacerlo de esta forma:
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
por supuesto, tabla deberia empezar en una direccion multiple de 256
bytes, sino se puede se anyadirian un par de sumas y una resta
se os ocurre algun sistema mas rapido?
Segun ha dicho lo quiere porque esta intentando hacer un juego para
CPC, y quiere una rutina
para pintar los sprites en "modo espejo"... supongo que los timings
siguen siendo los mismos, no?
Con esta premisa lo mas practico quizas sea tener una tabla de 256
bytes y acceder a ella, pues
seria una rutina critica en el tiempo, pero claro, 256 bytes... buffff
:)
Saludos! :)
Kak
> se os ocurre algun sistema mas rapido?
>
> Segun ha dicho lo quiere porque esta intentando hacer un juego para
> CPC, y quiere una rutina para pintar los sprites en "modo espejo"...
Que guarde copias ya espejadas de los sprites. Ya sea metiéndolas
directamente en el código como datos, ya sea preparándolas en la
inicialización del programa, que así no tiene que preocuparse tanto de la
velocidad.
--
Salu2
>[...]
>que hacen 11 bytes y 4+(4+8+13)*7+(4+8+8)+4+4*4 = 219 t-estados si no
>me he equivocado.
>Haciendo loop unroll, serian 4+(4+8)*8+4+4*4 = 120 t-estados, y 19
>bytes mas
Una pequeña mejora al sistema sin tablas:
ld c,a ;1/4
ld b,0 ;2/7
sla a ;2/8
rr b ;2/8
rla ;1/4
rr b ;2/8
rla ;1/4
rr b ;2/8
rla ;1/4
rr b ;2/8
rr c ;2/8
rla ;1/4
rr c ;2/8
rla ;1/4
rr c ;2/8
rla ;1/4
rr c ;2/8
rla ;1/4
or b ;1/4
115 estados, 29 bytes.
>despues pensamos que podriamos usar una tabla de 16 bytes con los
>nibbles rotados, o sea:
>
>tabla:
>db 0000b ; el nibble 0000 rotado
>db 1000b ; el nibble 0001 rotado
>db 0100b ; el nibble 0010 rotado
>db 1100b ; el nibble 0011 rotado
>db 0010b ; el nibble 0100 rotado
>
>etc...
>
>
>y hacerlo de esta forma:
> ld h,tabla/256 ; 4t, 2b
esto es 7t
>
> ; 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
yo diría que justo aquí va otro "and $f" para evitar que las rotaciones dejen
bits a 1 en la parte alta
> 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
y corregido queda en 37 bytes/87 t-estados (tu suma inicial daría 77, no 81)
>se os ocurre algun sistema mas rapido? [...]
>Con esta premisa lo mas practico quizas sea tener una tabla de 256
>bytes y acceder a ella, pues
>seria una rutina critica en el tiempo, pero claro, 256 bytes... buffff
Pues yo diría que es la mejor manera, si se puede permitir el lujo:
ld h,tabla/256 ;2/7
ld l,a ;1/4
la a,(hl) ;1/7
4+256 bytes / 18 estados
METALBRAIN
(C) 1977 Tejedor & Gómez Research Ltd.
Vale. No quiere rotarlo, quiere tener en espejo cada nibble por separado. Es que
lo de "rotar" me ha liado.
> se os ocurre algun sistema mas rapido?
La tabla de traducción de toda-la-vida, con la base de la tabla en una posición
múltiplo de 256: rápido y corto (en bytes de código). En A está el byte a invertir.
ld h,Tabla/256 7
ld l,a 4
ld a,(hl) 7
TOTAL 18 ciclos
Versión que no usa HL, con código automodificable (más lento eso sí)
ld ($+1),a 13
ld a,(Tabla) 13
TOTAL 26 ciclos
Si no se puede hacer múltiplo de 256, hay dos opciones:
Sumando offsets:
ld hl, Tabla 10
ld e,a 4
ld d,0 7
add hl,de 11
ld a,(hl) 7
TOTAL 39 ciclos
Código automodificable: (en IX tendríamos como constante la dirección base de la
Tabla de traducción). Es algo más rápido que el método de los offsets, y más
corto (6 bytes) y tiene la ventaja de no necesitar a HL o DE.
ld ($+2),a 13
ld a,(ix+0) 19
TOTAL 32 ciclos
> Segun ha dicho lo quiere porque esta intentando hacer un juego para
> CPC, y quiere una rutina
> para pintar los sprites en "modo espejo"... supongo que los timings
> siguen siendo los mismos, no?
Si mal no recuerdo, el CPC va a 4MHz. Los timmings son los mismos que en el
Spectrum, si usas como unidad de medida el T-estado.
> Con esta premisa lo mas practico quizas sea tener una tabla de 256
> bytes y acceder a ella, pues
> seria una rutina critica en el tiempo, pero claro, 256 bytes... buffff
256 bytes no es mucho. Desde luego, es lo más rápido. Aunque si sus sprites son
unos determinados, igual le sale más a cuenta tener guardados esos mismos
sprites en espejo y usar unos u otros en función de.... digo yo, el sentido en
el que camine el personaje.
> 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.
ld c,1 ; 4t,1b (4 t-estados, 1 byte)
lab:
rra ; 4t,1b
rl c ; 8t,2b
jr nc,lab ; 12/7t, 2b
ld a,c ; 4t,1b
rrca ; 4t,1b
rrca
rrca
rrca
que hacen 11 bytes y 4+(4+8+12)*7+(4+8+7)+4+4*4 = 211 t-estados, y
además deja libre el registro B.
> Kak escribió:
> > Hola gente! :)
> >
> > La idea es que tiene un byte "abcdefgh" , y quiere rotar los bits 4
> > a 4, o sea, que quede
> > "dcbahgfe", por ejemplo, 00101101 pasaria a 01001011.
...
> La tabla de traducción de toda-la-vida, con la base de la tabla en una posición
> múltiplo de 256: rápido y corto (en bytes de código). En A está el byte a invertir.
>
> ld h,Tabla/256 7
> ld l,a 4
> ld a,(hl) 7
> TOTAL 18 ciclos
>
> Versión que no usa HL, con código automodificable (más lento eso sí)
> ld ($+1),a 13
> ld a,(Tabla) 13
> TOTAL 26 ciclos
>
>
> Si no se puede hacer múltiplo de 256, hay dos opciones:
>
Hola. Una duda solo por y para los que andamos toqueteando el z80 que
motivo tiene la tabla para que sea de 256 bytes? Más aún porque debe
estar en una posición múltiplo de 256? Por cierto, que quiere decir
el $ que incluyes sumandole 1 al que vas a meterle a? Vamos preguntas
de andar por casa.... se nota que no tengo mucha idea?
Gracias
sejuan
Porque hay 256 posibles entradas con sus 256 posibles soluciones.
>Más aún porque debe
>estar en una posición múltiplo de 256?
Para que no varíe el valor de byte alto de la dirección, facilitando la tarea.
>Por cierto, que quiere decir
>el $ que incluyes sumandole 1 al que vas a meterle a?
Es un símbolo que utiliza el ensamblador para indicar la posición actual
(o tal vez la posición siguiente, que sería lo lógico en este caso. Yo la
verdad es que no la suelo usar, prefiero etiquetas). En este caso lo que
hace es que la primera instrucción modifica el byte bajo de la segunda,
y es equivalente a:
ld (IQLEV+1),a ; Instrucción que ajusta la dirección
IQLEV: ld a,(Tabla) ; Instrucción Que Lee El Valor
El +1 es porque la IQLEV se codifica con 3 bytes: el primero
significa ld a,(NN) y los dos siguientes especifican la dirección NN, de
forma que el valor pequeño aparece antes (y es el que tenemos
que modificar según valga el registro a) y luego el mayor (que tiene
que quedarse fijo).
> >Hola. Una duda solo por y para los que andamos toqueteando el z80 que
> >motivo tiene la tabla para que sea de 256 bytes?
>
> Porque hay 256 posibles entradas con sus 256 posibles soluciones.
> .
Supongo coordenada X en pantalla, ¿no?
> ld (IQLEV+1),a ; Instrucción que ajusta la dirección
> IQLEV: ld a,(Tabla) ; Instrucción Que Lee El Valor
>
> El +1 es porque la IQLEV se codifica con 3 bytes: el primero
> significa ld a,(NN) y los dos siguientes especifican la dirección NN, de
> forma que el valor pequeño aparece antes (y es el que tenemos
> que modificar según valga el registro a) y luego el mayor (que tiene
> que quedarse fijo).
Esta claro.
Gracias, como siempre un placer.
Sejuan
Bueno... ya te han respondido :D
Solo añadir quizás, que en mis propuestas, el valor de $ que estoy considerando
que es la dirección de memoria donde comienza la siguiente instrucción a aquella
que se está ensamblando. En algunos ensambladores $ es la dirección de memoria
de la instrucción que se está ensamblando en ese momentofr5.
Las 256 entradas no corresponden a la pantalla en este caso. Es una forma de
tabular los posibles valores de una función.
Dicho de otra forma: si tú quieres implementar un algoritmo que calcule f(x) con
x valiendo 0 a 255 tienes dos alternativas:
- Haces un algoritmo (programa) que de forma procedural genere el valor de la
función f(x) que le corresponde a x
- Haces una tabla con todos los posibles valores de f(x) ordenados según el
valor de x
La tabla tiene una gran ventaja sobre el algoritmo, y es su velocidad: calcular
f(x) se limita a leer cierta posición de memoria que varía en función de x. En
esa posición de memoria está f(x). Sin embargo, para poder usar este método debe
cumplirse:
- x debe estar acotado de tal forma que el número de posiciones diferentes de
memoria no sea excesivo para la máquina en la que se va a implementar. Para una
máquina con 48K de RAM, 256 valores posibles no es problemático. Para un PC
trabajando en 32 bits, 65536 valores posibles tampoco es problemático. Si x
originalmente no es un número entero, o bien no se puede usar este método, o
bien hay que limitar x sólo a ciertos valores de su dominio e interpolar para el
resto.
- el cálculo de f(x) debe ser más costoso en tiempo de proceso que el hecho de
calcular qué posición de memoria ha de leerse y leerla.
Un ejemplo muy típico, en las demos y juegos, es tener tabulados los valores de
sen y cos para los valores de x desde 0 a 359 grados. Si se necesita un valor
intermedio, pongamos el coseno de 45.7 grados, se usan los valores de cos 45 y
cos 46 y se interpola entre ellos para averiguar el dado. La interpolación es
mucho menos costosa que el cálculo directo del coseno usando series de potencias.