Images en quadrichrome sur vg5000

Cette catégorie traite de développements récents pour nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Répondre
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

Bonjour,

Après avoir parcouru le forum et lu les livres concernant l'ef9345, j'ai essayé de faire un synthèse de tout ce que j'ai pu trouver.
Donc ci-dessous, 2 sources permettent d'afficher des images en quadrichrome.

- D'abord un programme en python 3 (quadri.py) qui prend en entrée quelques paramètres: une image, éventuellement un matrice de dithering, des dimensions, une palette. ce programme va générer de l'assembleur à inclure dans le 2eme programme. L'image doit être à des dimensions compatibles avec le mode quadrichrome du vg5000. Il faut également prendre en compte que ce mode a des pixels plus larges que hautes pour le redimensionnement. Enfin, la librairie PIL doit être installée pour qu'il fonctionne.
- Le deuxième programme en assembleur qui permet d'afficher le résultat du premier.

Concernant le mode quadrichrome, les jeux Q6 et Q7 sont utilisés ce qui fait un maximum de 200 caractères redéfinis.

Par exemple, je souhaite afficher cette image sur mon vg5000:
Image

J'utilise le programme python dont voici les arguments:

I need the following arguments:
* a picture filename
* a bayer matrix size in (1 2 3 4 8), 0 for none
* image width
* image height
* a 8 binary coded palette, 1 for the wanted color in
(white cyan violet blue yellow green red black) order
with a 4 colors restriction
ex: 01011010 = cyan blue yellow red

Pour mon image b.png de 8*10 pixels, ça donne sans dithering (0 pour la matrice) et avec les couleurs blanc, jaune, rouge, noir :
python quadri.py b.png 0 8 10 10001011

J'obtiens :
- Le code asm à inclure en bas de mon 2eme programme assembleur d'affichage (je copie-colle à partir de ;Converting b.png).
- Une image quadri_ordered.png qui affiche le résultat du dimensionnement/dithering/palette tel qu'il apparaitra sur le vg5000.

Je change quelques paramètres dans le prog asm résultant pour que l'image s'affiche correctement:
- ligne 98, dans "de", le nombre de tampons qui est indiqué en bas du code généré. Pour une image de 8*10, ca fait 1 tampon.
- ligne 108, dans "e", je précise la palette utilisée qui est également indiqué en bas du code généré. Ici $8b
- ligne 112, dans "de", les dimensions de l'image au format quadrichrome, toujours indiqué en bas du code généré. Pour une image de 8*10, 2*4 sur 1*10, c'est à dire $0201

C'est du code z80asm. Le seul assembleur que je connaisse pour le moment. La compilation se fait avec cette commande:
z80asm -b b.asm

Je charge le bin dans dcvg5k

Un "call 20480"

Et voila le résultat:
Image

Ces programmes m'ont permis de mettre en application ce que j'avais lu concernant le mode graphique du vg5000. Il y a peut-être des bugs et des améliorations à y apporter mais je me suis bien amusé. Franchement c'est aussi fun que de programmer une nvidia dernier cri.


Quelques exemples:

Image

Image


Image

Image


Les 2 programmes :

Code : Tout sélectionner

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  quadri.py
#
#  Copyright 2020 rodoc <rodoc@linux.home>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#

from PIL import Image
import os
import copy

weight = (8, 4, 2, 1)
data_per_line = 9

BAYER_1 = ((170,),)
BAYER_2 = ((0, 170), (255, 85))
BAYER_3 = ((0, 223, 95), (191, 159, 63), (127, 31, 255))
BAYER_4 = ((0, 136, 34, 170), (204, 68, 238, 102), (51, 187, 17, 153),
           (255, 119, 221, 85))

BAYER_8 = ((0, 194, 48, 242, 12, 206, 60,
            255), (129, 64, 178, 113, 141, 76, 190,
                   125), (32, 226, 16, 210, 44, 238, 28,
                          222), (161, 97, 145, 80, 174, 109, 157, 93),
           (8, 202, 56, 250, 4, 198, 52,
            246), (137, 72, 186, 121, 133, 68, 182,
                   117), (40, 234, 24, 218, 36, 230, 20,
                          214), (170, 105, 153, 89, 165, 101, 149, 85))


VG5K_COLORS = ((255,255,255), (0,255,255), (255,0,255), (0, 0, 255), 
				(255,255,0), (0,255,0), (255,0,0), (0,0,0))



def threshold_bayer_matrix(bayer_matrix, strength):
    mat = []
    for i in range(0, len(bayer_matrix)):
        row = []
        for j in range(0, len(bayer_matrix[i])):
            row.append(int(bayer_matrix[i][j] * strength))
        mat.append(tuple(row))
    return tuple(mat)



def resize_vg_sprite(im, x_size, y_size):
    im.thumbnail(
        (x_arg, y_arg))


