ejercicio 1.txt

(9 KB) Pobierz
Vamos a hacer un tutorial orientado a un concurso en particular que salio de una idea de un grupo de telegram de hacer una competicion de programar algo en ensamblador y no solo jugar a juegos, aunque esta algomas orientada a programadores algo experimentados intentate hacerlo sificientemente entendible para los expertos y para los poco o nada experimentados.

como ensamblador usaremos el SJASM 0.42 en el que se puede escribir XOR A,A y convertirse en un unico opcode y no como en algunos enambladores que toman esta notacion como una macro que se convierte en 2 opcodes XOR A XOR A y tambien permite algunas licencias como aceptar mas formatos que otros compiladores, pero puedes usar cualquier otro ensamblador si lo prefiere como el pasmo...

http://xl2s.eu.pn/sjasm.html

lo mas sencillo que se me ocurrio fue hacer un motor para un juego como resultado final por varias razones y una de ellas es porque varias de las tareas se pueden llevar a cabo de forma facil y el resultado es algo practico, no solo un paso intermedio para aprender a programar, es decir, aprenderemos ensamblador con el paso del tiempo y de paso tendremos una libreria o un resultado de nuestra competicion que podra sernos utiles a nosotros o a cualquiera como resultado de cada iteraccion.

lo mas sencillo que se me ocurrio entonces fue hacer algo que necesitasemos en cualquier videojuego y que se puede programar de multiples formas con algunas restricciones por ser para una competicion.

TAREA: leer la entrada de datos desde un joystick en sus diferentes formatos para Spectrum: Sinclair I, Sinclair II, Kepston, Cursor, Fuller, el teclado tipico OPQA+Espacio y un teclado redefinible

Restricciones:
-. La salida de todos las lecturas debe de ser la misma, si pulsamos disparo el bit en cada uno de los joystick debe de ser el mismo para todos ellos y lo mismo para todas las direcciones en que nos movamos.
-. Los bits no utilizados deben de estar a 0.

Libertades:
-. La logica puede estar negada o no negada, es decir la salida 0001:0000 y 0000:1111 pueden ser interpretadas como que el boton de disparo esta activado en logica normal y en logica invertida dependiendo de la forma de interpretarlo que se quiera utilizar

Especificaciones (Datos):

