Vidage des registres et de la mémoire !

On peut difficilement être plus proche du cœur du CPU qu'avec l'assembleur...

Modérateur : Francois

Répondre
Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Vidage des registres et de la mémoire !

Message par Artemus24 » ven. 22 janv. 2021 08:08

Salut à tous.

Je viens de terminer mon premier petit projet qui consiste, comme l'a fait avant moi M. Vincent Leboulou, l'affichage des registres et de la mémoire.
Pour ce faire, j'ai décomposé mon projet en deux parties, dont l'une est une bibliothèque et l'autre le programme principale.

Voici le source de la bibliothèque :

Code : Tout sélectionner

	.section .init
	.data

mess:	.ascii	"Reg    :  "
digit:	.fill	11,1,0x20
lf:	.ascii	"\n"

addr:	.fill	8,1,0x20
	.ascii	"  :  "
dump:	.fill	48,1,0x20
	.ascii	" :  "
char:	.fill	16,1,0x20
	.ascii	"\n"

addr1:	.word	0
addr2:	.word	0


	.text
	.global addr1,addr2,reg,mem

@ ================= @
@ Subroutine : disp @
@ ================= @

disp:	push	{r0,r7,lr}

	mov	r0,#1
	mov	r7,#4
	svc	#0

	pop	{r0,r7,pc}
	bx	lr


@ ================ @
@ Subroutine : aff @
@ ================ @

aff:	push	{r0-r2,r4-r12,lr}

	sub	r3,r3,#1
	cmp	r3,#0
	bgt	aff1

	mov	r2,#22
	mov	r3,#4			@ line feed
	b	aff2

aff1:	mov	r2,#21
aff2:	ldr	r1,=mess
	bl	disp

	pop	{r0-r2,r4-r12,pc}
	bx	lr


@ ================ @
@ Subroutine : reg @
@ ================ @

reg:	push    {r0-r12,lr}

@ ---------- @
@ Initialize @
@ ---------- @

	mov	r0,#0			@ loops number
	ldr	r1,=mess		@ mess address
	ldr	r2,=digit		@ digit address
	mov	r3,#4			@ line feed
	mov	r4,#0			@ register number
	mov	r5,#7			@ register display

@ --------------- @
@ Register Number @
@ --------------- @

