org 0x0100 ; Adresse de début .COM

;Ecriture de la chaîne hello dans la console
    mov si, hello; met l'adresse de la chaîne à afficher dans le registre SI
;    call affiche_chaine

    mov bx, 1; on va écrire les nombres avec un caractère terminal
    int 0x11
    test ax, 0b00000000000001
    jnz lecteurs_disquette
;    mov si, pas
;    call affiche_chaine
fin_disquette:
;    mov si, disquettes
;    call affiche_chaine
test_coprocesseur:
    test ax, 0b00000000000010
    jnz coprocesseur_present
;    mov si, pas
;    call affiche_chaine
coprocesseur_present:
;    mov si, coprocesseur
;    call affiche_chaine

test_DMA:
;    mov si, au_demarrage
;    call affiche_chaine
;    pop ax
    test ax, 0b00000100000000
    jnz DMA_present
;    mov si, pas
;    call affiche_chaine
DMA_present:
;    mov si, DMA
;    call affiche_chaine
test_RS232:
    push ax
    and ax, 0b00111000000000
    shr ax, 9
    mov di, hello
    call nombre_vers_chaine
;    mov si, hello
;    call affiche_chaine
;    mov si, RS232
;    call affiche_chaine
    pop ax
    test ax, 0b01000000000000
    jnz manette_presente
;    mov si, pas
;    call affiche_chaine
manette_presente:
;    mov si, manette
;    call affiche_chaine
test_modem:
    test ax, 0b10000000000000
    jnz modem_present
;    mov si, pas
;    call affiche_chaine
modem_present:
;    mov si, modem_interne
;    call affiche_chaine
    shr ax, 14
    mov di, hello
    call nombre_vers_chaine
;    mov si, hello
;    call affiche_chaine
;    mov si, imprimantes
;    call affiche_chaine
;lecture mémoire disponible
    int 0x12
    mov di, hello
    call nombre_vers_chaine
;    mov si, hello
;    call affiche_chaine
;    mov si, memoire_dispo
;    call affiche_chaine

;Informations du disque 0
    mov ah, 0x08;            /* Get drive info */
    mov dl, 0x80;    /* Drive is 80H for Disk 0, 81H for Disk 1 */
    int 0x13
    jc ecran
    push cx
    xor al, al
    mov ah, cl
;    and ah, 0xC0
    shr ah, 6
;    shl ax, 2
;    shr cx, 8
    add al, ch
    add ax, 2; /* +1 because starts from 0 and +1 for FDISK leaving one out */
    mov bx, 1
    mov di, hello
    call nombre_vers_chaine
    mov si, hello
    call affiche_chaine
    mov si, nombre_de_cylindres
    call affiche_chaine
    xor ah, ah
    mov al, dl
    inc al
    mov di, hello
    call nombre_vers_chaine
    mov si, hello
    call affiche_chaine
    mov si, nombre_de_tetes
    call affiche_chaine
    pop cx
    mov ax, cx
    xor ah, ah
    and al, 0x3F
    mov di, hello
    call nombre_vers_chaine
    mov si, hello
    call affiche_chaine
    mov si, nombre_de_secteurs
    call affiche_chaine
ecran:
    mov ax, 0x4F00 ; demande infos sur le pilote VESA
    mov di, hello
    int 10h
    cmp al, 0x4F ; Si AL <> 0x4F, on n'a pas de VESA, donc fin.
    jne fin
    mov si, hello + 0x06 ; pointeur vers le nom de l'OEM stocké offset:segment
    lodsw; on charge l'adresse d'offset dans ax
    mov bx, ax ; BX contient l'adresse d'offset
    lodsw ; on charge l'adresse de segment dans ax
    mov si, bx ; SI pointe sur le nom de l'OEM
    push ds ; on sauvegarde DS
    mov ds, ax ; ds contient l'adresse de segment du nom de l'OEM
    call affiche_chaine
    pop ds ; on restaure DS
    mov si, retour_chariot
    call affiche_chaine

    mov si, hello + 0x0E ; pointeur vers la liste des modes supportés
    lodsw ; on charge l'adresse d'offset dans ax
    mov cx, ax ; cx contient l'adresse d'offset
    lodsw ; on charge l'adresse de segment dans ax
    mov si, cx ; si pointe sur le premier mode supporté
    mov dx, ax ; dx contient l'adresse de segment
