Desbloqueo del acceso a ASIC/RMR2 en los modelos Amstrad GX/Plus

¡Hola a todos!

Me topé con Programming:Unlocking ASIC. ¡Menudo contenido hay en esas rutinas optimizadas! :heart_eyes:

Y aquí van mis dos centavos al respecto.

Como se menciona en el hilo del antiguo foro enlazado, es responsabilidad de quien llama a la rutina
gestionar las interrupciones, ¡así que fuera todos los DI/EI! -2 bytes

Como recordatorio, la secuencia completa de desbloqueo de RMR2 que se debe escribir en el puerto E/S #BCxx es:
NZB, #00,#FF,#77...#8A, STATE (#CD), EOK

NZB: Cualquier valor excepto cero.
STATE: #CD desbloqueará (cualquier otro valor bloqueará).
EOK: Se debe enviar para sacar al ASIC de su secuencia de desbloqueo y recuperar la selección del registro CRTC por E/S. Puede ser cualquier valor.

La rutina optimizada clásica no aprovecha algunas propiedades de la secuencia de desbloqueo. Como por ejemplo:

  • Colocamos los datos de la secuencia justo después de que termine la rutina, con un RET, es decir, un código de operación &C9, que no es cero. ¡Mmm… me huele a un NZB! : -1 byte
  • ¿Para qué guardar el valor EOK en los datos de la secuencia? Nos da igual el valor que sea, enviaremos lo que nos encontremos: -1 byte

Esto nos da una versión ligeramente más ajustada:

				; Enviar una secuencia de 17 bytes al puerto E/S #BCxx para desbloquear
				; el acceso al registro RMR2. Enfoque KISS usando una tabla de valores puros.
				;
				; Tamaño: 28 bytes
				; Tiempo: 178 µs
				;
				; Salida:
				;  BC=&BC00
				;  Modifica HL y Flags 
rmr2_unlock:
				ld bc,&BC00+17
				ld hl,_rmr2_data_key
_rmr2_send_key		inc b
					outi
					dec c
					jr nz,_rmr2_send_key
_rmr2_data_key	ret		; Este opcode se usa también como valor SYNC/NZB (#C9)
				db 0, &FF,&77,&B3,&51,&A8,&D4,&62,&39,&9C,&46,&2B,&15,&8A
_rmr2_data_lock	db 205	; 205 para Desbloquear, cualquier otro para bloquear

				; La rutina leerá un byte de más en esta posición
				; para obtener un valor EOK, necesario para el desbloqueo correcto.

Y ahora, con 28 bytes de longitud, esta rutina tan al estilo KISS hace que las optimizadas parezcan… Bueno, no importa. (¡os seguimos queriendo!)

Pero la rutina de re-implementación de LFSR de @Urusergi me dio cierto gusanillo. Hay taaaantas formas y trucos de bits para implementar estas diminutas cosas de LFSR, que podría haber algunas variaciones más cortas por ahí…

…unos días, llantos y sangrados de nariz después: ¡bueno, parece que no tantas!
Solo encontré una:

				; Re-implementación por software de la lógica LFSR descrita en
				; la patente de Amstrad (GB2243701A). Genera una secuencia de
				; 15 bytes verificada por el ASIC para desbloquear el acceso a RMR2.
				;
				; Diseñada por Urusergi
				; Modificada por Grim (¡rascando un solo byte, uf!)
				;
				; Tamaño: 27 bytes
				; Tiempo: 389 µs
				;
				; Salida:
				;  BC=&BCFF
				;  Modifica HL y AF
rmr2_unlock:
				ld bc,&BCFF
				out (c),c ; SYNC/NZB
				out (c),0 ; SYNC/NUL
				ld a,c
_rmr2_send_key
					out (c),a
					ld h,a
					add hl,hl
					rra
					add hl,hl
					ld l,a
					xor h
					and &F7
					xor l
					add a,h
					and &88
					xor l
					cp c
					jr nz,_rmr2_send_key
				ret

Intenté deshacerme de la (coqueta) prueba de salida cp c y usar algún flag después del último xor l, pero por ahora no lo he conseguido. ¡El cp c se queda! :slight_smile:

1 me gusta

La optimización prematura es la raíz de todos los males.

Solo necesitas desbloquear el ASIC exactamente una vez. No hay ninguna razón sensata para volver a bloquearlo.

Ahorrar un puñado de bytes es extremadamente poco probable que sirva para algo, excepto tal vez en algún escenario extraño de tipo demo de 4K, en cuyo caso las desventajas de que las máquinas Plus no tengan rutinas de ROM existentes a las que puedas llamar para funcionalidades básicas como esta, por lo general, anularán cualquier ventaja sobre simplemente escribir código estándar de CPC.

Veo un posible caso de uso para bloquear el ASIC después de restablecer ciertas funciones. Es muy probable que este escenario involucre código de demostración de CPC que busca ser compatible con CRTC Type 3, mientras se abusa intencionadamente del bit 5 de GateArray RMR por razones oscuras de optimización, lo que podría causar problemas significativos si el ASIC permanece desbloqueado.

Así que tienes razón, definitivamente no hay ninguna razón sensata :slight_smile:

Si tu código es consciente del ASIC, creo que te costaría encontrar un caso realista en el que necesites enviar un valor que altere el RMR2. Y es aún menos probable que hacer algo así compense la sobrecarga de volver a desbloquear el ASIC la próxima vez que necesites cambiar cualquiera de las funciones del Plus.

Es simplemente uno de esos escenarios que no tienen mucho sentido.

Programar demos no tiene por qué tener sentido, siempre y cuando se ejecute rápido. Especialmente al hacer beam-racing, lo habitual es intentar meter a la fuerza y empaquetar la mayor cantidad de datos posible en los registros del Z80 (son veloces), reutilizándolos y exprimiéndolos al máximo. Y luego, tu comando de GA no es solo eso, sino que también actúa como una dirección de E/S en sombra para otro dispositivo, controla bits en el Puerto C del PPI y qué sé yo. Cada bit cuenta.

Y solo el código de inicio de tu demo para CPC necesita detectar el ASIC (para asegurarte de que el hardware esté estable antes de tomar el control), pero todo lo que venga después puede asumir con seguridad un GateArray de CPC donde el bit 5 de su comando no tiene ningún efecto.

Por tanto, no se trata de desbloquear/bloquear el ASIC cada vez que necesites trastear en él; lo haces solo una vez. Simplemente consiste en configurar adecuadamente el hardware antes de que se ejecute el código principal para CPC (no Plus). No hay ningún consumo de recursos que sobrepesar aquí.