Obligement - L'Amiga au maximum

Lundi 25 septembre 2017 - 17:20  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - les variables locales
(Article écrit par Thomas Pimmel et extrait d'ANews - septembre 1999)


L'homo-assembleur n'utilise généralement la pile que pour y ranger sa massue et éventuellement ses adresses de retour.

Je vous propose dans cette rubrique une méthode simple pour créer des variables locales, histoire de ne pas gâcher tout cet espace et de rendre vos programmes réentrants.

Nous allons nous servir de l'instruction "link", inventée par un fumeur de LIFO (last in, first out) et des macros. Link est un animal assez évolué, mais relativement facile à domestiquer. Pour ceux qui ne le connaissent pas, voici ses habitudes. Tout d'abord, il faut savoir que link ne se reproduit pas en captivité et que sa femelle s'appelle "unlk". L'exemple suivant...

link   a5,#-16

...sauve le contenu de a5 dans la pile, copie le SP (stack pointer) dans a5, puis recule le SP de 16 octets. C'est l'équivalent de la routine suivante :

move.la5,-(sp)
move.lsp,a5
sub.l        #16,sp

On constate que a5 pointe sur la fin de la zone allouée. Pour effacer la zone, il faut utiliser les offsets suivants :

clr.l   -4(a5)
clr.l   -8(a5)
clr.l   -12(a5)
clr.l   -16(a5)

L'instruction "unlk a5" fait le contraire et rétablit la pile :

move.l   a5,sp
move.l   (sp)+,a5

On voit tout de suite qu'utiliser des offsets négatifs, ce n'est pas très propre pour un homo-erectus qui va de l'avant. Il faudrait pouvoir définir des noms de variables pour ces offsets, par le moyen d'une structure.

Pour déclarer une structure, on utilise la macro STRUCTURE définie dans exec/types.i, et pour déclarer des offsets on a le choix entre LONG, WORD, APTR, etc.

Je propose donc de créer les macros _LONG, _WORD, etc. qui reculeront l'offset au lieu de l'avancer. Voici la définition de LONG :

_LONG     MACRO    ;long (32 bits)
\1        EQU    SOFFSET
SOFFSET   SET    SOFFSET+4
          ENDM

Elle peut être complétée par celle-ci :

LONGMACRO
SOFFSET    SET    SOFFSET-4
\1         SET    SOFFSET
           ENDM

Et voici à quoi peut ressembler une structure destinée aux variables locales :

STRUCTURE   variable_locale,0
   __LONG   motlong           ; -4
   __LONG   petitkiki         ; -8
   __LONG   varloc_sizeof     ; -8

On l'utilise très simplement :

link        a5,#varloc_sizeof
move,l#$BABA,motlong(a5)
unlk        a5

C'est tout de même plus joli.

On va donc reprendre exec/types.i et recréer toutes les macros. Jetez un oeil sur le nouvel include suivant (varloc.i). J'ai repris toutes les définitions de macros en les adaptant aux offsets négatifs :

*********************************************
* Macros pour variables locales
*********************************************

_APTR	MACRO
SOFFSET	SET	SOFFSET-4
\1	SET	SOFFSET
	ENDM

_LONG	MACRO
SOFFSET	SET	SOFFSET-4
\1	SET	SOFFSET
	ENDM

_SHORT	MACRO
SOFFSET	SET	SOFFSET-2
\1	SET	SOFFSET
	ENDM

_BYTE	MACRO
SOFFSET	SET	SOFFSET-1
\1	SET	SOFFSET
	ENDM

_STRUCT	MACRO	; name, size
SOFFSET	SET	SOFFSET-\2
\1	EQU	SOFFSET
	ENDM

_LINK	MACRO
	link	\1,#(\2&$fffffffc)
	ENDM

Une petite macro bien pratique, en passant :

STRUCT     MACRO     ; name, size
SOFFSET    SET       SOFFSET-\2
\1         EQU       SOFFSET
           ENDM

Avec _STRUCT il est possible de loger une structure entière dans la pile (ici une structure de dos.i) :

STRUCTURE utile,0
     _STRUCT     ma_structure,ds_
SIZEOF
     LABEL       utile_sizeof

Pour utiliser cette structure, on peut imaginer un code comme celui-ci :

lea     ma_structure(a5),a()
clr.l   ds_Days(a0)
clr.l   ds_Minute(a0)
clr,l   ds_Tick(a0)

Avant de vous laisser graver ces quelques lignes de code sur les murs de la grotte, une dernière macro :

_LINK     MACRO
    link  \1,#(\2&$fffffffc
    ENDM

Ceux qui n'ont pas abusé de l'alcool de palme ont compris... Cette macro assure l'alignement de la pile et vous évitera des accidents de chasse. De plus, elle vous évite de devoir écrire la caractère "#", et j'ai horreur d'écrire les "#".

STRUCTURE   exemple,0
    __STRUCT  date,dat_SIZEOF
    __BYTE    pipo
    LABEL     exemple_sizeof

MaFonction
     _LINK    a3,exemple_sizeof
     clr.b    pipo(a3)
     unlk     a3
     rts

Voici un petit exemple. C'est une routine qui ouvre une bibliothèque et affiche un petit message d'erreur :

	include	exec/types.i
	include	exec/memory.i
	include	dos/dos.i
	include	varloc.i
	include	exec_lib.i
	include	dos_lib.i
Début
	; ouverture de la doslib version 75, ça devrait
	; en toute logique foirer complètement

	moveq	#75,d0
	lea	dosname(pc),a0
	bsr	OpenLibrary
	tst.l	d0
	beq	.error

	nop	; sisi!

.error
	moveq	#0,d0
	rts


;=============================
; Base=OpenLibrary(libname/version)
;			a0	d0
;=============================

 STRUCTURE openlibrary,0
	_LONG	ol_version		; version
	_APTR	ol_name			; nom de la lib à ouvrir
	_APTR	ol_dosbase		; dos.library
	_APTR	ol_output		; sortie donnée par _LVOOutput
	_APTR	ol_closeoutput		; sortie donnée par _LVOOpen
	_APTR	ol_return		; valeur de retour
	LABEL	ol_sizeof

OpenLibrary
	_LINK	a5,ol_sizeof
	movem.l	d2-7/a2-4,-(sp)

	; init de la structure
	move.l	a0,ol_name(a5)
	move.l	d0,ol_version(a5)
	clr.l	ol_closeoutput(a5)
	clr.l	ol_dosbase(a5)
	clr.l	ol_return(a5)

	; ouverture
	bsr	OL_Open

	; fermetures éventuelles
	bsr	OL_Close

	move.l	ol_return(a5),d0
	movem.l	(sp)+,d2-7/a2-4
	unlk	a5
	rts

;----------------
; ouvrir lib
;----------------
OL_Open
	; on ouvre
	move.l	ol_name(a5),a1
	move.l	ol_version(a5),d0
	move.l	4.w,a6
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,ol_return(a5)
	bne.s	.rts
	bsr	OL_Error
.rts
	rts


;----------------
; fermer dosbase et con:
;----------------
OL_Close
	; fermer con:
	move.l	ol_closeoutput(a5),d1
	beq.s	.noclose
	move.l	ol_dosbase(a5),a6
	jsr	_LVOClose(a6)
.noclose
	; fermer doslib
	move.l	ol_dosbase(a5),a1
	tst.l	a1
	beq.s	.nolib
	move.l	4.w,a6
	jsr	_LVOCloseLibrary(a6)
.nolib
	rts

;----------------
; Afficher erreur
;----------------
OL_Error
	; ouvrir dos en version 0
	moveq	#0,d0
	lea	dosname(pc),a1
	move.l	4.w,a6
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,ol_dosbase(a5)
	beq.s	.nomsg

	; chercher une sortie
	move.l	ol_dosbase(a5),a6
	jsr	_LVOOutput(a6)
	move.l	d0,ol_output(a5)
	bne.s	.displaymsg

	; ouvrir con:
	move.l	#ol_con,d1
	move.l	#MODE_NEWFILE,d2
	jsr	_LVOOpen(a6)
	move.l	d0,ol_output(a5)
	move.l	d0,ol_closeoutput(a5)
	beq.s	.nomsg

.displaymsg
	bsr	OL_DspMsg
.nomsg
	rts

;----------------
; "Write" Erreur
;----------------
 STRUCTURE dspmsg,0
	_APTR	dm_buffer
	_LONG	dm_size
	LABEL	dm_sizeof

OL_DspMsg
	_LINK	a4,dm_sizeof
	clr.l	dm_size(a4)
	clr.l	dm_buffer(a4)

	; compter la place utile pour le message
	lea	ol_msg(pc),a0
	lea	ol_name(a5),a1
	lea	RDFMT_Cpt(pc),a2
	lea	dm_size(a4),a3
	move.l	4.w,a6
	jsr	_LVORawDoFmt(a6)

	; allouer mémoire
	move.l	dm_size(a4),d0
	move.l	#MEMF_PUBLIC,d1
	move.l	4.w,a6
	jsr	_LVOAllocVec(a6)
	move.l	d0,dm_buffer(a4)
	beq.s	.rts

	; copier
	lea	ol_msg(pc),a0
	lea	ol_name(a5),a1
	lea	RDFMT_Copy(pc),a2
	move.l	dm_buffer(a4),a3
	move.l	4.w,a6
	jsr	_LVORawDoFmt(a6)

	; écrire message dans sortie
	move.l	ol_output(a5),d1
	move.l	dm_buffer(a4),d2
	move.l	dm_size(a4),d3
	subq.l	#1,d3			; le zéro de la fin n'a pas à être imprimé
	move.l	ol_dosbase(a5),a6
	jsr	_LVOWrite(a6)

	; libérer mémoire
	move.l	dm_buffer(a4),a1
	move.l	4.w,a6
	jsr	_LVOFreeVec(a6)
.rts
	unlk	a4
	rts

RDFMT_Cpt
	addq.l	#1,(a3)
	rts

RDFMT_Copy
	move.b	d0,(a3)+
	rts


;========================
; Constantes
;========================
dosname	dc.b	'dos.library',0
ol_con	dc.b	'con:////"Test"/CLOSE/WAIT',0
ol_msg	dc.b	'Erreur lors de l''ouverture de',$a
	dc.b	'"%s" version %lu',$a,0

Pour le mois prochain, ne perdez pas cet article. Nous verrons comment lancer des sous-programmes en multitâche. Il y aura de l'aventure, du sexe, de la violence, et bien sûr des caraïbles locales.


[Retour en haut] / [Retour aux articles]