puerto Kempston		(#  1F, 0x  1F,    31)	000FUDLR
puerto Sinclair I	(#F7FE, 0xF7FE, )	-x-FDURL
puerto Sinclair II	(#EFFE, 0xEFFE, )	-x-LRUDF
Puerto Cursor		(#F7FE, 0xF7FE, )	-x-L----
			(#EFFE, 0xEFFE, )	-x-UDR-0
Puerto Fuller		(#  7F, 0x  7F,   127)	F---RLDU (active low)

puerto Teclado		(#FEFE, 0xFEFE, )	-x-VCXZ (SHIFT)
puerto Teclado		(#FDFE, 0xFDFE, )	-x-GFDSA
puerto Teclado		(#FBFE, 0xFBFE, )	-x-TREWQ
puerto Teclado		(#F7FE, 0xF7FE, )	-x-54321
puerto Teclado		(#EFFE, 0xEFFE, )	-x-67890
puerto Teclado		(#DFFE, 0xDFFE, )	-x-YUIOP
puerto Teclado		(#BFFE, 0xBFFE, )	-x-HJKL (ENTER)
puerto Teclado		(#7FFE, 0x7FFE, )	-x-BNM (SYMBOL) (SPACE)

Siguiendo la politica de tutorial (o tontorial como llamo yo cari?osamente a los tutoriales) pondremos un ejemplo de como hacerlo, empezando por una de las combinaciones de teclas mas iconicas de todos los tiempo OPQA+Espacio

lo primero sera leer el puerto en donde tenemos alguna tecla, en este caso estan en sitios muy dispares por lo que requiere la lectura de un mayor numero de puertos para leer todas las direcciones pero antes de empezar vamos a pensar en las reglas que tenemos que cumplir.

paso 1: para poder obtener todos los bits de las direcciones de igual forma tendremos que al menos invertir el joystick typo Fuller ya que trabaja con logica negada respecto al resto y es mas facil de invertir solo los bits de este tipo que del resto.

paso 2: Para que todos los bis queden en la misma posiciion deberemos rotar varios de los bits para dejarlos en su lugar.

Aqui podemos utilizar varias aproximaciones para dar con la solucion, la lectura y posterior recolocacion de los bits o utilizar una tabla para hacer esto apartir de ella (la manera mas rapida)

vamos a obtener 2 bits correspondientes a las teclas O y P
	LD	A,#F7
	IN	A,[#FE]
	AND	A,#03
	LD	C,A
Ahora a?adimos la letra A a la ecuacion con la precaucion de dejar el bit en el lugar adecuado
	LD	A,#FD
	IN	A,[#FE]
	RLA
	RLA
	AND	A,#04
	OR	A,C
	LD	C,A

Repetimos la misma operacion con la letra Q
	LD	A,#FB
	IN	A,[#FE]
	RLA
	RLA
	RLA
	AND	A,#08
	OR	A,C
	LD	C,A

Y por ultimo la tecla espacio
	LD	A,#7F
	IN	A,[#FE]
	RLA
	RLA
	RLA
	RLA
	AND	A,#10
	OR	A,C
	LD	C,A
y ya solo nos queda volver, como lo que vamos a hacer es una rutina volvemos con un RET
	RET

con esto ya tendriamos nuestra rutina para leer las teclas OPQA+Espacio y ya tendriamos una parte del problema resuelto

Si miramos a la siguiente tabla en la que se indica en que bits estan cada direccion LR y RL se cumplen en la misma cantidad de ocasiones pero UD y DU no, ya que UD esta 3 veces en lugar de solo en 2 de ellas y hay que cumplir esta regla tambien, que siempre tengamos el mismo orden

puerto Kempston		(#  1F, 0x  1F,    31)	000FUDLR
puerto Sinclair I	(#F7FE, 0xF7FE, )	-x-FDURL
puerto Sinclair II	(#EFFE, 0xEFFE, )	-x-LRUDF
Puerto Cursor		(#F7FE, 0xF7FE, )	-x-L----
			(#EFFE, 0xEFFE, )	-x-UDR-0
Puerto Fuller		(#  7F, 0x  7F,   127)	F---RLDU (active low)

Ahora vamos a probar con una tabla que en el caso de los puertos sinclair los datos estan invertidos

	LD	A,#F7
	IN	A,[#FE]
	AND	A,#1F
	LD	L,A
	LD	H,#80
	LD	A,[HL]
	RET
org #8000
	DB	#00,#10,#08,#18,#04,#14,#0C,#1C
	DB	#02,#12,#0A,#1A,#06,#16,#0E,#0E
	DB	#01,#11,#09,#19,#05,#15,#0D,#1D
	DB	#03,#13,#0B,#1B,#07,#17,#0F,#1F

Esta rutina es mucho mas rapida pero necesita de 32 bits adicionales, como tenemos varios joystick podemos elegir entre ambas alternativas si vemos que el codigo relentiza en esceso la rutina o si esta es demasiado larga

No he hecho ninguna optimizacion, ni he tenido en cuenta el valor de los registros en ningun caso, cosa que se deberia de hacer.

como esqueleto del programa que llamase a la rutina del teclado para que ambos jugadores leidos de forma casi simultanea seria la siguiente

	EQU	player1   32001
	EQU	player2   32002
	EQU	joystick1 33000
	EQU	joystick1 34000

leerjoy	CALL	joystick1
	LD	[player1],A
	CALL	joystick2
	LD	[player2],A
	RET

dicha rutina puede ser llamada desde basic por lo que seria facil de usar en juegos en basic, simplemente con colocar el codigo en memoria con un CLEAR y colocar las direcciones de memoria en sitios mas adecuados, pero podria valer tal cual.
	Hay una ritina curiosa que seria de leer un teclado redefinible y aqui tenemos un problema adicional, podemo usar todo el teclado, pero nos podemos tomas alguna licencia "poetica", para leer cualquier tecla independientemente de donde este podemos usar el siguiente codigo en el cual tenemos 2 variables, es decir escribiendo en ella en 2 posiciones de memoria distintas sabremos si la tecla esta pulsada y cambiar la localizacion de dicha tecla.

	LD	A,#--
	IN	A,[#FE]
	AND	A,#--
	ADD	A,#FF
	RL	C

en LD A,#-- tenemos que seleccionar la semifila que queremos leer, y en AND A,#-- que tecla es la que hemos pulsado, incluso un programa para cambiar estos datos seria relativamente sencillo.

para usar esta porcion de codigo deberiamos de hacer algunos areglos como los siguientes
	LD	C,#00 (limpiar el teclado)
	[el codigo anteriormente escrito 4 veces]
	LD	A,#--
	IN	A,[#FE]
	AND	A,#--
	ADD	A,#FF
	...
		(aqui sustituimos el ultimo RL C por un peque?o truco)
	...
	LD	A,C
	RLA
	RET

con esto nos ahorramos 1 byte RL C ocupa mas y es mas lento que RLA y por otra parte lo que estamos a?adiendo es el Carry por le derecha del registro A y da igual hacerlo antes que despues

---------------------------------------------------------

estos son ejemplos de como hacerlo pero salvo la rutina para leer un teclado en el que las teclas esten redefinidas que quizas sea un problema algo mayor y que he dado ya hecha asi como el como hacer una rutina con una tabla para acelerar la lectura de un tipo en particular pero que ocupa mas memoria que si se programase.

recordar, las rutinas que he puesto no estan optimizadas de ninguna forma, salvo la del teclado redefinible, en ningun caso hacen una salvaguarda de ningun registro que deberia de hacerse en alguna parte.

una ritina deberia tener varias opciones de ser llevadas a cabo sin que ninguna de ellas sea o tenga que ser perfecta, en el Spectrum y en el microprocesador que integra hay varios recursos y hay que aprobecharlos lo mejor posible por lo que la forma de puntuar va a ser algo distinta y sera practicamente inposible consegir un 100% de los puntos... salvo que solo exista un participante

forma de puntuar:

el programa mas rapido se lleva 100 puntos y el mas lento la parte proporcional en la que sea mas lento, es decir si un programa tarda esactamente el doble que el mejor solo se llevara 50 punto en la categoria de velocidad

hay varias categorias:

-. Velocidad: Numero de T-States sin tener en cuenta la contencion. (menos tiempo de ejecucion)
-. Espacio en memoria: Numero de bytes que necesita la subrutina para ejecutarse incluyendo cualquier tabla. (a menor tama?o mas puntos)
-. Numero de registros de la CPU utilizados y la forma de utilizacion

En  cuanto al numero de registros utilizados aun no he definido una forma de puntuarlos, pero la mala utilizacion de un registro no es una buena practica aunque quizar el uso de el par de registros E como un contador en lugar de el registro B en ciertos casos puede ser un acierto, por lo que el uso de un mayor numero de registros no penalizara solo contara como una nota
Zgłoś jeśli naruszono regulamin