Using expanded CPC Plus palette from BASIC

Hi all!

As I’m a new user of this forum and this is my first post, let me introduce myself: My name is David and I’m from Barcelona, Spain. Although I’ve never owned an Amstrad computer (my first computer was a Commodore 64), I experienced the 8 and 16-bit computer boom of the 80s and early 90s and some of my friends had a CPC464 (and one of them a CPC6128).

Recently I’ve become interested in retro-programming in BASIC for vintage 8 bit and 16 bit systems, both for learning and for fun. Some months ago I wrote a simple game called “Mega Chase”, and I’ve been writing versions for different computers such as the Commodore 64, the MSX2+, the Amiga (AGA), the Atari ST/E, the Commodore VIC-20, the Commodore Plus/4, or the Mega65 (not a “vintage” system strictly speaking, though). Now I’m developing a version for the Amstrad CPC “plus” series, to take advantage of the expanded colour palette and the hardware sprites.

I’m facing a problem, though, when trying to use the 4096 colour palette for the main screen (the specific sprite palette works perfectly). When, for instance, I want to change the border colour (address &6420 and &6421 of the ASIC), the original colour is restored immediately, in the next frame. The results are the same even if I use de “DI” instruction to disable interrupts. It does the same both on WinApe (Windows) and in Amspirit (MacOS).

Is there a way to use the expanded palette from BASIC without the “immediate restoration” effect?

Best,

David (shad0wfax)

2 Me gusta

I’d be interested to see if you can get that working. Could make for some very interesting projects.

Oh, our first new user! Welcome, hope you find some answers here :slightly_smiling_face:

We have this kind of issue in ASM when using hardware access (using Hardware registers and colors), the firmware just reset it on each new frame… To correct this, we disable firmware and take full control of the CPC.
So I am not sure that you can keep a CPC+ color inside a BASIC program because firmware is necessary for BASIC.

If you use FRAME (Basic 1.1) did you try to change it just after (to set it at beginning of each frame)?

The problem is the CPC firmware sets up and interrupt routine that changes colours every frame (this is how flashing colours work). You basically have two options:

  1. The easy way: Use B-Asic extensions which handle all this for you, as well as giving you a bunch of other useful RSX commands

  2. The marginally more difficult way: In AA114, in the Tech tips page, there is a short BASIC listing which handles removing the interrupt handlers for you. Don’t be tempted to follow the advice a few issues earlier, in the article about using the Plus features because it just does it in a nasty ha KY way that slows down keyboard responsiveness and probably messes up all the timers etc.

2 Me gusta

Here’s the part @AndyCadley mentioned clipped out.

3 Me gusta

That was a nice letter Rob sent in.

Yeah. Although he is incorrect about the need to re-lock the ASIC after changing colours etc, that is completely unnecessary.

Muchas gracias a todos por vuestras respuestas. Está claro que esta es una comunidad muy activa y servicial :slight_smile:

Es una pena que Amstrad no proporcionara una versión actualizada del Basic al lanzar la serie «Plus» para aprovechar las mejoras del ASIC, ya que habría facilitado mucho las cosas. No sabía de la existencia de B-Asic, pero de todos modos no puedo usarlo porque el espacio de memoria ya está ocupado por algunos datos y la rutina de música por interrupción. Además, quiero ceñirme al Basic 1.1 en la medida de lo posible, ya que quiero compilar el código con ABASC. Esto significa que esta vez no usaré la paleta extendida para los gráficos, sino solo para los sprites, pero aun así está bastante bien porque puedo hacer efectos como ciclos de color y degradados.

¡Gracias de nuevo por vuestra ayuda!

2 Me gusta

Existe una diferencia entre el comando de BASIC «DI» y el comando de ensamblador «DI». Mientras que el primero solo deshabilita las rutinas registradas a través de «AFTER» o «EVERY», el segundo deshabilitará todas las rutinas dirigidas por interrupciones, especialmente el sondeo del teclado y la reproducción de música. Pero mientras las rutinas del firmware estén ejecutándose, reprogramarán los colores 50 veces por segundo para permitir colores parpadeantes (en BASIC, por ejemplo, con BORDER 1,0). Esto significa que si cambias algo en el hardware, se sobrescribirá en el siguiente fotograma.

Otra cosa: si haces la transición para mostrar la página de memoria simulada junto con los controles del ASIC, al mismo tiempo la página de memoria habitual se oculta. Debes asegurarte de que BASIC no use este gran bloque de memoria (con la instrucción MEMORY); de lo contrario, ocurrirán problemas graves (por ejemplo, BASIC intentará interpretar y ejecutar los controles del ASIC como si fueran un programa en BASIC). Para reprogramar el ASIC de forma segura, me parece que una pequeña rutina en ensamblador podría ser útil.

