MSX Village forum

La Place des Développeurs Mon premier jeu en assembleur

aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2654

Le 27/11/2023 à 20h54

Reprise du message précédent

Ton problème n'est qu'un problème d'assembleur. Il y a une disjonction entre les adresses physique de ton jeu dans la ROM et les adresses où il sera vu par le Z80.

Comme a expliqué Jipe, tout le contenu de ta ROM ne sera vu par le Z80 qu'à travers l'une des banques (pages) de la ROM qui seront toutes entre 4000h et BFFFh.

Par contre dans ton fichier ROM, les segments vont être empilés les uns dernières les autres. Le premier à l'offset 0000h, puis 4000h, 8000h, C000h, 10000h, 14000h, etc. (pour un mapper 16 KB).

Il faut que tu trouves un moyen avec ton assembleur de gérer ça. Notamment, si tu as du code dans tes segments, il faut qu'ils soit compilés pour être exécuté à l'emplacement final où il sera vu par le Z80. Sinon les symboles pour les call, les jump, etc. ne seront pas bons.

Évidemment, "oui"... :D
Mais j'ai dû créer un outil MSXhex pour bien gérer les mappeurs avec SDCC. Edité par aoineko Le 27/11/2023 à 20h56


On est toujours ignorant avant de savoir.
Github    
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 28/11/2023 à 09h15
Je crois qu'il va falloir qu'on change de méthode.
Ça va finir par se voir que ce thread n'est qu'une gigantesque publicité pour MSX-gl :p
   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2654

Le 28/11/2023 à 09h23
En même temps c'est à travers la création de cette lib que j'ai quasiment tout appris du système MSX... et du coup je ne connais pas grand chose en dehors des outils que j'utilise.

Ton assembleur doit probablement avoir une façon de gérer les segments de mappeur et si ce n'est pas le cas, tu dois pouvoir trouver un autre assembleur qui le fait. Mais là dessus, je vais pas pouvoir t'aider.

Je pourrais 'expliquer comment ça fonctionne avec l'assembleur de SDCC (ils utilise sdasz80) mais pas sûr que ça te soit utile. Edité par aoineko Le 28/11/2023 à 09h25


On est toujours ignorant avant de savoir.
Github    
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 28/11/2023 à 10h02
Je plaisantais bien sûr.
Quand je lis tout ce que fait MSX-gl, je suis persuadé que c'est la solution idéale pour faire un jeu sur MSX.
Je m'accroche à l'assembleur car ce qui m'amuse, c'est l'assembleur. Mais si je voulais faire un jeu, je choisirai MSX-gl.

Pour ce qui est de mon assembleur, je vais éplucher la doc et laisser tomber la solution de facilité (segments en statique à la queue-leu-leu). C'est forcément prévu. D'ailleurs certains devs de OpenMSX utilisent cet assembleur (sjasm-plus), ce n'est surement pas par hasard.
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1482

Le 28/11/2023 à 16h59
zone :
Pour ce qui est de mon assembleur, je vais éplucher la doc et laisser tomber la solution de facilité (segments en statique à la queue-leu-leu). C'est forcément prévu. D'ailleurs certains devs de OpenMSX utilisent cet assembleur (sjasm-plus), ce n'est surement pas par hasard.

Si c'est comme sjasm, c'est le couple "defpage/page".


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 28/11/2023 à 19h38
sjasm ne connait pas defpage / page, il a un système qui m'a l'air bien compliqué:
https://z00m128.github.io/sjasmplus/documentation.html#s_realdevice

J'avoue que ça m'échappe.
Je comprends bien le problème, mais je ne sais pas si il y a une solution possible sans recopier les variables modifiables dans la ram à 0xC000, au démarrage de la ROM.
Et pour les accès à ces variables, ça va être coton également car il faut que les offsets soient recalculés si on les copie.


   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2654

Le 28/11/2023 à 22h49
Il y a forcement un moyen simple de le faire avec ton assembleur.