lit_mode_suivant:
    push ds
    mov ds, dx ; ds contient l'adresse de segment de la liste des modes
    lodsw ;charge dans ax le mode
    pop ds
    cmp ax, 0xFFFF ; Fin de la liste
    je arret_modes
    xor ah, ah ; on enlève le haut du mode
    mov di, hello ; on écrit dans hello
    mov bx, 0
    call nombre_vers_chaine
    mov al, ' '
    stosb
    mov al, 0 ; on met 2 caractères d'un coup après la chaîne : un espace et le zéro terminal.
    stosb ; les caractères sont dépilés, c'est à dire qu'il faut placer le premier dans la zone basse
    push si ;sauve si sur la pile
    mov si, hello
    call affiche_chaine
    pop si ; on récupère si
    jmp lit_mode_suivant
arret_modes:
    mov si, retour_chariot ; Affichage d'un retour chariot
    call affiche_chaine
    mov cx, [mode_souhaite] ; On s'enquiert du mode souhaité
;suite_mode_VESA:
    mov ax, 0x4F01 ; demande infos sur le mode VESA
    mov di, hello
    int 0x10
    cmp al, 0x4F ; Si AL <> 0x4F, la fonction n'est pas supportée, on se contentera du VGA.
    jne adresse_mode_13h
    cmp ah, 0x01 ; idem en cas de AH à 1
    je adresse_mode_13h
    mov si, hello ; pointeur vers la zone de données remplie par l'interruption
    lodsw
    test ax, 0b1 ; mode supporté ?
    jz adresse_mode_13h ; On se contente du VGA
    mov si, hello + 0x06 ; pointeur vers la taille de la fenêtre graphique
    mov di, taille_fenetre ; pointeur vers notre structure à nous
    mov ax, ds ; DS = ES
    mov es, ax
    movsw ; SI pointe maintenant vers l'adresse du segment de la fenêtre A
    movsw ; taille_fenetre et adr_fen_A sont maintenant stockées
    movsw ; adr_fen_B sont maintenant stockées
    mov si, hello + 0x10 ; largeur
    mov di, largeur_memoire ; pointeur vers notre structure à nous
    movsw
    movsw
    movsw ; Lit hauteur_image
;    mov si, hello + 0x1A ; nombre de banques
;    mov di, nombre_de_banques_ecran ; pointeur vers notre structure à nous
;    movsb
;    xor ah, ah
    mov ax, [largeur_image]
    mov di, hello ; on écrit dans hello
    mov bx, 1
    call nombre_vers_chaine
    mov si, hello
    call affiche_chaine
    mov si, retour_chariot
    call affiche_chaine
    mov ax, [adr_fen_A]
    or ax, ax ; on teste l'adresse du segment de la fenêtre. Si elle est nulle, on passe en mode 0x13
    jnz adresse_OK
adresse_mode_13h:
    mov word [mode_souhaite], 0x0013 ; infos du mode 0x13, le mode VGA
    mov word [adr_fen_A], 0xA000
    mov word [hauteur_image], 200
    mov word [largeur_image], 320
    mov word [largeur_memoire], 320
adresse_OK:
    xor ax, ax
    mov es, ax
    les bx, [es:0x33*4]
    mov cx, es
    or cx, bx
    jcxz pas_de_souris      ; aucune interruption présente!
    mov bx, [es:0xCE]
    mov es, bx
    cmp Byte [es:0], 0xCF ; Pour les hypocrites d'interruption souris, quand
    je  pas_de_souris           ; elles sont bidon, elles pointent sur un IRET!
    ; Pilote souris présent
    xor ax, ax
    int 0x33
    or ax, ax
    jz pas_de_souris
    jmp souris_OK
