Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:paginacion_128k [04-01-2024 17:28] – [Particularidades +2A/+3] sromero | cursos:ensamblador:paginacion_128k [19-01-2024 12:23] (actual) – [Ejemplo sencillo: alternando Bancos 0 y 1] sromero | ||
---|---|---|---|
Línea 10: | Línea 10: | ||
Los modelos de Spectrum 128K, +2, +2A, +2B y +3 disponen de 128KB de memoria, aunque no toda está disponible simultáneamente. Al igual que en el modelo de 48KB, el microprocesador Z80 sólo puede direccionar 64K-direcciones de memoria, por lo que para acceder a esta memoria " | Los modelos de Spectrum 128K, +2, +2A, +2B y +3 disponen de 128KB de memoria, aunque no toda está disponible simultáneamente. Al igual que en el modelo de 48KB, el microprocesador Z80 sólo puede direccionar 64K-direcciones de memoria, por lo que para acceder a esta memoria " | ||
- | | + | |
Así que ... ¿cómo hacemos para utilizar más de 64KB de memoria si nuestro procesador sólo puede leer datos de la celdilla 0, 1, 2, 3 ... 65534 y 65535? La respuesta es: **mediante la paginación**. | Así que ... ¿cómo hacemos para utilizar más de 64KB de memoria si nuestro procesador sólo puede leer datos de la celdilla 0, 1, 2, 3 ... 65534 y 65535? La respuesta es: **mediante la paginación**. | ||
- | Los 64KB de memoria del Spectrum, se dividen en 4 bloques de 16KB. El primer bloque ($0000 - $4000) está mapeado sobre la ROM del Spectrum. Accediendo a los bytes desde $0000 a $3FFF de la memoria estamos accediendo a los bytes $0000 a $3FFF del "chip (físico)" | + | Los 64KB de memoria del Spectrum, se dividen en 4 bloques de 16KB. El primer bloque ($0000 - $4000) está mapeado sobre la ROM del Spectrum. Accediendo a los bytes desde $0000 a $3fff de la memoria estamos accediendo a los bytes $0000 a $3fff del "chip (físico)" |
- | | + | |
- | El bloque que nos interesa a nosotros es el cuarto. La zona final del área de memoria, desde $C000 a $FFFF, es nuestra " | + | El bloque que nos interesa a nosotros es el cuarto. La zona final del área de memoria, desde $c000 a $ffff, es nuestra " |
| | ||
Línea 26: | Línea 26: | ||
\\ | \\ | ||
- | | + | |
- | La última porción de 16KB de la memoria es, pues, una " | + | La última porción de 16KB de la memoria es, pues, una " |
- | Si paginamos el bloque 1 en nuestra ventana $C000-$FFFF, cuando accedamos a este rango de memoria, ya no accederíamos a los mismos datos que guardamos en el banco 0, sino a la zona de memoria "Banco 1". Es posible incluso mapear la zona de pantalla (Banco 5), de forma que las direcciones $4000 y $C000 serían equivalentes: | + | Si paginamos el bloque 1 en nuestra ventana $c000-$ffff, cuando accedamos a este rango de memoria, ya no accederíamos a los mismos datos que guardamos en el banco 0, sino a la zona de memoria "Banco 1". Es posible incluso mapear la zona de pantalla (Banco 5), de forma que las direcciones $4000 y $c000 serían equivalentes: |
- | El mapa de memoria del Spectrum con los bloques mapeables/ | + | El mapa de memoria del Spectrum con los bloques mapeables/ |
\\ | \\ | ||
{{ cursos: | {{ cursos: | ||
+ | \\ | ||
\\ | \\ | ||
===== Cambiando de banco ===== | ===== Cambiando de banco ===== | ||
- | El puerto que controla la paginación en los modelos 128K es el $7FFD. En realidad, nuestro Spectrum sólo decodifica los bits 1 y 15, por lo que cualquier combinación con los bits 1 y 15 a cero accederá a la gestión de paginación. No obstante, se recomiente utilizar $7FFD por compatibilidad con otros sistemas. | + | El puerto que controla la paginación en los modelos 128K es el $7ffd. En realidad, nuestro Spectrum sólo decodifica los bits 1 y 15, por lo que cualquier combinación con los bits 1 y 15 a cero accederá a la gestión de paginación. No obstante, se recomiente utilizar $7ffd por compatibilidad con otros sistemas. |
- | La lectura del puerto $7FFD no devolverá ningún valor útil, pero sí podemos escribir en él un valor con cierto formato: | + | La lectura del puerto $7ffd no devolverá ningún valor útil, pero sí podemos escribir en él un valor con cierto formato: |
|< 60% >| | |< 60% >| | ||
Línea 48: | Línea 49: | ||
| 0-2 | Página de la RAM (0-7) a mapear en el bloque $c000 - $ffff. | | | 0-2 | Página de la RAM (0-7) a mapear en el bloque $c000 - $ffff. | | ||
| 3 | Visualizar la pantalla gráfica " | | 3 | Visualizar la pantalla gráfica " | ||
- | | 4 | Selección de la ROM, entre (0) ROM BASIC 128K (Menú y editor), y (1) BASIC 48K. | | + | | 4 | Selección de la ROM, entre (0) ROM BASIC 128K (Menú y editor), y (1) BASIC 48K. | |
- | | 5 | Si lo activamos, se desactivará el paginado de memoria hasta que se resetee el\\ Spectrum. El hardware ignorará toda escritura al puerto $7FFD. | | + | | 5 | Si lo activamos, se desactivará el paginado de memoria hasta que se resetee el\\ Spectrum. El hardware ignorará toda escritura al puerto $7ffd. | |
- | + | ||
A la hora de cambiar de página de memoria hay que tener en cuenta lo siguiente: | A la hora de cambiar de página de memoria hay que tener en cuenta lo siguiente: | ||
- | * La pila (stack) debe de estar ubicada en una zona de memoria que no vaya a ser paginada (no puede estar dentro de la zona que va a cambiar). | + | \\ |
- | | + | * Las interrupciones deben de estar deshabilitadas para realizar el cambio de banco. |
- | * Si se va a ejecutar código con interrupciones (y no pueden estar deshabilitadas), | + | |
+ | * La pila (stack) debe de estar ubicada en una zona de memoria que no vaya a ser paginada (no puede estar dentro de la zona que va a cambiar), ya que su contenido se perdería después del cambio de banco. | ||
+ | |||
+ | * Si estamos utilizando o vamos a utilizar el modo de interrupciones 2 ('' | ||
+ | |||
+ | * Si se va a ejecutar código con interrupciones (y no pueden estar deshabilitadas), | ||
+ | \\ | ||
Un ejemplo de cambio de banco en ASM: | Un ejemplo de cambio de banco en ASM: | ||
<code z80> | <code z80> | ||
- | | + | ld a, ($5b5c) |
- | AND | + | and %11111000 |
- | OR 4 ; Seleccionar banco 4 | + | or %00000100 |
- | LD BC, $7ffd | + | ld bc, $7ffd |
- | DI | + | |
- | LD | + | |
- | OUT (C), A | + | |
- | EI | + | ei |
</ | </ | ||
Línea 80: | Línea 86: | ||
; | ; | ||
SetRAMBank: | SetRAMBank: | ||
- | LD A, ($5b5c) | + | ld a, ($5b5c) |
- | AND $f8 ; Cambia sólo los bits que debas cambiar | + | and %11111000 |
- | OR B ; Seleccionar banco " | + | or b ; Seleccionar banco " |
- | LD BC, $7ffd ; Colocamos en BC el puerto a | + | ld bc, $7ffd ; Colocamos en BC el puerto a |
- | DI | + | |
- | LD ($5b5c), | + | |
- | OUT (C), A | + | |
- | EI | + | ei |
- | RET | + | ret |
</ | </ | ||
- | + | Un detalle apuntado por la documentación de World Of Spectrum es que los bancos 1, 3, 5 y 7 son " | |
- | Un detalle apuntado por la documentación de World Of Spectrum es que los bancos 1, 3, 5 y 7 son " | + | |
\\ | \\ | ||
Línea 99: | Línea 104: | ||
En el caso del +2A y +3 hay que tener en cuenta una serie de detalles " | En el caso del +2A y +3 hay que tener en cuenta una serie de detalles " | ||
- | * Los bancos de contended-memory son los bloques 4, 5, 6 y 7 (no el 1, 3, 5 y 7). | + | \\ |
- | | + | |
- | | + | |
+ | | ||
+ | |||
+ | | ||
+ | \\ | ||
- | Este puerto (el $1FFD) tiene el siguiente significado a la hora de escribir en él: | + | Este puerto (el $1ffd) tiene el siguiente significado a la hora de escribir en él: |
|< 60% >| | |< 60% >| | ||
Línea 112: | Línea 121: | ||
| 3-4 | 3=Motor del disco (1/0, ON/OFF), 4=Impresora | | | 3-4 | 3=Motor del disco (1/0, ON/OFF), 4=Impresora | | ||
- | | + | |
\\ | \\ | ||
Línea 123: | Línea 132: | ||
^ ROM ^ Contenido ^ | ^ ROM ^ Contenido ^ | ||
| 0 | Editor 128K, Menú y programa de testeo | | | 0 | Editor 128K, Menú y programa de testeo | | ||
- | | 1 | Chequeador de sintaxis 128K BASIC | | + | | 1 | Chequeador de sintaxis 128K BASIC | |
| 2 | +3DOS | | | 2 | +3DOS | | ||
| 3 | BASIC 48K | | | 3 | BASIC 48K | | ||
- | De nuevo, al igual que en el caso del puerto genérico sobre paginación, | + | De nuevo, al igual que en el caso del puerto genérico sobre paginación, |
\\ | \\ | ||
Línea 135: | Línea 144: | ||
\\ | \\ | ||
- | * Paginamos el bloque/ | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
+ | |||
+ | | ||
\\ | \\ | ||
- | | + | |
Para terminar de comprender el ejemplo, lo mejor es compilarlo y ejecutarlo: | Para terminar de comprender el ejemplo, lo mejor es compilarlo y ejecutarlo: | ||
Línea 152: | Línea 168: | ||
; | ; | ||
; Bancos.asm | ; Bancos.asm | ||
- | ; | ||
; Demostracion del uso de bancos / paginación en modo 128K | ; Demostracion del uso de bancos / paginación en modo 128K | ||
; | ; | ||
+ | ORG 35000 | ||
- | ORG 35000 | + | call CLS |
- | + | ||
- | LD HL, 0 | + | |
- | ADD HL, SP ; Guardamos el valor actual de SP | + | |
- | EX DE, HL ; lo almacenamos en DE | + | |
- | LD SP, 24000 | + | ld hl, 0 |
+ | add hl, sp | ||
+ | ex de, hl ; lo almacenamos en DE | ||
- | CALL Wait_For_Keys_Released | + | ld sp, 26000 ; Pila fuera de $c000-$ffff |
- | LD HL, $c000 ; Nuestro puntero | + | |
- | ; Ahora paginamos el banco 0 sobre $c000 y guardamos un valor | + | call Wait_For_No_Key |
- | ; en el primer byte de sus 16K (en la direccion | + | ld hl, $c000 ; Nuestro puntero |
- | LD B, 0 | + | |
- | CALL SetRAMBank | + | |
- | LD A, $AA | + | ; Ahora paginamos el banco 0 sobre $c000 y guardamos un valor |
- | LD (HL), A | + | ; en el primer byte de sus 16K (en la direccion |
+ | ld b, 0 | ||
+ | call SetRAMBank | ||
- | ; Ahora paginamos el banco 1 sobre $c000 y guardamos un valor | + | ld a, $AA |
- | ; en el primer byte de sus 16K (en la direccion | + | ld (hl), a |
- | LD B, 1 | + | |
- | CALL SetRAMBank | + | |
- | LD A, $01 | + | ; Ahora paginamos el banco 1 sobre $c000 y guardamos un valor |
- | LD (HL), A | + | ; en el primer byte de sus 16K (en la direccion |
+ | ld b, 1 | ||
+ | call SetRAMBank | ||
- | | + | ld a, $01 |
- | CALL Wait_For_Keys_Pressed | + | ld (hl), a |
- | CALL Wait_For_Keys_Released | + | |
- | | + | |
- | ; hay en $c000 y lo representamos en pantalla. Recordemos que | + | call Wait_For_Key |
- | ; acabamos de escribir $01 (00000001) | + | |
- | ; y que en su momento pusimos $AA (unos y ceros alternados): | + | |
- | LD B, 0 | + | |
- | CALL SetRAMBank | + | |
- | LD A, (HL) ; Leemos ($c000) | + | |
- | CALL ClearScreen | + | |
- | | + | |
- | CALL Wait_For_Keys_Pressed | + | ; hay en $c000 y lo representamos en pantalla. Recordemos que |
- | CALL Wait_For_Keys_Released | + | ; acabamos de escribir $01 (00000001) antes de cambiar de banco, |
+ | ; y que en su momento pusimos $AA (unos y ceros alternados): | ||
+ | ld b, 0 | ||
+ | call SetRAMBank | ||
+ | ld a, (hl) ; Leemos ($c000) | ||
+ | call ClearScreen | ||
- | | + | |
- | ; hay en $c000 y lo representamos en pantalla. Recordemos que | + | call Wait_For_Key |
- | ; acabamos de leer $A antes de cambiar de banco, y que en su | + | |
- | ; momento pusimos $01: | + | |
- | LD B, 1 | + | |
- | CALL SetRAMBank | + | |
- | LD A, (HL) ; Leemos ($c000) | + | |
- | CALL ClearScreen | + | |
- | | + | |
- | CALL Wait_For_Keys_Pressed | + | ; hay en $c000 y lo representamos en pantalla. Recordemos que |
- | CALL Wait_For_Keys_Released | + | ; acabamos de leer A antes de cambiar de banco, y que en su |
+ | ; momento pusimos $01: | ||
+ | ld b, 1 | ||
+ | call SetRAMBank | ||
+ | ld a, (hl) ; Leemos ($c000) | ||
+ | call ClearScreen | ||
- | EX DE, HL ; Recuperamos SP para poder volver | + | |
- | LD SP, HL ; a BASIC sin errores | + | call Wait_For_Key |
- | RET | + | |
+ | ex de, hl ; Recuperamos SP para poder volver | ||
+ | ld sp, hl ; a BASIC sin errores | ||
+ | ret | ||
; | ; | ||
Línea 223: | Línea 235: | ||
; | ; | ||
SetRAMBank: | SetRAMBank: | ||
- | LD A, | + | ld a, ($5b5c) |
- | AND $f8 ; Sólo cambiamos los bits necesarios | + | and %11111000 |
- | OR B ; Elegir banco " | + | or b ; Elegir banco " |
- | LD BC,$7ffd | + | ld bc, $7ffd |
- | DI | + | di |
- | LD ($5b5c),A | + | |
- | OUT (C),A | + | |
- | EI | + | ei |
- | RET | + | ret |
; | ; | ||
Línea 239: | Línea 250: | ||
; | ; | ||
ClearScreen: | ClearScreen: | ||
- | PUSH HL | + | push hl |
- | PUSH DE | + | push de |
- | LD HL, 16384 | + | ld hl, 16384 |
- | LD (HL), A | + | |
- | LD DE, 16385 | + | ld de, 16385 |
- | LD BC, 6143 | + | ld bc, 6143 |
- | LDIR | + | ldir |
- | POP DE | + | |
- | POP HL | + | pop hl |
- | RET | + | ret |
- | + | ||
- | + | ||
- | ; | + | |
- | ; Rutinas para esperar la pulsación y liberación | + | |
- | ; | + | |
- | Wait_For_Keys_Pressed: | + | |
- | XOR A ; A = 0 | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR Z, Wait_For_Keys_Pressed | + | |
- | RET | + | |
- | + | ||
- | Wait_For_Keys_Released: | + | |
- | XOR A | + | |
- | IN A, (254) | + | |
- | OR 224 | + | |
- | INC A | + | |
- | JR NZ, Wait_For_Keys_Released | + | |
- | RET | + | |
- | END 35000 | + | ;--- Libreria utils.asm --- |
+ | INCLUDE " | ||
+ | END 35000 | ||
</ | </ | ||
Línea 282: | Línea 275: | ||
| | ||
- | A continuación podemos ver una rutina, que nos permitirá detectar si el modelo de Spectrum que estamos ejecutando es 48K o 128K. Para saber si estamos en un modelo 48K o en un modelo 128K, simplemente tratamos de paginar escribiendo y recuperando valores en la dirección $C000, antes y después de paginar dicho banco, para ver si el valor cambia o no. Según el resultado de esta operación, establecemos a 1 o no la variable de memoria | + | A continuación podemos ver una rutina, que nos permitirá detectar si el modelo de Spectrum que estamos ejecutando es 48K o 128K. Para saber si estamos en un modelo 48K o en un modelo 128K, simplemente tratamos de paginar escribiendo y recuperando valores en la dirección $c000, antes y después de paginar dicho banco, para ver si el valor cambia o no. Según el resultado de esta operación, establecemos a 1 o no la variable de memoria |
<code z80> | <code z80> | ||
- | ORG 35000 | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; | ; | ||
Línea 305: | Línea 298: | ||
; | ; | ||
CHECK_128: | CHECK_128: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; en un 128k mantendra el valor original => Z | ; en un 128k mantendra el valor original => Z | ||
; en un 48k el contenido de HL estara invertido => NZ | ; en un 48k el contenido de HL estara invertido => NZ | ||
- | | + | |
; Si NZ => 48K => salimos sin tocar el " | ; Si NZ => 48K => salimos sin tocar el " | ||
- | | + | |
; tiene paginacion de memoria es un 128k, +2, +2AB/E o +3/E | ; tiene paginacion de memoria es un 128k, +2, +2AB/E o +3/E | ||
- | | + | |
- | | + | |
fin_check_128: | fin_check_128: | ||
- | | + | |
- | | + | |
es_128k | es_128k | ||
; | ; | ||
- | ROM_CLS | + | ROM_CLS |
- | ROM_STACK_BC | + | ROM_STACK_BC |
- | ROM_PRINT_FP | + | ROM_PRINT_FP |
- | END 35000 | + | |
</ | </ | ||
Si ejecutamos este programa, veremos aparecer en pantalla un " | Si ejecutamos este programa, veremos aparecer en pantalla un " | ||
- | Esta rutina, ejecutada al principio de nuestro programa, establecerá pues la variable | + | Esta rutina, ejecutada al principio de nuestro programa, establecerá pues la variable |
Línea 371: | Línea 364: | ||
El problema es que mientras el haz de electrones del monitor avanza redibujando la imagen, el Spectrum no puede interrumpirlo (de hecho, no puede controlarlo, | El problema es que mientras el haz de electrones del monitor avanza redibujando la imagen, el Spectrum no puede interrumpirlo (de hecho, no puede controlarlo, | ||
- | Esto implica que cuando la ULA está " | + | Esto implica que cuando la ULA está " |
- | Por eso, los programas que corren en el bloque de 16KB entre $4000 (16384) y $7FFF (32767), o pretenden acceder a la misma justo cuando la ULA quiere leer algún dato gráfico de la VRAM, pueden resultar más lentos en ejecución cuando la ULA está leyendo la pantalla. | + | Por eso, los programas que corren en el bloque de 16KB entre $4000 (16384) y $7fff (32767), o pretenden acceder a la misma justo cuando la ULA quiere leer algún dato gráfico de la VRAM, pueden resultar más lentos en ejecución cuando la ULA está leyendo la pantalla. |
Como se detalla en la FAQ de comp.sys.sinclair alojada en World Of Spectrum, este efecto sólo se da cuando se está dibujando la pantalla propiamente dicha, ya que para el trazado del borde la ULA proporciona al haz de electrones el color a dibujar y no se accede a memoria, por lo que no se produce este retraso o delay. | Como se detalla en la FAQ de comp.sys.sinclair alojada en World Of Spectrum, este efecto sólo se da cuando se está dibujando la pantalla propiamente dicha, ya que para el trazado del borde la ULA proporciona al haz de electrones el color a dibujar y no se accede a memoria, por lo que no se produce este retraso o delay. | ||
- | | + | |
Como podéis imaginar, este es uno de los mayores quebraderos de cabeza para los programadores de emuladores, y es la principal causa (junto con la **Contended I/O**, su equivalente en cuanto a acceso de puertos, también producido por la ULA), de que en los primeros tiempos de la emulación, no todos los juegos fueran correctamente emulados con respecto a su funcionamiento en un Spectrum. También muchas demos con complejas sincronizaciones y timings dejaban de funcionar en emuladores de Spectrum que no implementaban estos " | Como podéis imaginar, este es uno de los mayores quebraderos de cabeza para los programadores de emuladores, y es la principal causa (junto con la **Contended I/O**, su equivalente en cuanto a acceso de puertos, también producido por la ULA), de que en los primeros tiempos de la emulación, no todos los juegos fueran correctamente emulados con respecto a su funcionamiento en un Spectrum. También muchas demos con complejas sincronizaciones y timings dejaban de funcionar en emuladores de Spectrum que no implementaban estos " | ||
- | + | ||
- | En nuestro caso, como programadores, | + | En nuestro caso, como programadores, |
Para que los retrasos de la ULA no afecten a nuestro programa, podemos poner al principio del mismo (en esos 6768 bytes iniciales) todas las rutinas que utilicemos al principio del mismo o que su ejecución no sea vital en cuanto a tiempos: funciones para el menú del juego, detección de 128K/48K, rutinas de redefinición del teclado, textos de los menúes y del fin del juego, etc. | Para que los retrasos de la ULA no afecten a nuestro programa, podemos poner al principio del mismo (en esos 6768 bytes iniciales) todas las rutinas que utilicemos al principio del mismo o que su ejecución no sea vital en cuanto a tiempos: funciones para el menú del juego, detección de 128K/48K, rutinas de redefinición del teclado, textos de los menúes y del fin del juego, etc. | ||
Línea 390: | Línea 383: | ||
===== Contended Memory + Paginación | ===== Contended Memory + Paginación | ||
- | | + | |
* Modelos +2/128K : Bancos 1, 3, 5 y 7. | * Modelos +2/128K : Bancos 1, 3, 5 y 7. | ||
Línea 398: | Línea 391: | ||
< | < | ||
- | The RAM banks are of two types: RAM pages 4 to 7 which are contended | + | The RAM banks are of two types: RAM pages 4 to 7 which are contended |
(meaning that they share time with the video circuitry), and RAM pages | (meaning that they share time with the video circuitry), and RAM pages | ||
0 to 3 which are uncontended (where the processor has exclusive use). | 0 to 3 which are uncontended (where the processor has exclusive use). | ||
Línea 407: | Línea 400: | ||
For example, executing NOPs in contended RAM will give an effective | For example, executing NOPs in contended RAM will give an effective | ||
clock frequency of 2.66Mhz as opposed to the normal 3.55MHz in | clock frequency of 2.66Mhz as opposed to the normal 3.55MHz in | ||
- | uncontended RAM. | + | uncontended RAM. |
This is a reduction in speed of about 25%. | This is a reduction in speed of about 25%. | ||
Línea 419: | Línea 412: | ||
\\ | \\ | ||
- | ===== Paginación de memoria desde Z88DK (C) ===== | ||
- | | + | ===== En resumen ===== |
- | <code c> | + | |
- | //--- SetRAMBank ------------------------------------------------------ | + | |
- | // | + | |
- | // Se mapea el banco (0-7) indicado sobre $C000. | + | |
- | // | + | |
- | // Ojo: aqui no se deshabilitan las interrupciones | + | |
- | // de usar el registro B, se usa un parametro tomado desde la pila. | + | |
- | // En caso de ser importante la velocidad, se puede usar " | + | |
- | // el parametro | + | |
- | // | + | |
- | void SetRAMBank(char banco) | + | |
- | { | + | |
- | #asm | + | |
- | | + | |
- | ld hl, 2 | + | |
- | add hl, sp | + | |
- | | + | |
- | ld b, a | + | Esto es así porque el Z80 tiene un bus de direcciones de 16 bits, por lo que no es capaz de direccionar más de 65535 bytes. Por eso, para acceder a más de 65535 bytes necesitamos " |
- | | + | |
- | and F8h | + | |
- | | + | |
- | | + | |
- | | + | |
- | out (C), A | + | |
- | # | + | |
- | } | + | |
- | </ | + | |
- | Con el anterior código podemos mapear uno de los bancos | + | Es nuestra responsabilidad paginar |
- | * Todo el código en ejecución debe estar por debajo de $C000, para lo cual es recomendable definir los gráficos al final del " | + | Una vez tenidas |
- | * Es importantísimo colocar la pila en la memoria baja, mediante | + | |
- | < | + | Así, por ejemplo, podemos almacenar los datos de diferentes niveles en diferentes bloques, y cambiar de uno a otro mediante paginación en el momento adecuado. Esto permite realizar cargas de datos desde cinta almacenando la totalidad de los datos del juego o programa en bancos libres de memoria y convertir nuestro juego multicarga (con una carga por fase) en un juego de carga única (con todos los elementos del juego almacenados en memoria), evitando el tedioso sistema de rebobinar y volver a cargar la primera fase cuando el jugador muere. |
- | /* Allocate space for the stack */ | + | |
- | #pragma output STACKPTR=24500 | + | |
- | </ | + | |
- | + | ||
- | La regla general es asegurarse de que no haya nada importante (para la ejecución de nuestro programa) en el bloque $C000 a $FFFF cuando se haga el cambio: ni la pila, ni código al que debamos acceder. Tan sólo datos que puedan ser intercambiandos de un banco a otro sin riesgo para la ejecución del mismo (por ejemplo, los datos de un nivel de juego en el que ya no estamos). | + | |
- | + | ||
- | + | ||
- | \\ | + | |
- | ===== En resumen ===== | + | |
- | + | ||
- | | + | |
- | + | ||
- | Así, podemos almacenar los datos de diferentes niveles en diferentes bloques, y cambiar de uno a otro mediante paginación en el momento adecuado. Esto permite realizar cargas de datos desde cinta almacenando la totalidad de los datos del juego o programa en bancos libres de memoria y convertir nuestro juego multicarga (con una carga por fase) en un juego de carga única (con todos los elementos del juego almacenados en memoria), evitando el tedioso sistema de rebobinar y volver a cargar la primera fase cuando el jugador muere. | + | |
- | Ahora bastará con que nuestro programa, una vez cargado en memoria y en ejecución, pagine un determinado bloque, cargue 16K-datos sobre él, pagine otro bloque diferente, y realice otra carga de datos desde cinta, y así sucesivamente con todos los bloques de datos del juego. Estas cargas de datos podemos hacerlas bien desde nuestro programa " | + | En modo 128K bastará con que nuestro programa, una vez cargado en memoria y en ejecución, pagine un determinado bloque, cargue 16K-datos sobre él, pagine otro bloque diferente, y realice otra carga de datos desde cinta, y así sucesivamente con todos los bloques de datos del juego. Estas cargas de datos podemos hacerlas bien desde nuestro programa " |
El resultado: 128KB de memoria a nuestro alcance, tanto para cargar múltiples datos gráficos o de mapeado sobre ellos como para llenarlos internamente desde nuestro programa. | El resultado: 128KB de memoria a nuestro alcance, tanto para cargar múltiples datos gráficos o de mapeado sobre ellos como para llenarlos internamente desde nuestro programa. | ||
Línea 494: | Línea 447: | ||
* [[http:// | * [[http:// | ||
+ | \\ | ||
+ | **[ [[.: |