En primer lugar, no es buena idea hacer un programa con pantallas y menús metido en una variable del BASIC, ya que el contenido de la variable va cambiando su ubicación en cada nueva ejecución, y no se puede predecir dónde quedará la rutina USR.
He visto programas que antes de invocar al USR, cambian los bytes de la rutina que representan direcciones fijas, por ejemplo, sumándole el ADR(RUT$) a cada par LO-HI en el string que tiene las direcciones absolutas a partir de la dirección de memoria cero... es decir, el programa en el string estaba cocinado para que sea fácil de modificar para funcione correctamente. Pero insisto, es mala idea meter cosas que incluyen direcciones fijas en strings de BASIC y asumir que funcionarán así tal como está. Recuerden que un programa BASIC puro es interpretado por el cartucho y el manejo de memoria lo administra él. Con el USR estamos rompiendo las reglas y para que eso no sea problema, las rutinas deben cumplir ciertas reglas que ya expliqué, siendo la más importante que todo direccionamiento dentro del código debe ser relativo.
Pero no todo está perdido, es posible hacer algo interesante con este ejemplo, aprovechando ciertas cosas. Primero, no es necesario poner la dirección de memoria del texto en cada línea a desplegar cuando están contiguas, con lo que podemos disminuir la cantidad de bytes que requieren modificarse. Segundo, podemos decirle a la rutina USR qué lugares de sí mima modificar usando parámetros adicionales. En este caso, visualizo 2 lugares a modificar y 2 los valores respectivos para esos lugares. Pero para ello necesitamos un puntero en página cero que nos ayude.
Código: Seleccionar todo
*= $0600
PUNTERO = $CE
INICIO
LDA $02C5
STA $02C7
LDA $02C8
STA $02C6
PLA
PLA ;>CAMBIO1
STA PUNTERO+1
PLA ;<CAMBIO1
STA PUNTERO
LDY #1
PLA ;>LINEA1
STA (PUNTERO),Y
DEY
PLA ;<LINEA1
STA (PUNTERO),Y
PLA ;>CAMBIO2
STA PUNTERO+1
PLA ;<CAMBIO2
STA PUNTERO
LDY #1
PLA ;>HLIST
STA (PUNTERO),Y
STA $0231
DEY
PLA ;<HLIST
STA (PUNTERO),Y
STA $0230
LDA #1
LOOP BNE LOOP
LINEA1 .SBYTE " mi programa atari "
LINEA2 .SBYTE " PROGRAMAS PARA COMPUTADORES ATARI 2015 "
LINEA3 .SBYTE "OTRO EJEMPLO PARA VE"
LINEA4 .SBYTE " CREADO POR DOGDARK Y VITOCO 2015 "
HLIST
.BYTE $70,$70
.BYTE $46
CAMBIO1
.WORD LINEA1
.BYTE $70,$70
.BYTE $03 ;$43
; .WORD LINEA2
.BYTE $70,$70,$70,$70,$70,$70,$70,$70
.BYTE $07 ;$47
; .WORD LINEA3
.BYTE $70,$70,$70,$70,$70,$70,$70,$70
.BYTE $03 ;$43
; .WORD LINEA4
.BYTE $41
CAMBIO2
.WORD HLIST
; *= $02E0
; .WORD INICIO
La rutina tendría que ser invocada así:
X=USR(ADR(L$),CAMBIO1,LINEA1,CAMBIO2,HLIST)
Como el programa en BASIC no sabe a qué corresponde cada etiqueta del ASM, se lo damos precalculado:
M=ADR(L$)
X=USR(M,M+c1,M+c2,M+c3,M+c4)
donde debemos calcular las constantes restando los valores que entrega la compilación, es decir:
c1=CAMBIO1-INICIO
c2=LINEA1-INICIO
c3=CAMBIO2-INICIO
c4=HLIST-INICIO
NOTA: podría haber contado los bytes y ponerlos acá para las constantes, pero al menor cambio en la rutina, esos se moverían... prefiero explicar cómo obtener los valores y recalcularlos a manito cada vez, o bien poner las constantes con las restas tal cual al final del listado ASM para que sean calculados automáticamente y los copiemos al USR en el BASIC.
Yo no he probado esto... Lo dejo como tarea.
Ah! Algo muy importante: hay una restricción de hardware en el Atari que impide que una lista de despliegue traspase la frontera de 1K, es decir, no puede partir antes de una dirección de memoria que sea múltiplo de 1024 y terminar después de ella... (excepto si se usa la "instrucción" 65 ($41)). Como si eso fuera poco, la data a desplegar en una misma línea tampoco puede pasar por sobre una dirección que sea múltiplo de 4K. Como estamos en BASIC, no sabemos si pueda suceder eso o no, y habría que hacer malabares adicionales con DIM para evitarlo. Es por eso que insistía que no es buena idea meter un programa con pantallas en un string de BASIC para un USR