pas_de_souris:
    mov si, pas_33h
    call affiche_chaine

souris_OK:
    mov di, hello ; met l'adresse de la chaîne à lire dans le registre SI
    call lit_chaine ; On attend l'utilisateur pour nettoyer l'écran

    mov ax, 0x4F02
    mov bx, [mode_souhaite]
    int 0x10 ; Changement de mode vidéo
    call nettoyage_ecran
    mov ax, 160 ; Coordonnée X
    mov bx, 100 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    mov ax, 319 ; Coordonnée X
    mov bx, 199 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    mov ax, 639 ; Coordonnée X
    mov bx, 399 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    mov ax, 639 ; Coordonnée X
    mov bx, 479 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    mov ax, 799 ; Coordonnée X
    mov bx, 599 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    mov ax, 1279 ; Coordonnée X
    mov bx, 1023 ; Coordonnée Y
    mov dx, 0x03; Couleur
    call affiche_point
    push 100
    push 10
    push 100
    push 20
    mov dx, 0x04; Couleur
    call affiche_ligne
    add sp, 8
    push 102
    push 20
    push 102
    push 10
    mov dx, 0x05; Couleur
    call affiche_ligne
    add sp, 8
    push 114
    push 10
    push 104
    push 10
    mov dx, 0x06; Couleur
    call affiche_ligne
    add sp, 8
    push 104
    push 20
    push 114
    push 20
    mov dx, 0x07; Couleur
    call affiche_ligne
    add sp, 8
    push 126
    push 20
    push 124
    push 10
    mov dx, 0x08; Couleur
    call affiche_ligne
    add sp, 4
    push 116
    push 18
    mov dx, 0x09; Couleur
    call affiche_ligne
    add sp, 4
    push 124
    push 30
    mov dx, 0x0A; Couleur
    call affiche_ligne
    add sp, 4
    push 116
    push 22
    mov dx, 0x0B; Couleur
    call affiche_ligne
    add sp, 4
    push 132
    push 10
    mov dx, 0x0C; Couleur
    call affiche_ligne
    add sp, 4
    push 136
    push 16
    mov dx, 0x0D; Couleur
    call affiche_ligne
    add sp, 4
    push 136
    push 24
    mov dx, 0x0E; Couleur
    call affiche_ligne
    add sp, 4
    push 132
    push 30
    mov dx, 0x0F; Couleur
    call affiche_ligne
    add sp, 8
    push 10
    push 10
    push 1270
    push 1014
    mov dx, 0x02; Couleur
    call affiche_ligne
    add sp, 8
    push 511
    push 614
    push 1000
    push 614
    mov dx, 0x04; Couleur
    call affiche_ligne
    add sp, 8
    mov di, hello; met l'adresse de la chaîne à lire dans le registre SI
    call lit_chaine ; On attend la volonté de l'utilisateur
    mov ax, 0x4F02 ; Retour au mode texte
    mov bx, 0x0003; 80 * 25, mode texte
    int 0x10
fin:
    ret

lecteurs_disquette:
;On a un lecteur de disquette. Les bits 6 et 7 de AX en donnent le nombre
    push ax
    and ax, 0b0000000011000000
    shr ax, 6
    inc ax
    mov di, hello
    call nombre_vers_chaine
    mov si, hello
    call affiche_chaine
    pop ax
    jmp fin_disquette

;écrit dans la chaîne pointée par DI le nombre contenu dans AX
;si BL est à un, on écrit un caractère terminal
;BH contient le nombre minimal de caractères à utiliser
nombre_vers_chaine:
    push cx
    push dx
    push bx
    mov bx, 10
    mov cx, 1
    xor dx, dx
stocke_digit:
    div bx
;    mov dl, ah
    push dx ;sauve le reste dans la pile
    inc cx
;    xor ah, ah
    xor dx, dx
    or ax, ax
    jne stocke_digit

    inc bh
ajout_zero:
    cmp bh, cl
    jbe boucle_digit
    push 0
    inc cx
    jmp ajout_zero