Et je ne vois pas le problème avec la RAM.
Aucun des segments de ta ROM ne sera visible en C000h et a l'inverse toute les variables, quelques soit le segment ou elles sont déclarées, seront allouées en RAM (normalement a partir de C000h). Edité par aoineko Le 29/11/2023 à 07h48


On est toujours ignorant avant de savoir.
Github    
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1482

Le 29/11/2023 à 07h55
zone :
Je comprends bien le problème, mais je ne sais pas si il y a une solution possible sans recopier les variables modifiables dans la ram à 0xC000, au démarrage de la ROM.

Je ne vois pas où est le problème avec les variables en RAM ??
Tu les défini dans ton code avec une adresse qui commence à 0xC000, point barre. Forcément, tu vas devoir les initialiser au démarrage, mais ça c'est de la programmation standard.

Et pour les segments, tu ne peux pas simplement utiliser un 'org' qui définit l'adresse de démarrage de chaque segment ?

EDIT : ce sujet pourrait peut-être t'aider

Edité par Metalion Le 29/11/2023 à 11h48


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 29/11/2023 à 15h39
Ça a l'air simple, mais je ne vois pas comment faire.
J'ai essayé différentes combinaisons, avec un .ORG 0xC000

Dans tous les cas, ça augmente la taille de la ROM au dela des 128Ko attendus.
La solution doit être dans la définition d'un « device » (ce dont tu parlais hier avec les directives page,pageselect , mais qui ne sont pas disponibles dans sjasmplus). J'ai lu la doc, je n'ai rien compris. Il y a des devices préconfigurés mais le MSX ne fait pas partie de la liste (pour Spectrum et Amstrad, le mapping a l'air plus simple que sur MSX).

Je pense que je vais utiliser le segment de la rom situé à 0xC000 (physiquement dans le dump de mon programme), switcher dessus au démarrage (donc ça se retrouvera en 0x8000) et copier les valeurs en ram à 0xC000. Je n'aurai même pas besoin de recalculer les offsets, juste une boucle de copie de 5 lignes.

Voici mon programme, un dump de la rom, et une copie d'écran du résultat depuis OpenMSX.

Code :

; Example to create an MegaRom of 128kB that use an ASCII 16K Mapper
; sjasmplus megarom.sjsam --raw=megarom_sj.rom
LF:    equ    0Ah
CR:    equ    0Dh
ENASLT:    equ    0024h
INIT32:    equ    006Fh
CHPUT:    equ    00A2h    ; Address of character output routine of main Rom BIOS
RSLREG:    equ    0138h
Seg_P8000_SW:    equ    07000h    ; Segment switch for page 8000h-BFFFh (ASCII 16k Mapper)
LINL32:    equ    0F3AFh
EXPTBL:    equ    0FCC1h        ; Extended slot flags table (4 bytes)
  .org $4000
header:
    db    41h,42h
    dw    INIT,0,0,0,0,0,0
INIT:
    ld    a,32
    ld    (LINL32),a    ; 32 columns
    call    INIT32        ; SCREEN 1
; Typical routine to select the ROM on page 8000h-BFFFh from page 4000h-7BFFFh
    call    RSLREG
    rrca
    rrca
    and    3    ;Keep bits corresponding to the page 4000h-7FFFh
    ld    c,a
    ld    b,0
    ld    hl,EXPTBL
    add    hl,bc
    ld    a,(hl)
    and    80h
    or    c
    ld    c,a
    inc    hl
    inc    hl
    inc    hl
    inc    hl
    ld    a,(hl)
    and    0Ch
    or    c
    ld    h,080h
    call    ENASLT        ; Select the ROM on page 8000h-BFFFh
    ld    a,1
  ; pour la façon dont OpenMSX détecte le mapper, voir:
  ; https://github.com/openMSX/openMSX/blob/master/src/memory/RomFactory.cc#L112
  ld ($77ff),a ; forcer détection ASCII16
LOOP:
    ld    (Seg_P8000_SW),a    ; Select the segment on page 8000h-BFFFh
    push    af
    ld    hl,seg1     ; Text pointer into HL
    call    Print        ; Call the routine Print below
    pop    af
    inc    a    ; Increment segment number
    cp    8
    jr    nz, LOOP    ; Jump to LOOP if A<8
  ; test pour afficher mon segment R/W
  ld hl,data_rw+1
  ld (hl),'A' ; « RAM » à la place de « ROM » défini par défaut
  dec hl
  call Print
 
