# Print avec VisUAL

Le programme présent permet d'exécuter un programme assembleur écrit pour VisUAL et d'afficher les entiers ou
chaînes de caractères en utilisant la procédure `println`.

Ce programme ne sert que d'exécution, il ne modifie pas le programme assembleur. Ainsi, votre programme assembleur doit
être adapté dès le début en suivant les instructions ci-dessous.

## Utilisation

Vous pouvez exécuter votre programme assembleur et afficher son output avec la commande suivante :

```bash
java -jar pcl.jar <programme>
```

Par exemple `java -jar pcl.jar example.s`

## Adapter votre code

Ajoutez par défaut les instructions suivantes à votre programme assembleur.

### Le code à ajouter

Tout d'abord le programme doit commencer par une déclaration de l'espace nécessaire à l'affichage.

```armasm
STR_OUT      FILL    0x1000
```

Ajoutez le code nécessaire à l'affichage :

```armasm
println      STMFD   SP!, {LR, R0-R3}
             MOV     R3, R0
             LDR     R1, =STR_OUT ; address of the output buffer
PRINTLN_LOOP LDRB    R2, [R0], #1
             STRB    R2, [R1], #1
             TST     R2, R2
             BNE     PRINTLN_LOOP
             MOV     R2, #10
             STRB    R2, [R1, #-1]
             MOV     R2, #0
             STRB    R2, [R1]


             ;       we need to clear the output buffer
             LDR     R1, =STR_OUT
             MOV     R0, R3
CLEAN        LDRB    R2, [R0], #1
             MOV     R3, #0
             STRB    R3, [R1], #1
             TST     R2, R2
             BNE     CLEAN
             ;       clear 3 more
             STRB    R3, [R1], #1
             STRB    R3, [R1], #1
             STRB    R3, [R1], #1

             LDMFD   SP!, {PC, R0-R3}
```

Ajoutez le code nécessaire pour transformer un entier en chaîne de caractère :

```armasm
to_ascii      STMFD   SP!, {LR, R4-R7}
              ; make it positive
              MOV R7, R0
              CMP     R0, #0	
              MOVGE   R6, R0	
              RSBLT   R6, R0, #0
              MOV     R0, R6

              MOV     R4, #0 ; Initialize digit counter

to_ascii_loop MOV     R1, R0
              MOV     R2, #10
              BL      div32 ; R0 = R0 / 10, R1 = R0 % 10
              ADD     R1, R1, #48 ; Convert digit to ASCII
              STRB    R1, [R3, R4] ; Store the ASCII digit
              ADD     R4, R4, #1 ; Increment digit counter
              CMP     R0, #0
              BNE     to_ascii_loop

              ; add the sign if it was negative
              CMP     R7, #0
              MOVGE   R1, #0	
              MOVLT   R1, #45
              STRB    R1, [R3, R4]
              ADD     R4, R4, #1

              LDMFD   SP!, {PC, R4-R7}
```

Et le code pour une division :

```armasm
;       Integer division routine
;       Arguments:
;       R1 = Dividend
;       R2 = Divisor
;       Returns:
;       R0 = Quotient
;       R1 = Remainder
div32    STMFD   SP!, {LR, R2-R5}
         MOV     R0, #0
         MOV     R3, #0
         CMP     R1, #0
         RSBLT   R1, R1, #0
         EORLT   R3, R3, #1
         CMP     R2, #0
         RSBLT   R2, R2, #0
         EORLT   R3, R3, #1
         MOV     R4, R2
         MOV     R5, #1
div_max  LSL     R4, R4, #1
         LSL     R5, R5, #1
         CMP     R4, R1
         BLE     div_max
div_loop LSR     R4, R4, #1
         LSR     R5, R5, #1
         CMP     R4,R1
         BGT     div_loop
         ADD     R0, R0, R5
         SUB     R1, R1, R4
         CMP     R1, R2
         BGE     div_loop
         CMP     R3, #1
         BNE     div_exit
         CMP     R1, #0
         ADDNE   R0, R0, #1
         RSB     R0, R0, #0
         RSB     R1, R1, #0
         ADDNE   R1, R1, R2
div_exit CMP     R0, #0
         ADDEQ   R1, R1, R4
         LDMFD   SP!, {PC, R2-R5}
```

### Comment afficher maintenant ?

Remarque : les explications suivantes peuvent sensiblement différer selon la façon dont vous gérez votre pile et la
façon dont vous gérez les opérandes.

#### Idée générale

Vous devez stocker en pile la valeur que vous souhaitez afficher précédée d'un '0'. La limite théorique de taille à
afficher est grande (de la taille de STR_OUT).

#### Du code

On suppose que la valeur à afficher se trouve dans R0. L'idée reste la même si vous souhaitez afficher quelque chose de
plus grand que 4 octets.

Pour appeler la procédure `println` :

```armasm
SUB SP, SP, #4   ; réservez 4 octets pour le 0
MOV R1, #0
STR R1, [SP]
SUB SP, SP, #4   ; réservez 4 octets pour la valeur (ou plus)
STR R0, [SP]     ; stockez la valeur
MOV R0, SP       ; adresse de la valeur (ici SP, mais peut être n'importe quelle adresse)
BL println
ADD SP, SP, #8   ; libérez la pile
```

Si vous disposez dans R0 de l'adresse de la valeur à afficher, vous pouvez directement appeler `println`. L'important
est que la valeur dans R0 lors de l'appel soit bien l'adresse de la valeur à afficher.

### Remarque importante

Vous remarquerez que si vous donnez l'adresse d'une valeur entière, par exemple 65, vous allez afficher 'A' et pas
l'entier 65. Pour afficher un entier, vous devez donc le convertir en chaîne de caractères. Vous pouvez utiliser la
procédure `to_ascii` pour cela.

Un exemple d'appel en supposant que j'ai dans R0 la valeur entière que je souhaite afficher :

```armasm
addr0 FILL 12              ; on réserve 12 octets pour la valeur
      LDR R3, =addr0       ; on charge l'adresse de la valeur
      BL to_ascii          ; on convertit l'entier en chaîne de caractères
      LDR R0, =addr0       ; on charge l'adresse de la chaîne de caractères
      BL println           ; on affiche la chaîne de caractères
```

## Fonctionnement

La technique utilisée est l'exploitation des breakpoints de VisUAL.

Le programme Java lit d'abord le programme assembleur à la recherche de la ligne `STRB    R2, [R1, #-1]` indiquant la
fin de l'affichage. La ligne correspondante (en commençant à compter les lignes à 0) est alors stockée et considérée
comme un breakpoint.

La ligne utilisée permet d'ajouter un `\n` à la fin de l'affichage. Si vous souhaitez afficher sans saut de ligne, vous
pouvez supprimer la ligne précédente (le MOV de 0) ou recréer une procédure `print` sans le MOV (il faut tout de même le
STRB pour le breakpoint).

On exécute finalement le programme assembleur à l'aide de la version headless de VisUAL en lui donnant les arguments
nécessaires.
Basiquement, lors de l'exécution, le programme s'arrête à chaque breakpoint et produit du contenu dans un fichier de
log. Le fichier de log est ensuite lu par le programme Java et il extrait le contenu de STR_OUT lors de chaque
affichage. Le fichier de log contient la valeur en hexadécimal, convertie en ASCII lors de la lecture des logs.

L'exécution est plutôt verbeuse, si vous souhaitez simplement afficher le résultat de l'exécution, vous devrez extraire
la bonne information de l'output.