;Affichage du chiffre
boucle_digit:
    dec bh
    loop affiche_digit
    pop bx ; on récupère le paramètre bx
    test bl, 0b1 ; s'il est à 1, on écrit un caractère terminal
    jz depile
    mov byte [di], 0
depile:
    pop dx
    pop cx
ret

affiche_digit:
    pop ax
    add ax, '0'
    stosb ; met AL dans l'octet pointé par DI et incrémente DI
    jmp boucle_digit
;fin nombre_vers_chaine

affiche_chaine:
    push ax
    push bx
    push cx
    push dx
    xor bh, bh; RAZ de bh, qui stocke la page d'affichage
    mov ah, 0x03
    int 0x10; appel de l'interruption BIOS qui donne la position du curseur, stockée dans dx
    mov cx, 1; nombre de fois où l'on va afficher un caractère
affiche_suivant:
    lodsb
    or al, al;on compare al à zéro pour s'arrêter
    jz fin_affiche_suivant
    cmp al, 13
    je nouvelle_ligne
    mov ah, 0x0A;on affiche le caractère courant cx fois
    int 0x10
    inc dl; on passe à la colonne suivante pour la position du curseur
    cmp dl, 80
    je nouvelle_ligne
positionne_curseur:
    mov ah, 0x02;on positionne le curseur
    int 0x10
    jmp affiche_suivant
fin_affiche_suivant:
    pop dx
    pop cx
    pop bx
    pop ax
    ret
nouvelle_ligne:
    inc dh; on passe à la ligne suivante
    xor dl, dl; colonne 0
    jmp positionne_curseur
;fin de affiche_chaine

lit_chaine:
    push ax
    push cx
    push dx
    mov ah, 0x03
    int 0x10; appel de l'interruption BIOS qui donne la position du curseur, stockée dans dx
    mov cx, 1
attend_clavier:
    mov ah, 0x01;on teste le buffer clavier
    int 0x16
    jz attend_clavier
    ;al contient le code ASCII du caractère
    xor ah, ah; on lit le buffer clavier
    int 0x16
    stosb
    cmp al, 13
    je fin_attend_clavier
    ;al contient le code ASCII du caractère
    mov ah, 0x0A;on affiche le caractère courant cx fois
    int 0x10
    inc dl; on passe à la colonne suivante pour la position du curseur
    mov ah, 0x02;on positionne le curseur
    int 0x10
    jmp attend_clavier
fin_attend_clavier:
    inc dh; on passe à la ligne suivante pour la position du curseur
    xor dl, dl
    mov ah, 0x02;on positionne le curseur
    int 0x10
    mov byte [di], 0;on met le caractère terminal dans si
    pop dx
    pop cx
    pop ax
    ret
;fin de lit_chaine

;fonction affiche_point : on est déjà dans un mode graphique
;AX : Coordonnée X du point
;BX : Coordonnée Y du point
;dL : Couleur du point
affiche_point:
    push bx ; On sauve les registres qu'on va manipuler
    push cx
    push es
    push di
    push dx
    push ax
    mov es, [adr_fen_A] ; On va dans la mémoire vidéo
    mov ax, bx;
    mul word [largeur_memoire]
    mov di, ax
    pop cx
    add di, cx
    adc dx, 0
    cmp dx, [bloc_courant]
    je bloc_OK
    mov [bloc_courant], dx
    mov ax, 0x4F05
    xor bh, bh
    int 0x10 ; Changement de fenêtre
bloc_OK:
;    pop bx ; On récupère la coordonnée X
    pop dx ; On récupère la couleur
;    add di, bx ; index = IndexY + X
    push cx ; On remet X dans la pile
    mov al, dl ; On fixe la couleur du pixel
    stosb ; Et on l'écrit dans la mémoire vidéo
    pop ax ; On restaure les registres manipulés
    pop di
    pop es
    pop cx
    pop bx
    ret
;fin de affiche_point