def find_closest_color(c, palette):
    diff = 100000
    closest = 0
    for i in range(0, len(palette)-1, 3):
        d = abs(c[0] - palette[i]) + abs(c[1] - palette[i+1]) + abs(c[2] - palette[i+2])
        if d < diff:
            diff = d
            closest = i
    return closest//3



def ordered_dither(im, bayer, palette):
    # ~ palettedata = [
            # ~ 0, 0, 0,  
            # ~ 255, 0, 0,  
            # ~ 0, 0, 255,  
            # ~ 255, 255, 0];
    palette_data = []
    for i in range(0,4):
        for j in range(0,3):
            color = palette[i]
            palette_data.append(color[j])
    
    dithered_color = [0, 0, 0]
    img = Image.new('P', (im.width, im.height))
    img.putpalette(palette_data * 64)
    pixels = im.load()
    for x in range(im.width):
        for y in range(im.height):
            c = pixels[x, y]
            if bayer is not None:
                map_value = bayer[x % len(bayer)][y % len(bayer)]
                dithered_color[0]  = (c[0] + map_value)//2
                dithered_color[1]  = (c[1] + map_value)//2
                dithered_color[2]  = (c[2] + map_value)//2 
                index = find_closest_color(dithered_color, palette_data)
            else:
                # pas de dithering
                index = find_closest_color(c, palette_data)
            img.putpixel((x,y), index)
    return img


def get_car_string(car):
    pixels = car.load()
    data = ""
    for y in range(0, 10):
        w1 = 0
        w2 = 0
        sl = ""
        for x in range(0, 4):
            c = pixels[x, y]
            b = '{0:02b}'.format(c)
            b = b[::-1] 
            sl = sl + b
        line = hex(int(sl, 2))
        line = "$" + line[2:]
        data += line + ","
    return data[0:len(data)-1]
    
    
def get_car_list(car):
    pixels = car.load()
    data = []
    for y in range(0, 10):
        w1 = 0
        w2 = 0
        sl = ""
        for x in range(0, 4):
            c = pixels[x, y]
            b = '{0:02b}'.format(c)
            # ~ print(b)
            # b = b[::-1]
            # sl = sl + b
            sl = b + sl
        # ~ print(sl)
        # ~ exit()
        line = hex(int(sl, 2))
        line = "$" + line[2:]
        data.append(line)
    return data


def get_palette_from_bin(bin_oct):
    palette = []
    for i in range(len(bin_oct)-1, -1, -1):
        if bin_oct[i] == '1':
            palette.append(VG5K_COLORS[i])
    return palette


