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)

3 « J'aime »

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 « J'aime »

Here’s the part @AndyCadley mentioned clipped out.

3 « J'aime »

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.

Merci beaucoup pour toutes vos réponses. C’est clair que c’est une communauté très active et d’une grande aide :slight_smile:

C’est dommage qu’Amstrad n’ait pas fourni une version mise à jour du Basic lors de la sortie de la gamme « Plus », afin de tirer parti des améliorations de l’ASIC, car cela aurait rendu les choses beaucoup plus simples. Je ne connaissais pas l’existence de B-Asic, mais de toute façon je ne peux pas l’utiliser car l’espace mémoire est déjà occupé par des données et la routine musicale sous interruption. De plus, je veux m’en tenir au Basic 1.1 autant que possible, étant donné que je souhaite compiler le code avec ABASC. Cela signifie que cette fois-ci, je n’utiliserai pas la palette étendue pour les graphismes, mais uniquement pour les sprites. Cela reste quand même très bien car je peux faire des effets comme des fondus ou du défilement de couleurs (colour cycling).

Encore merci pour votre aide !

2 « J'aime »

Il y a une différence entre la commande BASIC « DI » et la commande assembleur « DI ». Alors que la première désactive uniquement les routines enregistrées via « AFTER » ou « EVERY », la seconde désactivera toutes les routines régies par les interruptions, en particulier le balayage du clavier et la lecture de musique. Tant que les routines du firmware s’exécutent, elles reprogrammeront les couleurs 50 fois par seconde pour permettre le clignotement des couleurs (en BASIC, par exemple avec BORDER 1,0). Cela signifie que si vous modifiez quelque chose au niveau du matériel, cela sera écrasé dès l’image suivante.

Autre chose : Si vous faites apparaître la page de mémoire simulée avec les commandes ASIC, la page de mémoire habituelle disparaît simultanément. Vous devez vous assurer que le BASIC n’utilise pas ce grand bloc de mémoire (avec l’instruction MEMORY), sinon des problèmes surviendront (par exemple, le BASIC essaiera d’interpréter et d’exécuter les commandes ASIC comme un programme BASIC). Pour reprogrammer l’ASIC en toute sécurité, je pense qu’une petite routine en assembleur pourrait être utile.

J’ai découvert que le firmware contient déjà une routine pour désactiver les changements automatiques de couleur. Cependant, elle ne fait pas partie de la table de saut, donc une petite routine en assembleur est nécessaire pour l’appeler. Elle désactivera la gestion des couleurs par le firmware et réglera tous les stylo-couleurs sur bleu foncé. Ensuite, vous devrez modifier directement les couleurs via le GateArray ou l’ASIC. Il faut utiliser les codes couleur matériels impairs au lieu des jolies valeurs ternaires utilisées par le BASIC et le firmware. Voici un petit programme qui réalise cela. Pour vérifier que cela fonctionne, définissez par exemple BORDER 1,0 au préalable. Lorsque le programme se termine, le clignotement s’arrête.

MODE 2 : BORDER 0,1

10 MEMORY &9FFF       ' Protéger la mémoire pour la petite routine assembleur.
20 POKE &A000,&CF     ' RST &10    ;; LO JUMP
30 POKE &A001,&55     '   DEFB &55 ;; octet de poids faible de l'adresse
40 POKE &A002,&0D+&80 '   DEFB &8D ;; octet de poids fort de l'adresse + activer le ROM BASIC
50 CALL &A000         ' Appeler la routine assembleur préparée.
60 OUT &7F00,1        ' GateArray: SELECT PEN 1
70 OUT &7F00,&4A      ' GateArray: SET INK brightYellow

Vous devez modifier la ligne 30 en fonction de votre système. Les valeurs sont les suivantes :

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

Il est peut-être possible d’obtenir le même résultat avec une autre approche, par exemple en désactivant simplement la routine d’événement au lieu de la supprimer.


Le découpage des réponses est limité à trois réponses consécutives. Je dois donc fusionner ce qui précède avec ma quatrième réponse ci-dessous.

Je voulais comprendre comment fonctionnait le petit programme de l’AA114. Après l’avoir désassemblé et analysé, je ne suis pas vraiment convaincu : il fonctionne, mais il installe une autre routine d’interruption qui entre en conflit avec la routine du firmware (en réinitialisant constamment un compteur). Je pense que désactiver la routine du firmware reste la meilleure solution.

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 ;; Définir le pointeur vers les données d'événement.
    LD BC,PRIORITY*256 + ROM_CONFIGURATION ;; 01 FF 81 ;;
    LD DE,RESET_BLINK_COUNTER              ;; 11 12 80 ;; Définir le pointeur vers la routine d'événement.
    JP KL_NEW_FRAME_FLY                    ;; C3 D7 BC ;; Installer la nouvelle routine d'événement.

disable_color_change_suppression:          ;;          ;;
    LD HL,event_block                      ;; 21 17 80 ;; Définir le pointeur vers les données d'événement.
    JP KL_DELETE_FRAME_FLY                 ;; C3 DD BC ;; Désinstaller la routine d'événement.

reset_blink_counter:                       ;;          ;;
    XOR A                                  ;; AF       ;;
    LD (BLINK_COUNTER),A                   ;; 32 F8 B7 ;; Réinitialiser le compteur de clignotement.
    RET                                    ;; C9       ;;

event_block:                               ;;          ;; Stocker les données d'événement ici.
    ;; DEFW next_event_block               ;;          ;;
    ;; DEFB counter                        ;;          ;;
    ;; DEFB priority                       ;;          ;;
    ;; DEFW event_routine                  ;;          ;;
    ;; DEFB rom_configuration              ;;          ;;

D’accord, cela explique pourquoi la « restauration des couleurs » persiste malgré l’utilisation de la commande « DI » de base. Merci pour ces clarifications.

Lorsque j’ai besoin d’accéder aux registres de l’ASIC (en gros, pour le positionnement des sprites et/ou la palette des sprites), j’utilise la structure suivante : DI:OUT &7F00,&B8:[accès aux registres de l’ASIC]:OUT &7F00,&A0:EI. D’après votre message précédent, cela signifie-t-il que « DI » et « EI » ne sont pas nécessaires ?

Les instructions BASIC DI/EI ne feront rien là, elles empêchent seulement les routines AFTER et EVERY d’être exécutées.

Super ! Ça marche ! Merci beaucoup !

À bientôt,

David

1 « J'aime »

Oh génial, la coloration syntaxique fonctionne à merveille, même si elle est un peu incomplète !

1 « J'aime »