reg1:	cmp	r4,#9
	addle	r7,r4,#48
	addgt	r7,r4,#55
	strb	r7,[r1,#4]		@ hexadecimal character

	add	r4,r4,#1		@ next value
@	cmp	r4,#13
@	addeq	r4,r4,#1		@ Reg E

@ -------------- @
@ Register Value @
@ -------------- @

	ldr	r6,[sp,r0]

reg2:	and	r7,r6,#15
	cmp	r7,#9
	addle	r7,r7,#48
	addgt	r7,r7,#55
	strb	r7,[r2,r5]		@ hexadecimal character

	lsr	r6,#4			@ logical right shift
	sub	r5,r5,#1
	cmp	r5,#0
	bge	reg2

	bl	aff			@ subroutine disp

	mov	r5,#7			@ register display

@ ----------- @
@ End of Loop @
@ ----------- @

	add	r0,r0,#4		@ next register
	cmp	r0,#48
	ble	reg1

	ldr	r1,=lf
	mov	r2,#1
	bl	disp
	bl	disp

@ ------ @
@ Return @
@ ------ @

	pop	{r0-r12,pc}
	bx	lr


@ ================= @
@ Subroutine : hexa @
@ ================= @

hexa:	and	r8,#15
	cmp	r8,#9
	addle	r8,r8,#48
	addgt	r8,r8,#55
	strb	r8,[r4,r5]

	bx	lr


@ ================ @
@ Subroutine : mem @
@ ================ @

mem:	push	{r0-r12,lr}

@ ---------- @
@ Initialize @
@ ---------- @

	ldr	r0,=addr1		@ start memory address
	ldr	r0,[r0]
	lsr	r0,#4
	lsl	r0,#4

	ldr	r1,=addr2		@ end   memory address
	ldr	r1,[r1]
	lsr	r1,#4
	lsl	r1,#4

	ldr	r2,=addr		@ address
	mov	r3,#7

	ldr	r4,=dump		@ dump
	mov	r5,#0			@ index

	ldr	r6,=char		@ char
	mov	r7,#0			@ index and loop

@ ------- @
@ Address @
@ ------- @

mem1:	mov     r8,r0

mem2:	and     r9,r8,#15
        cmp     r9,#9
        addle   r9,r9,#48
        addgt   r9,r9,#55
        strb    r9,[r2,r3]              @ hexadecimal character

        lsr     r8,#4                   @ logical right shift
        sub     r3,r3,#1
        cmp     r3,#0
        bge     mem2

@ ----------- @
@ Hexadecimal @
@ ----------- @

mem3:	ldrb	r8,[r0]
	lsr	r8,#4
	bl	hexa			@ Hexa Low

	ldrb	r8,[r0]
	add	r5,r5,#1
	bl	hexa			@ Hexa High

	add	r5,r5,#2

@ --------- @
@ Character @
@ --------- @

	ldrb	r8,[r0]

	cmp	r8,#32
	blt	mem4
	cmp	r8,#128
	blt	mem5

mem4:	mov	r8,#46
mem5:	strb	r8,[r6,r7]

	add	r0,r0,#1		@ Next Hexa

	add	r7,r7,#1
	cmp	r7,#16
	blt	mem3

@ ------- @
@ Display @
@ ------- @

	push	{r0-r2,r7}
	ldr	r1,=addr		@ address of string
	mov	r2,#82			@ length  of string
	bl	disp
	pop	{r0-r2,r7}

@ ----------- @
@ End of Loop @
@ ----------- @

	mov	r3,#7
	mov	r5,#0
	mov	r7,#0
	cmp	r0,r1
	blt	mem1

@ ------ @
@ Return @
@ ------ @

	pop	{r0-r12,pc}
	bx	lr
Voici le makefile qui est associé à ce source :

Code : Tout sélectionner

# ------------------------------- #
#   Déclaration des Executables   #
# ------------------------------- #

RM	= @rm -f
ASM	= @as
EX	= @chmod +x
AR	= @ar rc
RL	= @ranlib

# -------------------------- #
#   Déclaration des Objets   #
# -------------------------- #

SRC	= main.asm
OBJ	= libsubr.o
BIN	= libsubr.a

# ------------------------------ #
#   Déclaration des Paramètres   #
# ------------------------------ #

FLAG	=

# ------------------------------------ #
#   Compilation et Edition des liens   #
# ------------------------------------ #

all: before $(BIN) after

before:
	clear
	$(RM) $(OBJ)
	$(RM) $(BIN)

$(BIN): $(OBJ)
	$(AR) $(BIN) $(OBJ)
	$(RL) $(BIN)

$(OBJ): $(SRC)
	$(ASM) $(SRC) -o $(OBJ)

after:
	$(RM) $(OBJ)
Le nom de ma bibliothèque est "libsubr.a" pour library subroutine.

Voici le source du programme principale :

Code : Tout sélectionner

	.section .init
	.data

	.align	4
alpha:	.byte	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15
	.byte	 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31
	.byte	 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47
	.byte	 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63
	.byte	 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79
	.byte	 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95
	.byte	 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111
	.byte	112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127
	.byte	128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143
	.byte	144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159
	.byte	160, 161, 162, 163, 160, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175
	.byte	176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191
	.byte	192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207
	.byte	208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223
	.byte	224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239
	.byte	240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
	.equ	beta,.

	.text

@ ============ @
@ Main Program @
@ ============ @

	.global	main

main:

@ ---------- @
@ Initialize @
@ ---------- @

	ldr	r0,=alpha
	ldr	r1,=addr1
	str	r0,[r1]

	ldr	r1,=beta
	ldr	r2,=addr2
	str	r1,[r2]

	mov	r2,#0
	mov	r3,#0
	mov	r4,#0
	mov	r5,#0
	mov	r6,#0
	mov	r7,#0
	mov	r8,#0
	mov	r9,#0
	mov	r10,#0
	mov	r11,#0
	mov	r12,#0

@ --------------- @
@ Call reg & mem  @
@ --------------- @

	bl	reg
	bl	mem

@ ---- @
@ Exit @
@ ---- @

	mov	r0,#0			@ return code 0
	mov	r7,#1			@ exit system call
	svc	#0			@ supervisor call
Et voici le makefile :

Code : Tout sélectionner

# ----------------------------- #
#   Déclaration des Commandes   #
# ----------------------------- #

RM	= @rm -rf
ASM	= @as
CC	= @gcc
EX	= @chmod +x

# -------------------------- #
#   Déclaration des Objets   #
# -------------------------- #

SRC	= main.asm
OBJ	= main.o
BIN	= dump

# --------------------------------- #
#   Déclaration des Bibliothèques   #
# --------------------------------- #

LIBS	= ../include/libsubr.a

# ------------------------------------ #
#   Compilation et Edition des liens   #
# ------------------------------------ #

all: clean $(BIN) after

.PHONY: clean $(BIN) after

clean:
	clear
	$(RM) $(OBJ)
	$(RM) $(BIN)

$(BIN): $(OBJ)
	$(CC)  $(OBJ) -o $(BIN) $(LIBS)

$(OBJ): $(SRC)
	$(ASM) $(SRC) -o $(OBJ)

after:
	$(RM) $(OBJ)
	$(EX) $(BIN)
@./$(BIN)
Pour terminer, je vous donne le résultat de l'exécution :

Code : Tout sélectionner

Reg 0  :  00021030   Reg 1  :  00021130   Reg 2  :  00000000   Reg 3  :  00000000
Reg 4  :  00000000   Reg 5  :  00000000   Reg 6  :  00000000   Reg 7  :  00000000
Reg 8  :  00000000   Reg 9  :  00000000   Reg A  :  00000000   Reg B  :  00000000
Reg C  :  00000000

00021030  :  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  :  ................
00021040  :  10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F  :  ................
00021050  :  20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F  :   !"#$%&'()*+,-./
00021060  :  30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  :  0123456789:;<=>?
00021070  :  40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F  :  @ABCDEFGHIJKLMNO
00021080  :  50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F  :  PQRSTUVWXYZ[\]^_
00021090  :  60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F  :  `abcdefghijklmno
000210A0  :  70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F  :  pqrstuvwxyz{|}
000210B0  :  80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F  :  ................
000210C0  :  90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F  :  ................
000210D0  :  A0 A1 A2 A3 A0 A5 A6 A7 A8 A9 AA AB AC AD AE AF  :  ................
000210E0  :  B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF  :  ................
000210F0  :  C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF  :  ................
00021100  :  D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF  :  ................
00021110  :  E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF  :  ................
00021120  :  F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF  :  ................
>
Dans cet exemple, l'adresse de début ainsi que l'adresse de fin du vidage de la mémoire sont dans les registre 0 et 1.
L'adresse est un mutile de 4K, ox00010000, puisqu'une section fait 4K.

Je suis en UTF-8. J'ai affiché que les caractères ASCII lisible. Pour le reste, j'ai mis un point.

@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Vidage des registres et de la mémoire !

Message par Artemus24 » sam. 23 janv. 2021 08:07

Salut à tous.

Si cela ne vous intéresse pas d'avoir une bibliothèque, vous pouvez fusionner les deux sources en un seul exécutable.
Vous renommer main.asm, celui qui contient les subroutines en subr.asm.
Puis vous lancez de makefile :

Code : Tout sélectionner

# ----------------------------- #
#   Déclaration des Commandes   #
# ----------------------------- #

RM      = @rm -rf
ASM     = @as
CC      = @gcc
EX      = @chmod +x

# -------------------------- #
#   Déclaration des Objets   #
# -------------------------- #

SC1     = subr.asm
OB1     = subr.o

SC2     = main.asm
OB2     = main.o

BIN     = dump

# ------------------------------------ #
#   Compilation et Edition des liens   #
# ------------------------------------ #

all: clean $(BIN) after

.PHONY: clean $(BIN) after

clean:
        clear
        $(RM) $(OB1)
        $(RM) $(OB2)
        $(RM) $(BIN)

$(BIN): $(OB1) $(OB2)
        $(CC)  $(OB1) $(OB2) -o $(BIN)

$(OB1): $(SC1)
        $(ASM) $(SC1)        -o $(OB1)

$(OB2): $(SC2)
        $(ASM) $(SC2)        -o $(OB2)

after:
        $(RM) $(OB1)
        $(RM) $(OB2)
        $(EX) $(BIN)
        @./$(BIN)
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

VincentLeboulou
Messages : 35
Enregistré le : jeu. 19 oct. 2017 10:11

Re: Vidage des registres et de la mémoire !

Message par VincentLeboulou » mar. 26 janv. 2021 16:12

Bonjour.
Bravo pour votre premier projet et bienvenue dans la programmation en assembleur Arm.
Une remarque : vous faites en début de routine push {....,lr} et en fin de routine un pop {...,pc} puis un bx lr.
Dans ce cas cette dernière instruction est inutile puisque le pop pc va mettre dans le compteur d'instruction pc l'adresse de retour contenue dans lr.
Et donc le bx lr n'est jamais exécuté.
Bon courage pour la suite.

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Vidage des registres et de la mémoire !

Message par Artemus24 » mer. 27 janv. 2021 08:37

Salut M. Vincent Leboulou.

Bravo pour votre blog consacré à l'assembleur ARM de la raspberry. :D

J'ai déjà fait de l'assembleur, jadis, mais à chaque fois, c'est un nouvel apprentissage car les règles ne sont pas les mêmes.
Merci pour cette précision concernant le push et le pop, car hormis la sauvegarde des registres r0 jusqu'à r12, je n'ai pas compris l'utilité de faire la sauvegarde du registre lr dans pc.

A ce niveau, quelle est la bonne pratique ?
Dois-je continuer à mettre "push {..., lr}" puis "pop {...,pc]" sans utiliser le 'bx lr" ?
Ou bien mettre "push {...}" puis "pop {...]" et utiliser le 'bx lr" ?
Je parle de ce qui est le plus propre, enfin je veux dire la norme.

Avez-vous testé mon exemple ?

Cordialement.
Artemus24.
@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

VincentLeboulou
Messages : 35
Enregistré le : jeu. 19 oct. 2017 10:11

Re: Vidage des registres et de la mémoire !

Message par VincentLeboulou » mer. 27 janv. 2021 15:02

Je ne sais quelle est la norme en la matière !! Mais compte tenu que la solution pop {..,pc} fait gagner une instruction elle est à privilégier s'il est nécessaire d'optimiser une sous -routine sinon je trouve que la solution avec bx lr est plus lisible.

Artemus24
Raspinaute
Messages : 1077
Enregistré le : ven. 15 sept. 2017 19:15

Re: Vidage des registres et de la mémoire !

Message par Artemus24 » mer. 27 janv. 2021 15:27

Oui, moi aussi je considère que la solution avec "bx lr" est plus lisible.

@+
RPI4B/8GB + Argon FanHAt
Rpi3A+, Rpi3B+
RPi 2B + Joy-It I2C Serial 20x4 2004 LCD Module
RPi 2B + PIM273 Unicorn HAT HD 16x16 Leds RGB
RPi0v1.3, RPi0W + LibreElec/Kodi, Rpi0WH + Tuner TV HAT
NodeMCU ESP32

Répondre

Retourner vers « Assembleur »