;fonction affiche_ligne : on est déjà dans un mode graphique
; DL contient la couleur
affiche_ligne:
    jmp depart_affiche_ligne
Y2: dw 0
X2: dw 0
Y1: dw 0
X1: dw 0
deltaX: dw 0
deltaY: dw 0
incX: dw 0
incY: dw 0
e: dw 0
couleur: db 0
depart_affiche_ligne:
    push si
    push ax
    mov ax, sp
    mov si, ax
    add si, 6 ; SI pointe sur Y2
    push bx
    push cx
    push dx
    push di
    mov di, Y2
    mov ax, ds
    mov es, ax
    mov cx, 4
    rep movsw
    mov [couleur], dl
    mov ax, [X2]
    mov bx, [X1]
    sub ax, bx
    mov [deltaX], ax
    mov cx, [Y2]
    mov bx, [Y1]
    sub cx, bx
    mov [deltaY], cx
    or ax, ax ; test deltaX
    jnz test_deltaX_positif
    or cx, cx ; test deltaY
    jnz test_deltaY_deltaX_nul
fin_affiche_ligne:
    mov dl, [couleur]
    mov ax, [X2]
    mov bx, [Y2]
    call affiche_point
    mov ax, [X1]
    mov bx, [Y1]
    call affiche_point
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    pop si
    ret

deltaX_positif:
    or cx, cx
    jnz test_deltaY_deltaX_positif
    ;vecteur horizontal vers la droite
    mov cx, [deltaX]
    mov dx, 1
    mov word [incX], 1
    mov word [incY], 0
    jmp ligne_H_V

test_deltaY_deltaX_nul:
    mov word [incY], 1
    mov word [incX], 0
    cmp cx, 0
    jns ligne_H_V
    neg cx
    mov word [incY], -1
ligne_H_V:
    mov ax, [X1]
    mov bx, [Y1]
    mov dl, [couleur]
boucle_H_V:
    loop avance_H_V
    jmp fin_affiche_ligne

avance_H_V:
    add ax, [incX]
    add bx, [incY]
    call affiche_point
    jmp boucle_H_V

test_deltaX_positif:
    cmp ax, 0
    jns deltaX_positif
    or cx, cx
    jnz test_deltaY_deltaX_negatif
    ;vecteur horizontal vers la gauche
    mov cx, [deltaX]
    neg cx
    mov dx, -1
    mov word [incX], -1
    mov word [incY], 0
    jmp ligne_H_V

charge_registres:
    shl cx, 1
    shl ax, 1
    mov [deltaY], cx
    mov [deltaX], ax
    mov ax, [X1]
    mov bx, [Y1]
    ret

charge_e_deltaX_et_cmp_X2:
    mov [e], ax
    call charge_registres
    mov cx, [X2]
    ret

charge_e_deltaY_et_cmp_Y2:
    mov [e], cx
    call charge_registres
    mov cx, [Y2]
    ret

affiche_et_charge_eY:
    mov dl, [couleur]
    call affiche_point
    add bx, [incY]
    mov dx, [e]
    ret

affiche_et_charge_eX:
    mov dl, [couleur]
    call affiche_point
    add ax, [incX]
    mov dx, [e]
    ret

octants1_et_4:
    call charge_e_deltaX_et_cmp_X2
depart_boucle1:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    jns X_pret1
    add bx, [incY]
    add dx, [deltaX]
X_pret1:
    mov [e], dx
    jmp depart_boucle1

deltaY_positif_deltaX_negatif:
    neg ax
deltaY_positif_deltaX_positif:
    mov word [incY], 1
    ;deltaY > 0, deltaX > 0
    cmp ax, cx
    jae octants1_et_4
    neg ax
    call charge_e_deltaY_et_cmp_Y2
depart_boucle2_et_3:
    call affiche_et_charge_eY
    cmp bx, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    jns X_pret2_et_3
    add ax, [incX]
    add dx, [deltaY]
X_pret2_et_3:
    mov [e], dx
    jmp depart_boucle2_et_3