Finished:
    jr    Finished    ; Jump to itself endlessly.
Print:
    ld    a,(hl)
    call    CHPUT
    inc    hl    
  and a  ; dernier caractère
    jr nz,Print    
  ret
  block $8000-$,'C' ; code ($8000, car démarre à .org $4000)
seg1:            ; Text pointer label
    db "Text from segment 1",LF,CR,0    ; Zero indicates the end of text.
  block $4000+seg1-$, '1'
seg2:
    db "Text from segment 2",LF,CR,0
  block $4000+seg2-$, '2'
seg3:
    db "Text from segment 3",LF,CR,0
  block $4000+seg3-$, '3'
seg4:
    db "Text from segment 4",LF,CR,0
  block $4000+seg4-$, '4'
seg5:
    db "Text from segment 5",LF,CR,0
  block $4000+seg5-$, '5'
seg6:
    db "Text from segment 6",LF,CR,0
  block $4000+seg6-$, '6'
seg7:
    db "Text from segment 7",LF,CR,0
  block $4000+seg7-$, '7'
  .org 0xC000
data_rw:
  db "ROM",LF,CR,0
  
  END
vim: syntax=z8a


Un dump de la ROM (bien entendu ça déborde, comment pourrait-il en être autrement ?)

Code :

00000000  41 42 10 40 00 00 00 00  00 00 00 00 00 00 00 00  |AB.@............|
00000010  3e 20 32 af f3 cd 6f 00  cd 38 01 0f 0f e6 03 4f  |> 2...o..8.....O|
00000020  06 00 21 c1 fc 09 7e e6  80 b1 4f 23 23 23 23 7e  |..!...~...O####~|
00000030  e6 0c b1 26 80 cd 24 00  3e 01 32 ff 77 32 00 70  |...&..$.>.2.w2.p|
00000040  f5 21 00 80 cd 58 40 f1  3c fe 08 20 f0 21 01 c0  |.!...X@.<.. .!..|
00000050  36 62 2b cd 58 40 18 fe  7e cd a2 00 23 a7 20 f8  |6b+.X@..~...#. .|
00000060  c9 43 43 43 43 43 43 43  43 43 43 43 43 43 43 43  |.CCCCCCCCCCCCCCC|
00000070  43 43 43 43 43 43 43 43  43 43 43 43 43 43 43 43  |CCCCCCCCCCCCCCCC|
*
00004000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
00004010  74 20 31 0a 0d 00 31 31  31 31 31 31 31 31 31 31  |t 1...1111111111|
00004020  31 31 31 31 31 31 31 31  31 31 31 31 31 31 31 31  |1111111111111111|
*
00008000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
00008010  74 20 32 0a 0d 00 32 32  32 32 32 32 32 32 32 32  |t 2...2222222222|
00008020  32 32 32 32 32 32 32 32  32 32 32 32 32 32 32 32  |2222222222222222|
*
0000c000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
0000c010  74 20 33 0a 0d 00 33 33  33 33 33 33 33 33 33 33  |t 3...3333333333|
0000c020  33 33 33 33 33 33 33 33  33 33 33 33 33 33 33 33  |3333333333333333|
*
00010000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
00010010  74 20 34 0a 0d 00 34 34  34 34 34 34 34 34 34 34  |t 4...4444444444|
00010020  34 34 34 34 34 34 34 34  34 34 34 34 34 34 34 34  |4444444444444444|
*
00014000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
00014010  74 20 35 0a 0d 00 35 35  35 35 35 35 35 35 35 35  |t 5...5555555555|
00014020  35 35 35 35 35 35 35 35  35 35 35 35 35 35 35 35  |5555555555555555|
*
00018000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
00018010  74 20 36 0a 0d 00 36 36  36 36 36 36 36 36 36 36  |t 6...6666666666|
00018020  36 36 36 36 36 36 36 36  36 36 36 36 36 36 36 36  |6666666666666666|
*
0001c000  54 65 78 74 20 66 72 6f  6d 20 73 65 67 6d 65 6e  |Text from segmen|
0001c010  74 20 37 0a 0d 00 37 37  37 37 37 37 37 37 37 37  |t 7...7777777777|
0001c020  37 37 37 37 37 37 37 37  37 37 37 37 37 37 37 37  |7777777777777777|
*
00020000  52 4f 4d 0a 0d 00                                 |ROM...|
00020006