def main(args):
    if len(sys.argv) <= 5:
        print("")
        print("I need the following arguments:")
        print("  * a picture filename")
        print("  * a bayer matrix size in (1 2 3 4 8), 0 for none")
        print("  * image width")
        print("  * image height")
        print("  * a 8 binary coded palette, 1 for the wanted color in")
        print("    (white cyan violet blue yellow green red black) order")
        print("    with a 4 colors restriction")
        print("    ex: 01011010 = cyan blue yellow red")
        print("")
        exit()

    switch_bayer = {'0' : None, '1': BAYER_1, '2': BAYER_2, '3': BAYER_3, '4': BAYER_4, '8': BAYER_8}
    
    
    bayer_matrix = switch_bayer[sys.argv[2]]
    
    # ~ if len(sys.argv) == 4:
        # ~ bayer_matrix = threshold_bayer_matrix(bayer_matrix, float(sys.argv[3]))
        
    x_arg = int(sys.argv[3])
    y_arg = int(sys.argv[4])
    
    if x_arg % 4 != 0:
        print("x width must be a 4 divisor")
        exit()
        
    if y_arg % 10 != 0:
        print("y height must be a 10 divisor")
        exit()


    color_bits = sys.argv[5]
    palette = get_palette_from_bin(color_bits)


    print(";Converting " + sys.argv[1])
    im = Image.open(sys.argv[1])
    im = im.convert("RGB")
    
    print(";resizing to ", x_arg, y_arg)
    im = im.resize((x_arg, y_arg))
    im.save("quadri_resized.png")

    print(";dithering with", bayer_matrix)
    print(";using palette", palette)
    im = ordered_dither(im, bayer_matrix, palette)
    
    
    
    im.save("quadri_ordered.png")

    width, height = im.size
    x_step_count = int(width / 4)
    y_step_count = int(height / 10)
    count = 0
    dict_car = {}
    
    count_bloc = 6
    count_tampon = 0
    count_octet = 0
    
    list_cars = []
    for y in range(0, y_step_count):
        for x in range(0, x_step_count):
            crop_tuple = (x * 4, y * 10, (x + 1) * 4, (y + 1) * 10)
            car = im.crop(crop_tuple)
            data = get_car_list(car)
            list_cars.append(data)
    
    print (";cars count:", len(list_cars))
    
    print()
    print()
    print(".sprite_def")
    
    for i in range(0, len(list_cars), 4):
        try:
            car_1 = list_cars[i]
        except IndexError as e:
            car_1 = ["$0","$0","$0","$0","$0","$0","$0","$0","$0","$0"]
        
        try:    
            car_2 = list_cars[i+1]
        except IndexError as e:
            car_2 = ["$0","$0","$0","$0","$0","$0","$0","$0","$0","$0"]
        
        try:
            car_3 = list_cars[i+2]
        except IndexError as e:
            car_3 = ["$0","$0","$0","$0","$0","$0","$0","$0","$0","$0"]
        
        try:
            car_4 = list_cars[i+3]
        except IndexError as e:
            car_4 = ["$0","$0","$0","$0","$0","$0","$0","$0","$0","$0"]


        print("; Bloc", count_bloc, "  -  Tampon ", count_tampon)
        print("; car 1 : ", car_1)
        print("; car 2 : ", car_2)
        print("; car 3 : ", car_3)
        print("; car 4 : ", car_4)
        
        # calcul R4 et R5 en fct Bloc/Tampon/Octet
        # R4 bit 3 Bloc (1 car 6=110 ou 7=111)  - Tampon sur 5 bits
        # R5 bit 0 et 1 Bloc à l'envers (01 ou 11) - N° octet sur 6 bits
        R4_bits = "001" + '{0:05b}'.format(count_tampon)
        R5_bits = ""
        if count_bloc == 6:
            R5_bits = "01" + '{0:06b}'.format(count_octet)
        elif count_bloc == 7:
            R5_bits = "11" + '{0:06b}'.format(count_octet)
        else:
            # ca depasse
            print("; Blocs limited to 7")
            exit()
        
        R4_hex = "$" + hex(int(R4_bits, 2))[2:]
        R5_hex = "$" + hex(int(R5_bits, 2))[2:]
        print ("; R4 (write) = ", R4_bits, "=", R4_hex)
        print ("; R5 (write) = ", R5_bits, "=", R5_hex)
        print ("    db ", R4_hex, ",", R5_hex)
        
        slice = 0
        for j in range(0, 10):
            print("    db ", car_1[j], ",", car_2[j], ",", car_3[j], ",", car_4[j])
            slice +=4
        
        print(";;;;;;;")
        
        count_tampon += 1
        if count_tampon == 1:
            count_tampon += 7
        if count_tampon == 32:
            count_tampon = 0
            count_bloc += 1

    # Calcul de R1 et R2 pour l'utilisation des sprites
    print()
    print()
    print(".sprite_use")
    count_bloc = 6
    count_tampon = 0
    count_octet = 0
    count_col = 0
    count_lin = 0
    total_tampon = 0
    for i in range(0, len(list_cars), 4):
        for j in range (0, 4):
            
            # calcul coordonnées
            if count_col == x_step_count:
                count_col = 0
                count_lin += 1
                if count_lin == y_step_count:
                    break
            
            
            # Calcul de R1 et R2 en fonction du Bloc/Tampon/Octet
            # R1 numero du car avec 0,1,2,3 pour Tampon 1 et 32,127 pour tampons suivants
            # R2 11 (quadri) - Bloc 6  ou 7 (avec inv b1 et b0) 101 ou 111 - 0 - HR 0 - incrust 1 
            R1_hex = "$" + hex(count_octet)[2:]
            
            R2_bits = ""
            if count_bloc == 6:
                R2_bits = "11101001"
            elif count_bloc == 7:
                R2_bits = "11111001"
            else:
                # ca depasse
                print("; Blocs limited to 7")
                exit()
            
            R2_hex = "$" + hex(int(R2_bits, 2))[2:]
            print(";;;;;;;")
            print("; Bloc", count_bloc, " - Tampon ", count_tampon, " - Octet ", count_octet, " - (", count_col, ",", count_lin,")")
            print ("    db ", R1_hex, ",", R2_hex)
            count_octet += 1
            count_col += 1
        
        count_tampon += 1
        total_tampon += 1
        if count_tampon == 1:
            count_tampon += 7
            count_octet += 28
        if count_tampon == 32:
            count_tampon = 0
            count_bloc += 1
            
    print (";;;;;;;;;;;")
    print ("; resolution quadrichromesque", str(x_step_count) + "*4", str(y_step_count) + "*10", 
        "=", "$" + hex(x_step_count)[2:].zfill(2) + hex(y_step_count)[2:].zfill(2))
    print ("; tampons", total_tampon);
    print ("; palette", color_bits, "=",  "$" + hex(int(color_bits, 2))[2:]);

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))