octant5:
    call charge_e_deltaX_et_cmp_X2
depart_boucle5:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    sub dx, [deltaY]
    cmp dx, 0
    js X_pret5
    add bx, [incY]
    add dx, [deltaX]
X_pret5:
    mov [e], dx
    jmp depart_boucle5

octant8:
    neg cx
    call charge_e_deltaX_et_cmp_X2
depart_boucle8:
    call affiche_et_charge_eX
    cmp ax, cx
    je fin_affiche_ligne
    add dx, [deltaY]
    cmp dx, 0
    jns X_pret8
    add bx, [incY]
    add dx, [deltaX]
X_pret8:
    mov [e], dx
    jmp depart_boucle8

test_deltaY_deltaX_positif:
    mov word [incX], 1
    cmp cx, 0
    jns deltaY_positif_deltaX_positif
    ;deltaY < 0, deltaX > 0
    mov word [incY], -1
    neg cx
    cmp ax, cx
    jae octant8
    neg cx
    jmp octants6_et_7

test_deltaY_deltaX_negatif:
    mov word [incX], -1
    cmp cx, 0
    jns deltaY_positif_deltaX_negatif
    ;deltaY < 0, deltaX < 0
    mov word [incY], -1
    cmp ax, cx
    jbe octant5
    neg ax
octants6_et_7:
    call charge_e_deltaY_et_cmp_Y2
depart_boucle6_et_7:
    call affiche_et_charge_eY
    cmp bx, cx
    je fin_affiche_ligne
    add dx, [deltaX]
    cmp dx, 0
    js X_pret6_et_7
    add ax, [incX]
    add dx, [deltaY]
X_pret6_et_7:
    mov [e], dx
    jmp depart_boucle6_et_7
;AFFICHE_LIGNE ENDP

nettoyage_ecran:
    push di
    push es
    push ax
    push bx
    push cx
    push dx
    mov word es, [adr_fen_A ]; On lit l'adresse de départ de la mémoire vidéo

    mov cx, [hauteur_image]
    mov ax, [largeur_memoire]
    mul cx
boucle_fenetres:
    push cx
    mov dx, cx
    dec dx
    mov ax, 0x4F05
    xor bh, bh
    int 0x10 ; Changement de fenêtre
    mov cx, 0x8000 ; Nombre de mots dans un morceau d'écran
    xor di, di
    mov ax, 0x0101 ; Deux fois de suite la couleur à appliquer
    rep stosw ; et on boucle
    pop cx
    loop boucle_fenetres
    pop dx
    pop cx
    pop bx
    pop ax
    pop es
    pop di
    ret
;Fin nettoyage_ecran
mode_souhaite: dw 0x8107
taille_fenetre: dw 0
adr_fen_A: dw 0
adr_fen_B: dw 0
largeur_memoire: dw 320
largeur_image: dw 320
hauteur_image: dw 200
bloc_courant: db 0
disquettes: db ' lecteur(s) de disquette installé(s).', 13, 0
pas: db 'Pas de ', 0
coprocesseur: db 'Coprocesseur arithmétique.', 13, 0
memoire_dispo: db ' ko.', 13, 0
au_demarrage: db ' au démarrage.', 13, 0
DMA: db 'DMA.', 13, 0
RS232: db ' port(s) RS232 disponible(s).', 13, 0
manette: db 'Manette de jeu.', 13, 0
modem_interne: db 'Modem interne.', 13, 0
imprimantes: db ' imprimante(s) connectée(s).', 13, 0
heure: db '00 h 00 min 00 s', 13, 0
retour_chariot: db 13, 0
nombre_de_cylindres: db ' cylindres.', 13, 0
nombre_de_tetes: db ' tetes.', 13, 0
nombre_de_secteurs: db ' secteurs par piste.', 13, 0
pas_33h: db 'Pas d`interruption 0x33.', 13, 0
hello: db 'Bonjour papi. Je cherche une ligne de plus de quatre vingts caractères. Ce doit être relativement facile à trouver, non ?', 13, 0