Descubrí que el firmware ya contiene una rutina para desactivar los cambios de color automáticos. Sin embargo, no forma parte de la tabla de saltos, por lo que se requiere una pequeña rutina en ensamblador para llamarla. Esta desactivará la gestión de color del firmware y configurará todos los plumas (pens) en azul oscuro. Después, tendrás que cambiar los colores directamente con el GateArray o el ASIC. Debes usar los códigos de color de hardware impares en lugar de los amigables números ternarios que usan BASIC y el firmware. Aquí hay un pequeño programa que hace esto. Para comprobar que funciona, establece por ejemplo BORDER 1,0 antes. Cuando el programa termina, el parpadeo se detiene.

MODE 2 : BORDER 0,1

10 MEMORY &9FFF       ' Proteger la memoria para la pequeña rutina en ensamblador.
20 POKE &A000,&CF     ' RST &10    ;; LO JUMP
30 POKE &A001,&55     '   DEFB &55 ;; byte de dirección baja
40 POKE &A002,&0D+&80 '   DEFB &8D ;; byte de dirección alta + habilitar BASIC ROM
50 CALL &A000         ' Llamar a la rutina en ensamblador preparada.
60 OUT &7F00,1        ' GateArray: SELECCIONAR PLUMA 1
70 OUT &7F00,&4A      ' GateArray: ESTABLECER TINTA brightYellow

Debes modificar la línea 30 según el sistema. Los valores son los siguientes:

  • 464 - &4F
  • 664 - &51
  • 6128 y Plus - &55

Es posible que se pueda lograr lo mismo con otro enfoque, por ejemplo, simplemente desactivando la rutina de eventos en lugar de eliminarla.


Solo se permite dividir respuestas hasta tres veces consecutivas. Así que tengo que fusionar lo anterior con mi cuarta respuesta a continuación.

Me interesaba saber cómo funciona el pequeño programa de AA114. Después de desensamblarlo y entenderlo, no estoy muy convencido: funcionará, pero configura otra rutina de interrupción para luchar contra la rutina del firmware (reiniciando constantemente un contador). Creo que desactivar la rutina del firmware es la mejor opción.

NOLIST
ORG #8000

KL_NEW_FRAME_FLY    EQU #BCD7
KL_DELETE_FRAME_FLY EQU #BCDD
PRIORITY            EQU #81
ROM_CONFIGURATION   EQU #FF
BLINK_COUNTER       EQU #B7F8

enable_color_change_suppression:           ;;          ;;
    LD HL,event_block                      ;; 21 17 80 ;; Establecer puntero a los datos del evento.
    LD BC,PRIORITY*256 + ROM_CONFIGURATION ;; 01 FF 81 ;;
    LD DE,RESET_BLINK_COUNTER              ;; 11 12 80 ;; Establecer puntero a la rutina del evento.
    JP KL_NEW_FRAME_FLY                    ;; C3 D7 BC ;; Instalar nueva rutina de evento.

disable_color_change_suppression:          ;;          ;;
    LD HL,event_block                      ;; 21 17 80 ;; Establecer puntero a los datos del evento.
    JP KL_DELETE_FRAME_FLY                 ;; C3 DD BC ;; Desinstalar rutina de evento.

reset_blink_counter:                       ;;          ;;
    XOR A                                  ;; AF       ;;
    LD (BLINK_COUNTER),A                   ;; 32 F8 B7 ;; Reiniciar el contador de parpadeo.
    RET                                    ;; C9       ;;

event_block:                               ;;          ;; Almacenar datos del evento aquí.
    ;; DEFW next_event_block               ;;          ;;
    ;; DEFB counter                        ;;          ;;
    ;; DEFB priority                       ;;          ;;
    ;; DEFW event_routine                  ;;          ;;
    ;; DEFB rom_configuration              ;;          ;;

Vale, esto explica por qué la «restauración del color» se mantiene a pesar de usar el comando básico de «DI». Gracias por la aclaración.

Cuando necesito acceder a los registros del ASIC (básicamente, para el posicionamiento de sprites y/o la paleta de sprites), uso la siguiente estructura: DI:OUT &7F00,&B8:[accediendo a los registros del ASIC]:OUT &7F00,&A0:EI. Según tu mensaje anterior, ¿significa eso que «DI» y «EI» no son necesarios?

BASIC DI/EI no hará nada allí, solo evitan que se ejecuten las rutinas AFTER y EVERY.

¡Sí! ¡Funciona! ¡Muchas gracias!

Saludos,

David

1 me gusta

¡Genial, la resaltación de sintaxis funciona de maravilla, aunque un poco incompleta!

1 me gusta