Et le résultat devant vos yeux ébahis:
2023-11-29_15_36_57
Edité par zone Le 29/11/2023 à 16h29
   
aoineko Membre non connecté

Conseiller Municipal

Rang

Avatar

Groupe : Shoutbox

Inscrit le : 02/01/2011 à 21h17

Messages: 2654

Le 29/11/2023 à 18h19
Apparemment, asMSX a une gestion native des segments de mapper : https://github.com/Fubukimaru/asMSX/blob/master/doc/asmsx.md

Ceci dit, j'ai l'impression que tu as une confusion entre les adresses de link (ce a quoi sert la directive ORG) et l'adresse physique de tes segments dans la ROM.

Le link, c'est ce qui va donner la valeur final à tes labels en fonction de l'accumulation du code dans les différentes sections de ton programme. Dans le cadre d'une ROM-mapée tous tes segments vont devoir être dans des sections contenu entre 4000h et BFFFh. En aucun cas au delà de C000h où de toute façon ta ROM ne sera pas visible par le Z80.

C'est là où ma connaissance limitée des assembleurs (autre que celui de SDCC, asz80) fait que je ne saurais te dire comment faire concrètement, mais tu as forcément un moyen. Au pire, tu pourrais avoir un fichier assembleur par segment (avec un ORG correspondant à la banque/page dans laquelle il sera sélectionné), de les compiler séparément, puis d'avoir un outil qui regroupe les binaires générés en une seule ROM en plaçant chaque segment a sa place.

C'est ce que fait mon outil MSXhex à partir d'un fichier IHX. Je ne pense pas que JSASM ou asMSX ne supportent ce format donc il te faudra trouver une autre solution.

Tu ne dois pas être le premier à te poser ces questions. Tu dois forcément pouvoir trouver des infos sur le net. Edité par aoineko Le 29/11/2023 à 20h31


On est toujours ignorant avant de savoir.
Github    
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 29/11/2023 à 19h57
C'est assez bizarre, je l'admets, mais je n'ai rien trouvé.
Vous m'avez donné des pistes intéressantes, maintenant il faut que je me débrouille comme un grand :)

Je crois que j'ai une idée d'ailleurs, je vous dirai demain si ça a fonctionné.
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1482

Le 29/11/2023 à 21h12
zone :
Je pense que je vais utiliser le segment de la rom situé à 0xC000 (physiquement dans le dump de mon programme), switcher dessus au démarrage (donc ça se retrouvera en 0x8000) et copier les valeurs en ram à 0xC000.

Mais il n'y a pas de segment de ROM en 0xC000 !!! Tous les segments de ta ROM doivent être assemblés avec une adresse qui est comprise entre 0x4000 et 0xBFFF, quel que soit le segment.

Les segments de ta ROM sont uniquement visibles en 0x4000 et 0x8000 (si ce sont des segments de 16Kb). Ils ne peuvent pas être switchés en dehors de ces adresses. La RAM est disponible et libre à partir de 0xC000.

