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 Mi Piace

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 Mi Piace

Here’s the part @AndyCadley mentioned clipped out.

3 Mi Piace

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.

Grazie mille a tutti per le risposte. È evidente che questa è una community davvero attiva e disponibile :slight_smile:

È un peccato che Amstrad non abbia fornito una versione aggiornata del BASIC al momento del lancio della serie “Plus”, in modo da sfruttare le migliorie dell’ASIC, perché avrebbe reso le cose molto più semplici. Non sapevo dell’esistenza di B-Asic, ma in ogni caso non posso usarlo dato che lo spazio di memoria è già occupato da alcuni dati e dalla routine della musica sotto interrupt. Inoltre, voglio attenermi il più possibile al BASIC 1.1 perché vorrei compilare il codice con ABASC. Questo significa che questa volta non userò la tavolozza estesa per la grafica, ma solo per gli sprite; va comunque benissimo così, dato che posso realizzare effetti come il colour cycling e le dissolvenze.

Grazie ancora per l’aiuto!

2 Mi Piace

C’è differenza tra il comando BASIC «DI» e il comando assembler «DI». Mentre il primo disabilita solo le routine registrate tramite «AFTER» o «EVERY», il secondo disabiliterà tutte le routine gestite da interrupt, in particolare anche il controllo della tastiera (polling) e la riproduzione musicale. Tuttavia, finché le routine del firmware sono in esecuzione, riprogrammeranno i colori 50 volte al secondo per consentire i colori lampeggianti (in BASIC, ad esempio, con BORDER 1,0). Ciò significa che se modifichi qualcosa nell’hardware, verrà sovrascritto nel frame successivo.

Un’altra cosa: se dissolvi la pagina di memoria simulata insieme ai controlli dell’ASIC, allo stesso tempo la pagina di memoria regolare viene dissolta. Devi assicurarti che il BASIC non utilizzi questo grande blocco di memoria (con l’istruzione MEMORY), altrimenti succederanno cose spiacevoli (ad es. il BASIC cercherà di interpretare ed eseguire i controlli dell’ASIC come un programma BASIC). Per riprogrammare l’ASIC in modo sicuro, credo che una piccola routine in assembler potrebbe essere d’aiuto.

Ho scoperto che il firmware contiene già una routine per disabilitare il cambio automatico dei colori. Non fa però parte della jump table, quindi è necessaria una piccola routine in assembler per richiamarla. Questa disabiliterà la gestione dei colori del firmware e imposterà tutti i pennelli (pen) su blu scuro. Dopodiché dovrai modificare direttamente i colori con il GateArray o l’ASIC. È necessario utilizzare i codici colore hardware dispari invece dei comodi numeri ternari usati dal BASIC e dal firmware. Ecco un piccolo programma che fa proprio questo. Per verificare che funzioni, imposta ad esempio BORDER 1,0 prima dell’esecuzione. Quando il programma termina, il lampeggio si interrompe.

MODE 2 : BORDER 0,1

10 MEMORY &9FFF       ' Protegge la memoria per la piccola routine assembler.
20 POKE &A000,&CF     ' RST &10    ;; LO JUMP
30 POKE &A001,&55     '   DEFB &55 ;; byte di indirizzo basso
40 POKE &A002,&0D+&80 '   DEFB &8D ;; byte di indirizzo alto + abilita BASIC ROM
50 CALL &A000         ' Chiama la routine assembler preparata.
60 OUT &7F00,1        ' GateArray: SELEZIONA PEN 1
70 OUT &7F00,&4A      ' GateArray: IMPOSTA INK su giallo brillante (brightYellow)

È necessario modificare la riga 30 in base al sistema utilizzato. I valori sono i seguenti:

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

Potrebbe essere possibile ottenere lo stesso risultato con un altro approccio, ad esempio semplicemente disabilitando la routine dell’evento invece di rimuoverla.


Dividere le risposte è consentito solo fino a un massimo di tre risposte consecutive. Quindi devo unire quanto sopra con la mia quarta risposta qui sotto.

Ero curioso di capire come funzionasse il piccolo programma di AA114. Dopo averlo disassemblato e analizzato, non ne sono del tutto convinto: funziona, ma configura un’altra routine di interrupt per combattere contro quella del firmware (azzerando continuamente un contatore). Penso che disabilitare la routine del firmware sia la soluzione migliore.

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 ;; Imposta il puntatore ai dati dell'evento.
    LD BC,PRIORITY*256 + ROM_CONFIGURATION ;; 01 FF 81 ;;
    LD DE,RESET_BLINK_COUNTER              ;; 11 12 80 ;; Imposta il puntatore alla routine dell'evento.
    JP KL_NEW_FRAME_FLY                    ;; C3 D7 BC ;; Installa la nuova routine dell'evento.

disable_color_change_suppression:          ;;          ;;
    LD HL,event_block                      ;; 21 17 80 ;; Imposta il puntatore ai dati dell'evento.
    JP KL_DELETE_FRAME_FLY                 ;; C3 DD BC ;; Disinstalla la routine dell'evento.

reset_blink_counter:                       ;;          ;;
    XOR A                                  ;; AF       ;;
    LD (BLINK_COUNTER),A                   ;; 32 F8 B7 ;; Azzera il contatore di lampeggio.
    RET                                    ;; C9       ;;

event_block:                               ;;          ;; Memorizza qui i dati dell'evento.
    ;; DEFW next_event_block               ;;          ;;
    ;; DEFB counter                        ;;          ;;
    ;; DEFB priority                       ;;          ;;
    ;; DEFW event_routine                  ;;          ;;
    ;; DEFB rom_configuration              ;;          ;;

Ok, questo spiega perché la “ricostruzione del colore” rimane nonostante l’uso del comando di base “DI”. Grazie per il chiarimento.

Quando ho bisogno di accedere ai registri ASIC (in pratica, per il posizionamento degli sprite e/o la palette degli sprite), uso la seguente struttura: DI:OUT &7F00,&B8:[accesso ai registri ASIC]:OUT &7F00,&A0:EI. In base al tuo messaggio precedente, questo significa che «DI» ed «EI» non sono necessari?

I semplici DI/EI di BASIC non servono a nulla in questo caso: si limitano a impedire l’esecuzione delle routine AFTER ed EVERY.

Sì! Funziona! Grazie mille!

Un saluto,

David

1 Mi Piace

Oh fantastico, l’evidenziazione della sintassi funziona a meraviglia, anche se è un po’ incompleta!

1 Mi Piace