Code : Tout sélectionner

    ; Organisation memoire privee ef9345
    ;===================================
    ;|          EF9345                     VRAM  8ko                                            |
    ;|-----------------------------------------|   ~~ |-----------------------------------------|
    ;|         bloc 1   1024octets             |   ~~ |          bloc 8 1024octets              |
    ;|-----------------------------------------|   ~~ |-----------------------------------------|
    ;|TAMPON1|24octets| .....|TAMPON25|TAMPON26|   ~~ |TAMPON1|24octets| .....|TAMPON25|TAMPON26|
    ;|$0000                               $0400|   ~~ |                                    $2000|
    
    
    ;|             détail d'un BLOC de 1 Ko  (1024 octets)                    |
    ;|------------------------------------------------------------------------|
    ;| TAMPON1  | TAMPON2  | TAMPON3  | TAMPON4  | ~~ | TAMPON25  | TAMPON26  |
    ;| Y=0      | Y=1      | Y=8      | Y=9      | ~~ | Y=30      | Y=31      |
    ;| 40 octets| 24 octets| 40 octets| 40 octets| ~~ |  40 octets|  40 octets|

    
    ; Tampon : 1 2 3 4 5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
    ;      Y : 0 1 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

    ; Z=BLOC Y=TAMPON X=OCTET dans le TAMPON
    
    ; exemple : octet 10 stocke dans le 3eme tampon du 2eme bloc :
    ; Z=1 Y=8 X=09


    ; Les registres utilises pour acceder a la memoire privee:
    ; R4 et R5 : pointeur auxiliaires (X  Y  Z )
    ; R6 et R7 : pointeur principal   (X' Y' Z')
    
    ; X  x5 x4 x3 x2 x1 x0      X'  x'5 x'4 x'3 x'2 x'1 x'0
    ; Y     y4 y3 y2 y1 y0      X'      y'4 y'3 y'2 y'1 y'0
    ; Z        z3 z2 z1 z0      Z'          z'3 z'2 z'1 z'0
    
    ; R4  -    -    z'2  y'4  y'3  y'2  y'1  y'0
    ; R5  z'0  z'1  x'5  x'4  x'3  x'2  x'1  x'0
    ; R6  z3   z'3   z2   y4   y3   y2   y1   y0
    ; R7  z0    z1   x5   x4   x3   x2   x1   x0


    ; Ecriture memoire privee ef9345
    ; ==============================
    ; R0 = OCT Write R4/R5 00110100 = $34 = 52
    ; R1 = Z = Valeur octet a ecrire = $03
    ; R4 = Y = $09 -> tampon 9 = 3eme tampon (si num tampon commence a 0)
    ; R5 = X = $C2 -> 3eme car du tampon (11 000010) = bloc 3 octet 2(=3)
    
    
    ; Sinon c'est trop facile
    ; =======================
    ; Un tampon contient 4 car redefini (normal 40 octets)
    ; Le tampon suivant le tampon 0 est le 8
    ; Les tranches n de ces 4 cars sont successives:
    ; Tranche 1 : OCT 1 2 3 4
    ; Tranche 2 : OCT 1 2 3 4
    ; ...
    ; Tranche 10: OCT 1 2 3 4
    
    
    ; Redef car
    ; =========
    ; R1 avec les 10 tranches en inc R5 de 4


    ; Affichage
    ; =========
    ; R2 (B7 B6 B5 B4) : numero jeu - 	B7 = 1 car non standard
    ;					B6 = 0 monochrome
    ;					B5, B4 = jeu a utiliser G'0(00/1), G'10(10), G'11(11)

    ; R1 Numero car dans tampon Y :
    ;					T0 :  0    1    2    3 
    ;					T1 : 32   33   34   35
    ;					T2 : 36   37   38   39
    ;					...
    ;					T25:124  125  126  127


    ; Jeu caracteres bichrome
    ; =======================
    ; G'0  = alphanumerique 	(def bloc : DOR =          B3 B2 B1 B0)
    ; G'10 = semi graphique 1	(def bloc : DOR = B6 B5 B4            )
    ; G'11 = semi graphique 2

org $5000

main:
    di
    push hl
    push ix
    
    
    ; init mat pat...
    call init_redef_ef9345
    
    
    ; redef des car sur 1 tampons en partant de q6
    ld de, 1 ; 1 tampons
    call redef_cars
    
    ; efface l ecran avec hl
    ld hl, $2a56    ; avec des etoiles en magenta/cyan
    call efface_ecran


    ; palette quadri utilisee
    ld d, $23   ; r3 = palette couleurs quadri
    ld e, $8b
    call ef9345

    ; affichage sur 5*4 car
    ld de, $0201; 2*4 sur 1*10 (8x10)
    ld hl, sprite_use
    call display_sprite
    
    
    ; attente espace
    ld a, 0
scrute:
    call 00AAh
    cp 32 ; a contient le code clavier
    jr nz, scrute


    call restore_ef9345
    
    ; retour basic
    pop ix
    pop hl
    ei
    ret
    





;  ======================================
;  affichage direct du sprite
;  à partir de l'adresse "hl"
;  sur une dimension "de" (x*y)
;  suite de commande OCT en partant de hl
;  format lu :
;     R1 R2 sur (x*y) octets
;     soit 2 * d * e octets
;  name: display_sprite
;  @param hl  adresse de depart
;  @param de  dimension xy
;             
;  @return
;  ======================================
display_sprite:
    push de
    push hl
    
    ld b, e
    ld a, 0
    ld (_i), a  ; compteur de ligne

    
ligne_display_sprite:
    push b
    push d
    ld a, b
    ld (_buf), a
    ld b, d
    ld a, 0
    ld (_j), a  ; compteur de col
    
colonne_display_sprite:
    ; affichage des cars definis
    ld a, (hl)
    ld d, $21   ; r1 = car (tampon b6 a b2 + octet b0 et b1)
    ld e, a     ; tampon et car en (hl)
    call ef9345
    
    inc hl
    
    ld a, (hl)
    ld d, $22   ; r2 = jeu
    ld e, a     ; ex bloc 6 11 101 0 01 (11 = quadri) (101 = 110 = 6, B0&B1 inverses) 
                ;(01 HR + incrustation)
    call ef9345
    
    inc hl

    ld a, (_i)
    cp 0        ; a = 0 ?
    jr z, zero_display_sprite
    add a, 7    ; ajout de 7 seulement si pas 0
    zero_display_sprite:
    ld d, $26   ; r6 = ligne (0 pour 0 et n+7 pour [1 <= n <= 24])
    ld e, a
    call ef9345

    ld d, $27   ; r7 = colonne entre 0 et 39
    ld a, (_j)
    ld e, a
    inc a
    ld (_j), a
    call ef9345

    ; initialise avant l appel donc inutile
    ;~ ld d, $23   ; r3 = attributs couleurs quadri
    ;~ ld e, $4b
    ;~ call ef9345

    ld d, $28   ; d=40 (registre r0 + 8 pour l'execution) avec commande ligne suivante
    ld e, $00   ; et e=0 krf dit a l'ef9345 d'executer les registres definis plus tot
    call ef9345
    
    djnz colonne_display_sprite
    
    ; inc ligne
    ld a, (_i)
    inc a
    ld (_i), a
    
    pop d
    pop b
    djnz ligne_display_sprite
    
    pop hl
    pop de
    ret





;  ======================================
;  redefinition des cars ef9345
;  suite de commande OCT en partant du
;  label sprite_def
;  format lu :
;     pour chaque tampon 
;     R4 R5 et 4 cars entrelaces
;     soit 42 octets
;  name: redef_cars
;  @param de  nombre de tampons de 4 cars
;             a lire
;  @return
;  ======================================
redef_cars:
    push de
    push hl
    
    ;~ ld b, 54 ; 54 tampons
    ld b, e ; nombre de tampons
    ld hl, sprite_def ; index R4-R5-tranches
    
loop_tampon:
    push b
    
    ld b, 40; 40 valeurs pour 4 car dans un tampon

    ld a, (hl) ; R4 - bit 3 Bloc (1 car 6=110 ou 7=111)  - Tampon sur 5 bits
    ld (r4), a ; sauvegarde de l'accumulateur
    
    inc hl ; pointeur sur R5
    
    ld a, (hl) ; R5 bit 0 et 1 Bloc à l'envers (01 ou 11) - N° octet sur 6 bits
    ld (r5), a ; sauvegarde de l'accumulateur
    
    inc hl ; pointeur sur valeurs slice
    
loop_tranche:
    push af
    ld d, $21 ; r1
    ld e, (hl) ; Valeur a l index tranche 
    call ef9345
    
    ld d, $24 ; r4
    ld a, (r4)
    ld e, a ; 001 11111 = bloc B2  + N° tampon (31 = 24+7)
    call ef9345
    
    ld d, $25 ; r5
    ld a, (r5) ; bloc B0 B1 = 01
    ld e, a
    call ef9345

    ld d, $28 ; d=40 (registre r0 + 8 pour l'execution) avec commande ligne suivante
    ld e, $34 ; commande OCT
    call ef9345
    pop af
    
    inc a ; valeur r5 suivante (octet suivant dans le tampon)
    ld (r5), a ; on le garde au chaud
    inc hl ; index sur la valeur de la tranche suivante
    
    djnz loop_tranche
    
    pop b
    djnz loop_tampon
    
    pop hl
    pop de
    ret




;  ======================================
;  ecriture ef9345
;  name: ef9345
;  @param d numero registre ef9345
;  @param e valeur du registre
;  @return
;  ======================================
ef9345:
    call $0286; teste si ef935 est pret
    call $0d7c; ecrit dans ef9345 (d=numero du registre, e=valeur du registre)
    ret





;  ======================================
;  initialisation ef9345 commande longue
;  avec redefinition
;  name: init_ef9345
;  @param 
;  @return 
;  ======================================
init_redef_ef9345:

    ; ROR
    ld d, $21 ; dans r1
    ld e, $08 ; 
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $87 ; commande indirection r=1-> ror write
    call ef9345; ecrire dans le registre ror


    ; DOR : definition adresses car redef 
    ;			G'0 (B3 B2 B1 B0) = 0011
    ;			G'10 g'11 (B6 B5 B4) = 010
    ld d, $21 ; dans r1
    ld e, $23 ; Quadri Q6 Q7
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $84 ; commande indirection r=1-> dor write
    call ef9345; ecrire dans le registre dor

    ; TGS
    ld d, $21 ; dans r1
    ld e, $10 ; 0000 0001
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $81 ; commande indirection r=1-> tgs write
    call ef9345; ecrire dans le registre tgs (commandes longues)

    ; PAT
    ld d, $21 ; dans r1
    ld e, $67 ; 0100 0111
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $83 ; commande indirection r=3 -> pat write
    call ef9345; ecrire dans le registre pat

    ; MAT
    ld d, $21 ; dans r1
    ld e, $28 ; bleu
    call ef9345
    ld d, $28 ; r0 exec avec valeur de e ligne suivante
    ld e, $82 ; commande indirection (1000 0 010) r=2 -> mat write
    call ef9345; ecrire dans le registre mat
    
    ; ATTR
    ;~ ld d, $22 ; r2
    ;~ ld e, $81 ; attributs jeu de car / att video std
    ;~ call ef9345

    ;~ ld d, $23 ; r3
    ;~ ld e, $71 ; blanc/rouge dans r3 01110001 -> bits de poids fort = 7
    ;~ call ef9345    
    ret





;  ======================================
;  remise ef9345 etat vg5000
;  name: restore_ef9345
;  @param 
;  @return 
;  ======================================   
restore_ef9345:
    ld d, $21 ; dans r1
    ld e, $00 ; 0000 0001
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $81 ; commande indirection r=1-> tgs write
    call ef9345; ecrire dans le registre tgs (commandes longues)

    ld d, $21 ; dans r1
    ld e, $f7 ; 0100 0111
    call ef9345
    ld d, $28 ; r0 exec
    ld e, $83 ; commande indirection r=3 -> pat write
    call ef9345; ecrire dans le registre pat

    ld d, $21 ; dans r1
    ld e, $6e ; bleu
    call ef9345
    ld d, $28 ; r0 exec avec valeur de e ligne suivante
    ld e, $82 ; commande indirection (1000 0 010) r=2 -> mat write
    call ef9345; ecrire dans le registre mat
    ret



;  ======================================
;  efface l ecran
;  name: efface_ecran
;  @param h car a utiliser
;  @param l couleur encre/fond
;  @return 
;  ======================================   
efface_ecran:
    push de
    push bc
    push hl
    ld d, $22 ; R2
    ld e, $01; Attributs jeu de car / att video
    call ef9345
    ld d, $23 ; R3
    ld e, l ; Attributs jeu de car / att video
    call ef9345

    ld d, 20h       ;krf (01) avec increment pointer
    ld e, 1         ;r0
    call ef9345	    ;01 dans r0
    ld d, 21h

    ld a, h         ; car a utiliser - ex 32 espace
    ld e, a	        ;car dans r1
    call ef9345     ;r1
    ld h, 0         ;ligne 0
    call eralin
    ld h, 08h       ;seconde ligne=8
    ld b, 18h       ;18h lignes
    
cls:
    push bc
    call eralin
    inc h
    pop bc
    djnz cls
    pop hl
    pop de
    pop bc
    ret

eralin:
    ld d, 27h   ;r7
    ld e, 0     ;clr r7 - colonne 0
    call ef9345 ;0 dans r7
    ld b, 28h   ;nombre colonnes
    ld d, 38+8  ; 38d=26h=100110 (r6 ligne)
    ld e,h      ;h contient la ligne a effacer
    
erali1:
    call ef9345
    djnz erali1		;40x (28h dans b)
    ret






;  Variables globales
._buf
    db $00

.r4
    db $00

.r5 
    db $00

._i
    db $00
    
._j
    db $00
    



;Converting b.png
;resizing to  8 10
;dithering with None
;using palette [(0, 0, 0), (255, 0, 0), (255, 255, 0), (255, 255, 255)]
;cars count: 2


.sprite_def
; Bloc 6   -  Tampon  0
; car 1 :  ['$ff', '$3', '$f3', '$f3', '$3', '$f3', '$f3', '$3', '$ff', '$ff']
; car 2 :  ['$ff', '$fc', '$fc', '$fc', '$f0', '$f3', '$f3', '$f0', '$ff', '$ff']
; car 3 :  ['$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0']
; car 4 :  ['$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0', '$0']
; R4 (write) =  00100000 = $20
; R5 (write) =  01000000 = $40
    db  $20 , $40
    db  $ff , $ff , $0 , $0
    db  $3 , $fc , $0 , $0
    db  $f3 , $fc , $0 , $0
    db  $f3 , $fc , $0 , $0
    db  $3 , $f0 , $0 , $0
    db  $f3 , $f3 , $0 , $0
    db  $f3 , $f3 , $0 , $0
    db  $3 , $f0 , $0 , $0
    db  $ff , $ff , $0 , $0
    db  $ff , $ff , $0 , $0
;;;;;;;


.sprite_use
;;;;;;;
; Bloc 6  - Tampon  0  - Octet  0  - ( 0 , 0 )
    db  $0 , $e9
;;;;;;;
; Bloc 6  - Tampon  0  - Octet  1  - ( 1 , 0 )
    db  $1 , $e9
;;;;;;;;;;;
; resolution quadrichromesque 2*4 1*10 = $0201
; tampons 1
; palette 10001011 = $8b
Dernière modification par z80¯\_(ツ)_/¯ le 19 nov. 2020 20:35, modifié 1 fois.
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Images en quadrichrome sur vg5000

Message par Daniel »

Excellent !

Il est vrai que la documentation de l'EF9345 est un peu succincte et laisse planer des doutes, mais avec des essais successifs on arrive à apprivoiser le VDP. Le plus frustrant est la limitation du nombre de caractères, qui ne permet pas d'afficher de trop grandes images.

Il faut rappeler une fois de plus que l'émulation de l'EF9345 dans dcvg5k est assez sommaire. Seul un test avec la vraie machine permet de valider définitivement les programmes. Et s'il apparaît une différence avec l'émulateur, je suis toujours prêt à corriger.
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Papy.G
Modérateur
Messages : 3047
Inscription : 10 juin 2014 13:40
Localisation : Haute-Garonne/Gers

Re: Images en quadrichrome sur vg5000

Message par Papy.G »

z80¯\_(ツ)_/¯ a écrit : 02 nov. 2020 06:46Il faut également prendre en compte que ce mode a des pixels plus larges que hautes pour le redimensionnement.
:shock: Tu peux rétablir des pixels carrés, ainsi, tu doubles le nombres de caractères par Jeu de caractères.
z80¯\_(ツ)_/¯ a écrit :Concernant le mode quadrichrome, les jeux Q6 et Q7 sont utilisés ce qui fait un maximum de 200 caractères redéfinis.
Si ta page-écran n'occupe que les trois premiers blocs (taille maximale d'une page-ecran), il te reste Q3, Q4, et Q5 de libre aussi. :wink:
Daniel a écrit : 02 nov. 2020 08:34Le plus frustrant est la limitation du nombre de caractères, qui ne permet pas d'afficher de trop grandes images.
Avec cinq jeux de caractères en double hauteur, on rempli l'écran, et peut-être en rusant un peu pour récupérer les "octets perdus", on peut même remplir la ligne d'état aussi. 8)
Soyez exigeants, ne vous contentez pas de ce que l'on vous vend.
Demandez-en plus, ou faites-le vous-même.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Images en quadrichrome sur vg5000

Message par Dominique »

Très bien !

J'avais commencé une sorte de Paint en utilisant le BitMap 80 colonnes.Comme Daniel nous avait conseillé de toujours vérifier "en vrai" j'avais fait un petit programme qui affiche les valeurs de R0 à R7 ainsi que les indirects.

Le programme n'utilise que KRF ( avec ou sans INC) et je puis dire que les valeurs affichées en réel sont identiques, si ce n'est le registre R0

Le DCVG5K
VG5K.jpg
VG5K.jpg (82.05 Kio) Consulté 5659 fois
Le réel :
VG Reel.jpg
VG Reel.jpg (503.2 Kio) Consulté 5659 fois
Ci joint la K7 : Aller au Forth par CALL&"4A20" - depuis le Forth lancer la procedure par TEST2

Elle rempli un rectangle bleu en BIT MAP avec des points d'arret chaque fin de colonne (attente d'une touche, n'importe laquelle)
paint.zip
(6.31 Kio) Téléchargé 153 fois
Une petite video en réel :
video-1604309547.zip
(1.14 Mio) Téléchargé 158 fois
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

Je ne peux que tester sur dcvg5k et Mame. Pas de vg5000. Précisément, plus de vg5000 depuis plus de 30 ans...

Sur Mame l'émulation est moins bonne que sur dcvg5k, les palettes de couleurs ne sont pas respectées.

Sinon, je vais essayer d'utiliser d'autres blocs dans une prochaine version. Pour l'instant je me suis beaucoup appuyé sur les exemples du livre d'Alice qui sont sur 2 blocs. Mais en effet, on y parle aussi de la possibilité d'utiliser 5 blocs.
On y parle aussi d'un mode quadrichrome basse résolution avec des caractères de 5 pixels de haut.
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Images en quadrichrome sur vg5000

Message par Dominique »

Si tu as un ficher du programme (BIN OBJ ou wav ou K7) je peux tester si tu veux
Avatar de l’utilisateur
Carl
Modérateur
Messages : 13253
Inscription : 08 avr. 2007 13:21
Localisation : http://www.doledujura.fr
Contact :

Re: Images en quadrichrome sur vg5000

Message par Carl »

Je peux aussi...
Carl
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

Une archive avec un binaire et le source correspondant.

https://onedrive.live.com/embed?cid=3DD ... wTL24PZBBM
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Images en quadrichrome sur vg5000

Message par Dominique »

Je pense qu'il y a un petit problème au niveau de MAT ou PAT (synchronisation avec l écran), ce qui serait normal si tu a pris les paramètres de ces registres sur ALICE.

Premier test
z80-1.jpg
z80-1.jpg (248.21 Kio) Consulté 5605 fois
2° test
Z80-2.jpg
Z80-2.jpg (236.34 Kio) Consulté 5605 fois
Petite Vidéo
z80-3.zip
(925.06 Kio) Téléchargé 167 fois
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

En effet, ce n'est pas synchro sur la video.
Le test 2 est synchro, c'est bien ça ?
Qu'est ce qui change entre le test 1 et 2 ?
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Images en quadrichrome sur vg5000

Message par Dominique »

Je ne fais rien si ce n'est sortir du programme puis le relancer, puis sortir et relancer à nouveau.

A chaque fois l'image est soit décalée, ou saute comme sur la vidéo, ou ne s'affiche qu'en partie etc..

Je ne suis pas le plus calé pour te répondre, mais Il me semble que c'est bien un de ces registres.
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

J'ai l'impression qu'il faut jouer avec ce registre:
Image

Dans le programme, le TGS est à $10. Donc le bit 4 est à 1 (signal composite et comparateur de phase).
Avatar de l’utilisateur
Dominique
Messages : 828
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Images en quadrichrome sur vg5000

Message par Dominique »

Voila : En modifiant TGS ($0) PAT ($77) et MAT ($2E) ça marche

Peut être une seule modif. marcherait - c'est à voir

Code : Tout sélectionner

0348   50EF                 ; TGS
0349   50EF 16 21           ld d, $21 ; dans r1
0350   50F1                 ;ld e, $10 ; 0000 0001
0351   50F1 1E 00           ld e, $00 ; 0000 0001
0352   50F3 CD CC 50    	call ef9345
0353   50F6 16 28           ld d, $28 ; r0 exec
0354   50F8 1E 81           ld e, $81 ; commande indirection r=1-> tgs write
0355   50FA CD CC 50        call ef9345; ecrire dans le registre tgs (commandes longues)
0356   50FD             
0357   50FD                 ; PAT
0358   50FD 16 21           ld d, $21 ; dans r1
0359   50FF                 ;ld e, $67 ; 0100 0111
0360   50FF 1E 77            ld e, $77 ; 0100 0111
0361   5101 CD CC 50        call ef9345
0362   5104 16 28           ld d, $28 ; r0 exec
0363   5106 1E 83           ld e, $83 ; commande indirection r=3 -> pat write
0364   5108 CD CC 50        call ef9345; ecrire dans le registre pat
0365   510B             
0366   510B                 ; MAT
0367   510B 16 21           ld d, $21 ; dans r1
0368   510D                 ;ld e, $28 ; bleu
0369   510D 1E 2E       	ld e, $2E
0370   510F CD CC 50        call ef9345
0371   5112 16 28           ld d, $28 ; r0 exec avec valeur de e ligne suivante
0372   5114 1E 82           ld e, $82 ; commande indirection (1000 0 010) r=2 -> mat write
0373   5116 CD CC 50        call ef9345; ecrire dans le registre mat
Photo z80bis.jpg
Photo z80bis.jpg (265.05 Kio) Consulté 5576 fois

Video :
z80bis.zip
(1.1 Mio) Téléchargé 156 fois
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

Merci pour les tests et ces précisions.
Je vais potasser les PAT-MAT-TGS
Avatar de l’utilisateur
z80¯\_(ツ)_/¯
Messages : 77
Inscription : 06 oct. 2020 13:15
Localisation : Bourgogne

Re: Images en quadrichrome sur vg5000

Message par z80¯\_(ツ)_/¯ »

Suite de mon périple en quadrichromie.

Je voudrais bien utiliser d'autres jeux que q6 et q7 mais je n'arrive pas bien à comprendre l'initialisation du DOR.

Voici la doc Alice:
Explications pour le mode bichrome.
Image

Explications pour le mode quadrichrome.
Image

A chaque fois dans la doc, le DOR est à $23 soit 0010 0011
D'après ce que je comprends, il faut laisser les 3 premiers blocs pour la mémoire écran, d'où le 11 dans dans b3-b2-b1-b0 pour définir où commence le jeu G'0. Ok ?
Après il faut définir le G'10 et G'11 avec les bits b6-b5-b4 et c'est là que je ne comprends pas bien. Pourquoi ce 010 qui fait 2 en décimal détermine le bloc 4 ? Ou bien cela veut dire qu'on utilise 2 blocs consécutifs après le bloc G'0 ?

Enfin je me demande comment initialiser ce DOR si je souhaite récupérer les blocs 4, 5 et éventuellement 3.
Répondre