Bien évidemment, ce qui défini "physiquement" les segments (pour l'émulateur), c'est leur position dans le code assemblé. Si tu génères un fichier de 128 Kb, il comprendra que la page 0 est située de 0x00000 à 0x03FFF, ..., la page 15 est située de 0x1C000 à 0x1FFFF.

Exemple (avec sjasm) de définition de segments :
Code :
defpage 0,4000h ; défini la page 0 avec un début en 0x4000
defpage 1,4000h ; défini la page 1 avec un début en 0x4000
defpage 2,8000h ; défini la page 2 avec un début en 0x8000
defpage 3,8000h ; défini la page 3 avec un début en 0x8000

...

; code du segment 0
page 0
...

; code du segment 1
page 1
...

; code du segment 2
page 2
...

; code du segment 3
page 3
...


Edité par Metalion Le 29/11/2023 à 21h21


MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
   
zone Membre non connecté

Touriste

Rang

Avatar

Inscrit le : 11/10/2023 à 19h25

Messages: 66

Le 30/11/2023 à 12h05
Victoire !

Vu le temps que vous y avez passé, c’était bien la moindre des choses.

Je vais expliquer mon raisonnement, en espérant que cela aidera quelqu’un d’autre.

J'ai deux objectifs:
1) une ROM de 128 Ko, avec un mapper 16 Ko.
2) pouvoir modifier certaines variables définies à la compilation.

Le moyen le plus simple est de placer ces variables en 0xC000 (RAM).
Mais la cartouche a un mapper qui isole tous les les segments définis dessus:
1) le code va de 0x4000 à 0x7FFF
2) le reste suit, mais seul un segment à la fois est adressable de 0x8000 à 0xBFFF

En observant un dump de la megarom, je vois que tous les segments se suivent.
Le MSX a un stub très simple de 16 octets pour les cartouches. Il n'y a pas de définition de segments dans un entête.
J'en déduis que le seul levier à disposition des compilateurs est de placer « physiquement » les segments dans la ROM.

Il n'y a pas forcément correspondance physique entre le fichier ROM et la mémoire du MSX.
Les cartouches 16Ko permettent peut-être de caler des données dans la RAM puisque 0xC000 est disponible dans ce cas.
Mais je n'en mettrais pas ma main au feu (le segments physiquement à 0xC000 sur la cartouche est peut-être ignoré) et de toutes façons, avec une megarom ça ne fonctionnera pas (il y a déjà des données megarom à l'adresse 0xC000 de la cartouche)

La directive « .org » est utile pour calculer à l'avance les offsets des données, mais ne place rien physiquement en mémoire. C'est juste pour la compilation et les valeurs de décalage mémoire ou d'adressage absolu.

J'ai essayé de définir un segment avec le device « SPECTRUM128 » de sjasmplus, qui avait l'air de correspondre (pages de 16Ko).
Ça m'a créé une ROM de 4Ko, échec.

J'ai fini par aller au plus simple: dans mon segment « code », je peux mettre tout ce que je veux puisque les subtilités code / data / bss … n'ont pas lieu d'être sur ces vieilles machines.
J'utilise donc ce segment pour mes données à modifier, et elles sont copiées ensuite à 0xC000 au démarrage.

Voici la partie intéressante du programme:

Code :

  .org $4000
header:
    db    41h,42h
    dw    INIT,0,0,0,0,0,0
INIT: ; 0x4010
  ; copier les variables r/w vers la ram
  ld hl,data_rw_base_for_copy
  ld de,0xc000
  ld bc,ram_length
  ldir
 … ; suite du programme coupée

  ; bout du segment « code »
  ; il faut réserver de la place pour les données qui suivent et qui vont être copiées en RAM au boot
  block $8000-$ - ram_length,'C' ; code ($8000, car démarre à .org $4000)

data_rw_base_for_copy: ; base réelle dans ROM. Ne pas utiliser sauf pour copie vers RAM
  .org 0xC000
data_rw: ; ce label est à 0xC000
  db "ROM",LF,CR,0
ram_length equ $-$C000

  ; et ensuite, je repasse à 0x8000 pour commencer au bon endroit les segments de la ROM
  .org 0x8000
seg1:
  db "Text from segment 1",LF,CR,0
  block $4000+seg1-$, '1'
; et la même chose jusqu'au segment 7


Et pour tester tout ça:

Code :

  ; test pour afficher mon segment R/W
  ld hl,data_rw+1
  ld (hl),'A'
  dec hl
  call Print


La chaine « ROM » est bien modifiée en « RAM ».

2023-11-30_11_36_07 Edité par zone Le 30/11/2023 à 12h10
   
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie