;FL - Formule Leucocytaire ;par Gilles Muller ;chercher: ;DispG ;DispT ;PwrR ;StGDB ;Text ;affichage en petit caractères en BASIC ;qq fonctions intéressantes ;call _RAM_PAGE_1 ;call $33 ;call _VPUTBLANK ;call _cphlde ;call _vputsn ;rst 20h ;copy to OP1(destroy hl) ;call _lddr ;ld (iy+5),%00001010 #include "TI86.inc" ;#include "ti86ops.inc" ;#include "ti86math.inc" _ioPrompt equ $c324 _ASAP_IND equ $d623 ;_dispOP1 equ $515b ;alias et définitions - variables cpt_taille equ 2 nd_de_chiffres_apres_virgule equ 2 nb_de_compteurs equ 12 nb_de_lignes equ 7 ;début du programme : .org _asm_exec_ram ;remet les compteurs à zéro xor a ;a=0 ld hl,nbMaxLeuco ld b,result_1-nbMaxLeuco+10 raz: ld (hl),a inc hl djnz raz ld (result_2-1),a ld (result_3-1),a ;init ;OP1 = 100 ( _OP1=C089 h ) - OP1=00 02 FC 100 call _op1set1 ld a,2 ld (_OP1EXPM),a ;(_OP1+1) = 2 ld de,nb_100 call _movfrop1 ;11 octets de op1 à (de) ;demande de données (grands caractères) call _clrScrn call _homeup ld hl,nb_max_leuco call prompt ;call _puts / call _getkey / call input / call _newline ld de,_OP1+1 ;call convop1 ;op1 -> de,a (max 9999) call bcd2bin ;hl=nombre max de leucocytes (en binaire) ld (nbMaxLeuco),hl ;stocke résultat dans nbMaxLeuco ld de,nb_nbMax call _movfrop1 ;11 octets de op1 à (de) ;ld hl,_OP1+9 ;source ;ld de,nbMaxLeuco ;dest ;ld bc,cpt_taille ;nb octets ;ldir ;copie source vers dest avec la taille donnée ;rst 08h ;call _op1toop2 ;call _dispOP1 ;displays op1 right justified big numbers ld hl,nb_leuco call prompt ;OP1 = taux leuco ld de,nb_nbLeuco call _movfrop1 ;11 octets de op1 à (de) ;affichage de l'écran de saisie (petits caractères) call _clrLCD call _runindicoff ;enlève la barre qui clignote en haut à droite de l'écran call affichage_saisie ld hl,(nbMaxLeuco) ld b,l ld c,h inc c boucle_comptage: call compte_touche djnz boucle_comptage dec c jr nz,boucle_comptage ;comptage sur 16 bits ;calcul du résultat ;;OP3=nb max leuco ;;OP4=taux leuco ;pourcentage ;calcul du nb de leuco (G/L) corrigé ld hl,nb_nbLeuco call _movtoop1 ;11 octets de (hl) à op1 ld hl,nb_nbMax call _movtoop2 ;11 octets de (hl) à op2 call _FPMULT ld ix,cpt_deb+20 ld h,(ix) ;récupère Ea ld l,(ix+1) ;récupère Ea ld d,(ix+2) ;récupère Ep ld e,(ix+3) ;récupère Ep add hl,de ;hl=Ea+Ep ld de,(nbMaxLeuco) add hl,de ;hl=Ea+Ep+NbmaxLeuco call _setXXXXop2 ;hex hl to BCD op2 (modifie les registres) call _FPDIV ld de,nb_nbLeuco call _movfrop1 ;11 octets de op1 à (de) (OP1=nb leuco G/L modifié) ;fin calcul nb leuco G/L ld de,result_1 ld (result_ptrs),de ld de,result_2 ld ix,cpt_deb ld b,nb_de_compteurs calc_pourcent: ld a,b push bc ;sauvegarde bc pour la boucle push de ;sauvegarde de pour l'enregistrement cp 2 ;cas du compteur Ea jr nz,cas_normal_compteur ;cas du compteur Ea : on met 0 dans la ligne du bilan des leuco puis on continue normalement pour les Ea ld hl,nb_nbMax call _movtoop1 ld de,(result_ptrs) ld hl,_OP1 call OP2Dec ld (result_ptrs),de cas_normal_compteur: ;OP1 = 100 ld hl,nb_100 call _movtoop1 ;11 octets de (hl) à op1 ;OP2 = compteur ( _OP2=C094 h ) ;hl=pointeur vers cpt ld h,(ix) inc ix ld l,(ix) inc ix call _setXXXXop2 ;hex hl to BCD op2 (modifie les registres) ;sauvegarde la valeur pour l'affichage ld de,(result_ptrs) ld hl,_OP2 ;nombre à convertir call OP2Dec ld (result_ptrs),de ;calcule call _FPMULT ;rst 30h ;compteur*100 (op1=op1*op2) ld hl,nb_nbMax call _movtoop2 ;OP2 = nbMaxLeuco call _FPDIV ;compteur*100/nb max leuco (op1=op1/op2) pop de pop bc ld a,b push bc push de cp 2 ;cas du compteur Ea jr nz,cas_normal1 ;cas de la ligne leuco : on met 100 et la valeur actuel de OP1 est mise à la ligne suivante pour Ea ld hl,nb_100 call _movtoop2 ld hl,_OP2 pop de call OP2Dec push de cas_normal1: pop de ;récupère l'endroit à enregistrer ld hl,_OP1 ;nombre à convertir call OP2Dec pop bc ;récupère bc djnz calc_pourcent ld de,result_3 ld ix,cpt_deb ld b,nb_de_compteurs calc_GL: push bc ;sauvegarde bc pour la boucle push de ;sauvegarde de pour l'enregistrement ;OP2 = compteur ( _OP2=C094 h ) ;hl=pointeur vers cpt ld h,(ix) inc ix ld l,(ix) inc ix call _setXXXXop2 ;hex hl to BCD op2 (modifie les registres) ;OP1 = nb de leuco G/L corrigé ld hl,nb_nbLeuco call _movtoop1 ;11 octets de (hl) à op1 call _FPMULT ;rst 30h ;compteur*nb de leuco (op1=op1*op2) ;OP2 = nbMaxLeuco ld hl,nb_nbMax call _movtoop2 ;11 octets de (hl) à op2 call _FPDIV ;compteur*nb de leuco/100 (op1=op1/op2) pop de pop bc ld a,b push bc push de cp 2 ;cas du compteur Ea jr nz,cas_normal2 ;cas de la ligne leuco : on met le nombre G/L corrigé et la valeur actuel de OP1 est mise à la ligne suivante pour Ea ld hl,nb_nbLeuco call _movtoop2 ld hl,_OP2 pop de call OP2Dec push de cas_normal2: pop de ;récupère l'endroit à enregistrer ld hl,_OP1 ;nombre à convertir call OP2Dec pop bc ;récupère bc djnz calc_GL ;affichage du bilan (petit caractères) ;init colonnes : result_ptrs : nb_de_ligne_descendues,ptr0,ptr1,ptr2,ptr3 xor a ld (result_ptrs),a ;nb_de_ligne_descendues=0 ld hl,result_0 ld (result_ptrs+1),hl ld hl,result_1 ld (result_ptrs+3),hl ld hl,result_2 ld (result_ptrs+5),hl ld hl,result_3 ld (result_ptrs+7),hl call affichage_bilan ;quitte le programme (grands caractères) call _clrScrn call _homeup ld hl,au_revoir call _puts call _newline ret ;exit program ;;;;;;;;;;;;;;;; fonctions ;;;;;;;;;;;;;;;; ;;; Affichage du tableau de saisie ;; input ;hl = ptr début de la table à afficher ;; output ;table à l'écran ;; modifie: ;b, de, hl affichage_saisie: ld hl,ecran_saisie call affichage_col call affichage_col jr affichage_col ;optimisation : ret enlevé ;initialise les paramètres d'affichage affichage_init: ld e,(hl) ;x origine inc hl ld d,(hl) ;y origine inc hl ld c,(hl) ;dx ou dy (selon le cas ligne ou colonne) inc hl ld b,(hl) ;nb d'éléments inc hl ret ;affiche la colonne en cours affichage_col: call affichage_init boucle_affichage_col: ld (_penCol),de ld a,d add a,c ld d,a call _vputs djnz boucle_affichage_col ret ;affiche la ligne en cours affichage_ligne: call affichage_init boucle_affichage_ligne: ld (_penCol),de ld a,e add a,c ld e,a call _vputs djnz boucle_affichage_ligne ret ;;; Affichage_bilan ;; input ;hl = ptr début de la table à afficher ;; output ;table à l'écran ;; modifie: ;b, de, hl affichage_bilan: ;efface l'écran call _clrLCD call _runindicoff ;enlève la barre qui clignote en haut à droite de l'écran ;affiche la légende du tableau ld hl,bilan_ligne call affichage_ligne ;affiche le titre avec les unités ;affiche les valeurs des 4 colonnes ld ix,result_ptrs+1 ;pointeur vers les colonnes ld de,(bilan_col) ld b,4 ;nb de colonnes à afficher ld c,30 ;dx boucle_cols: ;protège bc et de push bc push de ;init déplacement en y ld c,8 ;dy ld b,nb_de_lignes ;nb_elem ;affiche la colonne courante ld l,(ix) inc ix ld h,(ix) inc ix call boucle_affichage_col ;modifie de ;récupère de et bc pop de pop bc ;passe à la col suivante ld a,e add a,c ;x=x+col_num*30 ld e,a djnz boucle_cols ;monte ou descend le texte avec les flèches ;quitte avec touche enter ou exit deroule: call _getkey ;a=code clavier cp kDown jr z,descend cp kUp jr z,monte cp kEnter ret z cp kExit ret z jr deroule ;si aucune de ces touches: attend une nouvelle touche descend: ;vérifie que le bas n'a pas déjà été atteint ld a,(result_ptrs) cp nb_de_compteurs-nb_de_lignes+1 ;nb de lignes descendues autorisées (+1 pour la ligne correspondant au bilan des leuco) jr z,deroule ;ne fait rien si c'est le cas ;descend inc a ld (result_ptrs),a ;indique qu'une ligne est descendue ld hl,result_ptrs+1 ;ld b,3 ld b,4 ;nb de colonnes à afficher boucle_descend: ld e,(hl) inc hl ld d,(hl) dec hl call valeur_suivante ;de pointe sur la valeur suivante ld (hl),e inc hl ld (hl),d inc hl djnz boucle_descend jr affichage_bilan monte: ;vérifie que le haut n'a pas déjà été atteint ld a,(result_ptrs) cp 0 jr z,deroule ;ne fait rien si c'est le cas ;monte dec a ld (result_ptrs),a ;indique qu'une ligne est montée ld hl,result_ptrs+1 ld b,4 ;nb de colonnes à afficher boucle_monte: ld e,(hl) inc hl ld d,(hl) dec hl call valeur_precedente ;de pointe sur la valeur suivante ld (hl),e inc hl ld (hl),d inc hl djnz boucle_monte jp affichage_bilan ;passe à la valeur suivante/précédente: ;modifie de, pour qu'il pointe sur le début de chaine suivante/précédente valeur_suivante: inc de ld a,(de) cp 0 jr nz,valeur_suivante inc de ret valeur_precedente: dec de dec de ld a,(de) cp 0 jr nz,valeur_precedente+1 inc de ret ;;; Prompt ;; input ;hl = ptr string ;; output ;OP1 = value prompt: ld de,_ioPrompt ;string storage for display when prompted call _mov10b ;move 10 bytes from (hl) to (de) call _mov10b ld a,$0d ;type of input - $0d=value - $0c = string ld (_ASAP_IND),a ;tell ti86 what kind to be inputted jp _exec_pg3 ;$ti86 os input routine of type ; (_asap_ind) with all ti-os key handler routines ;inputted value/string stored in op1 ;;; BCD to binary ;; input ;de: OP+2 in de ;;output ;hl ;;modifie ;a, b, de bcd2bin: ld hl,0 ld a,(de) ;exposant ld b,a inc b ;e0 = 1 nombre inc de ;passe le 2e octet d'exposant boucle_bcd: inc de ;octet suivant ld a,(de) ;récupère un octet (2 BCD) and $f0 ;ne garde que le 1er BCD position x16 rrca ;/2 rrca ;/4 rrca ;/8 rrca ;/16 call ajoute_bcd ;hl=10*hl+a dec b ret z ;quitte si nb fini ld a,(de) ;récupère même octet and $0f ;ne garde que le 2e BCD call ajoute_bcd djnz boucle_bcd ;octet suivant si non fini ret ;hl=10*hl+a ajoute_bcd: push bc add hl,hl ;*2 ld b,h ld c,l ;bc = hl add hl,hl ;*4 add hl,hl ;*8 add hl,bc ;*10 add a,l ;prepare le hl+a ld l,a adc a,h sub l ld h,a ;finalise hl+a pop bc ret ;;; demande une touche ;; entrée ;touche au clavier ;; sortie ;compteur incrémenté en mémoire ;; modifie ;a de hl compte_touche: push bc ;ld a,0 xor a ;a=0 ld (flag_leuco),a ;push hl touche: call _getkey ;a=code clavier ld bc,fin_clavier-clavier ld hl,clavier cpir ;décrémente bc et incrémente hl jusqu'à ce que a=(hl) ou bc=0 jr nz,touche ;la touche n'est pas supportée: redemande une autre touche ;converti c en pointeur positif ld a,fin_clavier-clavier sub c dec a ld c,a ;bc contient le n° d'élément de la touche ;incrémente le compteur correspondant push bc ;sauvegarde le n° pour plus tard ld h,b ld l,c ;hl=bc add hl,hl ;multiplie l'index par 2 (un nb = 2 octets) ld bc,cpt_deb ;début des compteurs add hl,bc ;hl pointe vers la bonne case call IncrementeCase ;incrémente compteur de catégorie pop bc ;récupère le n° ld hl,cpt_suite ;hl pointe vers la case leuco par défaut ld de,256*48+70 ;de= adresse de l'écran pour leuco ld a,c cp nb_de_compteurs-2 ;a-10 ? ex: a=12->carry=0 a=1->carry=1 jr c,leuco ;saute si c<10 ld a,1 ld (flag_leuco),a ;ld bc, (flag_leuco) ;ld a,1 ;ld (bc),a ;flag_leuco ld hl,cpt_suite+2 ;hl pointe vers la case erythro ld de,256*56+70 ;de= adresse de l'écran pour erythro leuco: call IncrementeCase ;bc=nouvelle valeur de la case ;affiche le contenu de la case leuco ou erythro qui a changé ld h,b ld l,c ;hl=bc ld (_penCol),de ;pour affichage avec _vputs ld de,str_tampon call Num2Dec ld hl,str_tampon-1 n0: inc hl ld a,(hl) cp '0' jr z,n0 ;enlève les 0 devant le nombre call _vputs ;affichage ;d817 ;(_penCol=$c37c)=endroit de l'écran hl=chaine de char finie pas $00 ;pop hl pop bc ld a,(flag_leuco) add a,b ld b,a ret nc inc c ret ;;;Incrémente le contenu d'une case ;;Entrée: hl = adresse de la case ;;Sortie: case incrémentée ;;modifie bc = valeur de la case incrémentée IncrementeCase: ld b,(hl) inc hl ld c,(hl) inc bc ;incrémente la case ld (hl),c dec hl ld (hl),b ret ;;;16-bit Integer to ASCII (decimal) ;;Input: HL = number to convert, DE = location of ASCII string ;;Output: ASCII string at (DE) ;;modify bc, de Num2Dec: ld bc,-10000 call Num1 ld bc,-1000 call Num1 ld bc,-100 call Num1 ld c,-10 call Num1 ld c,-1 Num1: ld a,'0'-1 Num2: inc a add hl,bc ;enlève 1000 à hl jr c,Num2 sbc hl,bc ;remet 1000 à hl (enlevé une fois de trop) ld (de),a inc de ret ;$DA56 ;;;OP1 to ASCII ;;Input: hl pointe vers OPn = number to convert, DE = location of ASCII string ;;Output: ASCII string at (DE) ;;modify a,b,de,hl OP2Dec: ld a,(hl) inc hl cp $80 ;negatif? jr nz,exp ld a,'-' ;nombre négatif ld (de),a inc de exp: ld b,(hl) inc hl ld a,(hl) inc hl cp $fc ;vérifie si l'exposant est négatif jr nc,exp_pos ;exp 1e-3 = 0.001 exp_neg: ld a,b xor $ff ;convertion en nombre positif moins un: 1e-3 = 0.001 : 2 zéros après la vigule ld b,a ;écrit "0." ld a,'0' ld (de),a inc de ld a,'.' ld (de),a inc de ;écrit "0000" si nécessaire ld c,1 ;pour charge_OP_nb ld a,b cp 0 jr z,decimale_deb ;pas de zéros supplémentaires nécessaires ld a,'0' zeros_apres_virgule: ld (de),a inc de djnz zeros_apres_virgule jr decimale_deb ;exp 1e3 = 1000 exp_pos: inc b ;1e3 = 1000 : 4 chiffres ;avant la virgule ld c,1 entier: call charge_OP_nb ld (de),a ;enregistre le caractère inc de djnz entier ;après la virgule ld a,(hl) and $0f jr z,fin_OP1 ld a,'.' ;ajoute la virgule ld (de),a inc de decimale_deb: ld b,nd_de_chiffres_apres_virgule decimale: call charge_OP_nb ld (de),a inc de djnz decimale ;arrondi: 1.016 -> 1.02 call charge_OP_nb ;regarde un chiffre de plus cp '5' jr c,fin_OP1 ;cas 1.015 -> 1.01 (ne fait rien de plus) push de call retenue cp $00 jr z,arrondi_fin inc a ld (de),a arrondi_fin: pop de fin_OP1: ;ajoute $00 (fin de chaine) xor a ;a=$00 ld (de),a inc de ret ;;;Vérifie et propage la retenue (lors de l'arrondi à 0.5) ;;Input: de = adresse vers la chaine de caractère à traiter ;;Output: chaine de caractère modifié à (de). Modifie de, a, b retenue: dec de ld a,(de) cp '.' jr nz,retenue_suite dec de ;ignore le '.' ld a,(de) retenue_suite: cp '9' ret nz ;pas de retenue ld a,'0' ;met le chiffre à zéro ld (de),a call retenue ;passe la retenue au chiffre supérieur cp $00 ;cas 9.998 -> 10.00 ret nz ex de,hl inc hl ld a,(hl) ld b,'1' decale_chiffre:;a:lecture, b:écriture ld (hl),b inc hl ld b,a ld a,(hl) cp $00 jr nz,decale_chiffre ex de,hl ret ;;;Un chiffre de OP1 en ASCII ;;Input: hl = number to convert, c = 1 ou 2 (1er ou 2e pos) ;;Output: a = nb en ASCII , c = nouvelle pos, hl incrémenté si besoin charge_OP_nb: ld a,(hl) dec c jr nz,second ld c,2 ;c'était le premier, le suivant sera le second dec hl ;contrecarre l'incrémentation en fin de fonction rrca rrca rrca rrca ;décale 4 bits vers la droite (/16) second: and $0f ;ne garde que le chiffre courant add a,'0' inc hl ret ;;;;;;;;;;;;;;;; données ;;;;;;;;;;;;;;;; nb_max_leuco: .db "Nb max Leuco:",0 ;N nb_leuco: .db "Nb Leuco (G/L):",0 ;L ecran_saisie: ;affichage par colonne .db 5, 0, 8 , 8 ; x, y, dy , nb_lignes .db "7:PN",0,"4:Ly",0,"1:mM",0,"0:Ea",0, .db "ENTER:Terminer",0,0,"Leucocytes",0,"Erythroblastes",0 .db 45, 0, 8 , 4 ; x, y, dy , nb_lignes .db "8:PE",0,"5:Mo",0,"2:M",0,".:Ep",0 .db 85, 0, 8 , 4 ; x, y, dy , nb_lignes .db "9:PB",0,"+:Mb",0,"3:pM",0,"-:Blaste",0 clavier: .db k7,k8,k9 .db k4,k5 .db k1,k2,k3,kAdd,kChs .db k0,kDecPnt ;ordre de stockage des compteurs fin_clavier: bilan_ligne: .db 5, 0, 30, 4 ; x, y, dx, nb_elem (affichage par ligne) .db "Cel",0,"Nb",0,"%",0,"G/L",0 bilan_col: .db 5, 8, 8, nb_de_lignes, 0 ; x, y, dy, nb_elem, fin (affichage par colonne) result_0: .db "PN",0,"PE",0,"PB",0,"Ly",0,"Mo",0,"mM",0,"M",0,"pM",0,"Mb",0,"Bl",0 ;.db "Leuco",0 .db "Leuco",0 .db "Ea",0,"Ep",0 ;.db "Attention: % de cel nuclees",0 ;.db "Fleches Haut/Bas pour defiler",0 cent: .db $00,$00,$fc,$02,$01 ;1e2=100 au_revoir: .db "Au revoir !",0 ;adresses après le programme pour stocker des données temporaires .org ($+255)&$ff00 ;démarre aux 255 bits entiers ($DA00) nbMaxLeuco: .org $+2 ;adr vers 2 octets (65536 max) binaire nb_nbMax .org $+11 ;bcd nb_nbLeuco .org $+11 ;bcd nb_100 .org $+11 ;bcd flag_leuco .org $+1 cpt_deb: .org $+32 ;tableau de 16 x 2 octets ;7:PN 8:PE 9:PB 4:Ly 5:Mo 1:mM 2:M 3:pM +:Mb -:Blaste 0:Ea .:Ep ;;12 cases cpt_suite: .org $+4 ;Nb Leuco Nb Erythro str_tampon: .org $+6 ;string pour afficher un nombre 16bits result_ptrs: .org $+10 ;nb_de_ligne_descendues,ptr0,ptr1,ptr2,ptr3 result_1: .org $+50 result_2: .org $+80 result_3: .org $+80 .end