;------------------------------------------------------------------------------------------
; [LIB_MATH] Copyright (c) 2007-2016. Vincent Bouffigny
;
; Copyright	Cette librairie va faire l'objet d'une publication en cours de rédaction et
;		ne peut donc être utilisée à des fins commerciales
;
; Auteur	Vincent Bouffigny
; Web		projet.infos.free.fr
;
; Informations  Développé sous WinAPE 2.0 alpha 13
;		Librairie de méthodes mathématiques utilisables directement dans vos programmes.
;		Deux types de méthodes sont disponibles, les méthodes avec opérations par sous-produits
;		et les méthodes par décalages de bits. LEs méthodes de calcul par sous-produits ne consomment
;		que les bits à 1 du multiplicateur et sont généralement plus rapides.
;
; Version	1.1 du 18/01/2016
;
; Modifications
;		1.1 de 18/01/2016
;
;			- Ajout de la méthode MATH_RRC_8, décalage de bits vers la droite avec ré-injection de carry à gauche
;			- Ajout de la méthode MATH_RLC_8, décalage de bits vers la gauche avec ré-injection de carry à droite
;
;		1.0 du 22/10/2007 - Version de lancement
;
; Travail en cours
;
;------------------------------------------------------------------------------------------
;	Informations
;		- Toutes les méthodes signalées par SP utilisent la pile pour passer les paramètres.
;		  Dans le cas contraire ce sont les registres qui sont utilisés
;		- Toutes les méthodes signalées par p utilisent un calcul par sous-produit.
;	Liste des méthodes
;
;	Version 1.1
;
;		MATH_RRC_8		Décalage de n bits vers la droite, carry est ré-injecté à gauche en cas de débordement
;		MATH_RLC_8		Décalage de n bits vers la gauche, carry est ré-injecté à droite en cas de débordement
;
;	Version 1.0
;
;		MATH_MUL_8x8		Multiplication de deux entiers de 8 bits
;		MATH_MUL_SP_8x8		Multiplication de deux entiers de 8 bits
;		MATH_MUL_SP_8x8p	Multiplication de deux entiers de 8 bits
;		MATH_MUL_16x8p		Multiplication de deux entiers de 16 par 8 bits
;		MATH_MUL_SP_16x8	Multiplication de deux entiers de 16 par 8 bits
;		MATH_MUL_SP_16x8p	Multiplication de deux entiers de 16 par 8 bits
;
;		MATH_DIV_8x8		Division d'un entier de 8 bits par un entier de 8 bits
;		MATH_DIV_SP_8x8		Division d'un entier de 8 bits par un entier de 8 bits
;		MATH_DIV_16x8		Division d'un entier de 16 bits par un entier de 8 bits
;		MATH_DIV_SP_16x8	Division d'un entier de 16 bits par un entier de 8 bits
;		MATH_DIV_16x16		Division d'un entier de 16 bits par un entier de 8 bits
;		MATH_DIV_SP_16x16	Division d'un entier de 16 bits par un entier de 16 bits
;
;		MATH_SLA_8		Décalage de n bits vers la gauche d'un entier de 8 bits
;		MATH_SLA_16		Décalage de n bits vers la gauche d'un entier de 16 bits
;		MATH_SRL_8		Décalage de n bits vers la droite d'un entier de 8 bits
;		MATH_SRL_16		Décalage de n bits vers la droite d'un entier de 16 bits
;
;------------------------------------------------------------------------------------------
NOLIST		; Ne pas affiche le code pendant la compilation
;ORG &4000	; Placement en mémoire &4000 après compilation
;RUN &4000	; Lancement automatique à l'adresse &4000






;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 8 bits
; avec un résultat sur 16 bits
;
; En entrée 
;	D  <=> Multiplicande (A)
;	E  <=> Multiplicateur (B)
; En sortie :
;	DE   Produit de A par B
; Registres affectés
;	DE
; Remarques
;	- Si A ou B = 0 => DE = 0 en sortie
;	
; 	- Exemple de méthode d'appel
;
;		LD D, 5
;		LD E, 2
;		CALL MATH_MUL_8x8
;		.
;

MATH_MUL_8x8:
		
	PUSH AF		; Sauvegarde des registres
	PUSH BC		;
	PUSH HL		;
	; Récupération des paramètres
	LD B, D		; Transfert des deux paramètres stockés dans DE, dans BC
	LD C, E		;

	; Initialisation des registres pour le calcul	
	LD HL, 0	; Valeur de retour
	LD A, B		; Transfert du multiplicande dans A
			; Le multiplicateur se trouve dans C

	; Vérification des valeurs en entrée
	OR A		; Test de A
			; Si A = 0 on sort
	JP z, _MATH_MUL_8x8_END
	LD L, A		; Sauvegarde de A pour le test de C
	LD A, C		; c est transféré dans A pour le test
	OR A		; Test de C via A
	LD A, L		; On restore A
	LD L, H		; On efface L via H
			; Si A(C) = 0 on sort
	JP z, _MATH_MUL_8x8_END

	; Début de code lié à la multiplication
	LD D, L		; D est effacer par L
	LD E, A		; Le multiplicande va dans E
	LD H, C		; Le multiplicateur va dans H
	LD B, 8		; Traitement des 8 bits
	
_MATH_MUL_8x8_1

	; Multiplication par 2 de HL (décalage d'1 bit vers le haut)
	ADD HL, HL
	JR nc, _MATH_MUL_8x8_2

	; Remplacement du bit de débordement par le multiplicateur
	ADD HL, DE	

_MATH_MUL_8x8_2

	DJNZ _MATH_MUL_8x8_1

_MATH_MUL_8x8_END
	
	EX HL,DE	; Récupération du résultat dans DE (à changer éventuellement)
	POP HL		; Restauration de registres
	POP BC		; 
	POP AF		;
	RET




;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 8 bits
; avec un résultat sur 16 bits
;
; En entrée :
;	[SP - 1]   Multiplicande (A)
;	[SP - 2]   Multiplicateur (B)
; En sortie :
;	DE   Produit de A par B
; Registres affectés
;	DE, les registres spécialisés
; Remarques
;	- Si A ou B = 0 => DE = 0 en sortie
;	- [SP - 1] et [SP - 2] sont dépilés
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;	
; 	- Exemple de méthode d'appel
;
;		LD B, 5
;		LD C, 2
;		PUSH BC
;		CALL MATH_MUL_SP_8x8
;		.
;

MATH_MUL_SP_8x8:

	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde de AF pour le retour

	; Récupération des paramètres
	POP HL		; Sauvegarde l'adresse de retour
	POP BC		; Récupération des deux paramètres
	PUSH HL		; Sauvegarde l'adresse de retour

	; Initialisation des registres pour le calcul	
	LD HL, 0	; Valeur de retour
	LD A, B		; Transfert du multiplicande dans A
			; Le multiplicateur se trouve dans C

	; Vérification des valeurs en entrée
	OR A		; Test de A
			; Si A = 0 on sort
	JP z, _MATH_MUL_SP_8x8_END
	LD L, A		; Sauvegarde de A pour le test de C
	LD A, C		; c est transféré dans A pour le test
	OR A		; Test de C via A
	LD A, L		; On restore A
	LD L, H		; On efface L via H
			; Si A(C) = 0 on sort
	JP z, _MATH_MUL_SP_8x8_END

	; Début de code lié à la multiplication
	LD D, L		; D est effacer par L
	LD E, A		; Le multiplicande va dans E
	LD H, C		; Le multiplicateur va dans H
	LD B, 8		; Traitement des 8 bits
	
_MATH_MUL_SP_8x8_1

	; Multiplication par 2 de HL (décalage d'1 bit vers le haut)
	ADD HL, HL
	JR nc, _MATH_MUL_SP_8x8_2

	; Remplacement du bit de débordement par le multiplicateur
	ADD HL, DE	

_MATH_MUL_SP_8x8_2

	DJNZ _MATH_MUL_SP_8x8_1

_MATH_MUL_SP_8x8_END

	PUSH HL		; Sauvegarde du résultat
	EXX		; Restauration des registres courant
	EX AF, AF'	; Restauration de AF
	POP DE		; Récupération du résultat dans DE (à changer éventuellement)
	RET




;***************************************************************
; Routine de multiplication par sous-produits de 2 entiers non 
; signés, de 8 bits avec un résultat sur 16 bits
;
; En entrée
;	[SP - 1] <=> Multiplicateur (A)
;	[SP - 2] <=> Multiplicande (C)
; En sortie
;	DE <=> Produit de C par A
; Registres affectés
;	DE et les registres spécialisés
; Remarques
;	- Si A ou C = 0 => DE = 0 en sortie
;	- [SP - 1] et [SP - 2]sont dépilés
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;	- Pour optimiser les calculs, vous pouvez vérifier que le
;	  multiplicateur est bien inférieur au multiplicande
;	  Plus le multiplicateur est petit plus l'opération est rapide
;

MATH_MUL_SP_8x8p:

	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde de AF

	POP HL		; Récupération de l'adresse de retour
	POP BC		; Récupération des deux paramètres
	PUSH HL		; Sauvegarde de l'adresse de retour

	; Initialisation des registres pour le test en entrée
	LD HL,0		; Valeur pour le retour
	LD A, B		; Le multiplicateur dans A

	; Vérification des valeurs en entrée
	OR A		; Test de A
			; Retour si A = 0
	JP z,_MATH_MUL_SP_8x8p_END
	LD L, A		; Sauvegarde de A pour le test de C (le multiplicande)
	LD A, C		; Transfert de B dans A pour le test
	OR A		; Test de C via A
	LD A, L		; On restore A
	LD L, H		; On efface L via H
			; Retour si A = 0
	JP z,_MATH_MUL_SP_8x8p_END

_MATH_MUL_SP_8x8p_1

	; Début du code lié à la multiplication
	LD D, L		; Le multiplicande est dans DE pour calculer les sous-produits
	LD E, C		; 

_MATH_MUL_SP_8x8p_2

	BIT 0, A	; Vérification si le bit 0 = 0, si oui
			; on ne cumule pas le sous-produit courant
	JP Z, _MATH_MUL_SP_8x8p_3
	ADD HL, DE	; Cumule du sous-produit courant

_MATH_MUL_SP_8x8p_3

	EX HL,DE	; Décalage du sous-produit courant
	ADD HL,HL	; de 1 bit vers le haut
	EX HL,DE	;
	SRL A 		; Décalage du multiplicateur de 1 bit
			; vers le bas
	OR A		; Vérification que tous les bits du
			; multiplicateur ont été traités
	JP nz, _MATH_MUL_SP_8x8p_2

_MATH_MUL_SP_8x8p_END

	PUSH HL		; Sauvegarde du résultat
	EXX		; Restauration des registres BC, DE, HL
	EX AF, AF'	; Restauration de AF
	POP DE		; Récupération du résultat dans DE
			; (Ou tout autre registre 16 bits)
	RET




;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 16 par
; 8 bits, avec un résultat sur 16 bits
;
; En entrée :
;	[SP - 2]   Multiplicande (DE)
;	[SP - 4]   Multiplicateur sur 8 bits (A)
; En sortie :
;	DE   Produit de DE par A (résultat sur 16 bits !)
; Registres affectés
;	DE et les registres spécialisés
; Remarques
;	- Si A ou DE = 0 => DE = 0 en sortie
;	- [SP - 2] et [SP - 4] sont dépilés
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;

MATH_MUL_SP_16x8:
	
	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde de AF

	; Récupération des paramètres
	POP HL		; Récupération de l'adresse de retour
	POP AF		; Récupération de [SP - 4] <=> Multiplicateur
			; Le multiplicateur va se retrouvé dans A
	POP DE		; Récupération du multiplicande
	PUSH HL		; Préservation de l'adresse de retour

	; Initialisation des registres
	LD HL, 0	; Valeur de retour

	; Vérification des valeurs d'entrée
	OR A		; Si A = 0 on sort
	JP z, _MATH_MUL_SP_16x8_END
	ADC HL, DE	; Ajout de DE à HL de manière à vérifier si DE = 0
			; Si DE = 0 => z = 1
	JP z, _MATH_MUL_SP_16x8_END

	; Début du code lié à la multiplication
	LD HL, 0	; Valeur de retour
	LD B, 8		; Traitement des 8 bits

_MATH_MUL_SP_16x8_1

	; Multiplication par 2 de HL (décalage d'1 bit vers le haut)
	ADD HL, HL
	ADD A, A
	JR nc, _MATH_MUL_SP_16x8_2

	; Remplacement du bit de débordement par le multiplicateur
	ADD HL, DE	

_MATH_MUL_SP_16x8_2

	DJNZ _MATH_MUL_SP_16x8_1

_MATH_MUL_SP_16x8_END

	PUSH HL		; Sauvegarde du résultat
	EXX		; Restauration des registres courant BC, DE, HL
	EX  AF, AF'	; Restauration de AF
	POP DE		; Récupération du résultat dans DE (Au tout autre registre 16 bits)
	RET



;***************************************************************
; Routine de multiplication de 2 entiers non signés, de 16 par
; 8 bits, avec un résultat sur 16 bits
;
; En entrée
;	DE <=> Multiplicande sur 16 bits
;	A  <=> Multiplicateur sur 8 bits
; En sortie
;	DE <=> Produit de DE par A (résultat sur 16 bits !)
; Registres affectés
;	DE
; Remarques
;	- Si le multiplicande ou le diviseur = 0 => DE = 0 en retour
;	- Pour optimiser les calculs, vous pouvez vérifier que le
;	  multiplicateur est bien inférieur au multiplicande
;

MATH_MUL_16x8p:

	PUSH AF		; Sauvegarde des registres
	PUSH HL		; 
	LD HL, 0	; Mise à blanc de HL pour le retour

	; Vérification des valeurs en entrée
	OR A		; Si A = 0 on sort
	JP z, _MATH_MUL_16x8p_END

	ADC HL, DE	; Si DE = 0 on sort
	JP z, _MATH_MUL_16x8p_END

	; Début du code lié à la multiplication
	LD HL, 0

_MATH_MUL_16x8p_1

	BIT 0, A	; Vérification si le bit 0 = 0, si oui
			; on ne cumule pas le sous-produit courant
	JP z, _MATH_MUL_16x8p_3
	ADD HL, DE	; Cumule du sous-produit courant

_MATH_MUL_16x8p_3

	EX HL, DE	; Décalage du sous-produit courant
	ADD HL, HL	; de 1 bit vers le haut
	EX HL, DE	;
	SRL A 		; Décalage du multiplicateur de 1 bit
			; vers le bas
	OR A		; Vérification que tous les bits du
			; multiplicateur ont été traités

	JP nz, _MATH_MUL_16x8p_1

_MATH_MUL_16x8p_END

	EX HL, DE	; Résultat dans DE
	POP HL		; Restauration des registres
	POP AF		; 
	RET


;***************************************************************
; Routine de multiplication par sous-produits de 2 entiers 
; non signés, de 16 par 8 bits, avec un résultat sur 16 bits
;
; En entrée
;	[SP - 2] <=> Multiplicande (DE)
;	[SP - 4] <=> Multiplicateur (A)
; En sortie
;	DE <=> Produit de DE x A (résultat sur 16 bits !)
; Registres affectés
;	DE et les registres spécialisés
; Remarques
;	- Si De ou A = 0 => DE = 0 en sortie
;	- [SP - 2] et [SP - 4] sont dépilés
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- Pour optimiser les calculs, vous pouvez vérifier que le
;	  multiplicateur est bien inférieur au multiplicande
;

MATH_MUL_SP_16x8p:

	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde du registre AF

	POP HL		; Récupération de l'adresse de retour
	POP AF		; Récupération du multiplicateur 8 bits dans A
	POP DE		; Récupération du multiplicande sur 16 bits
	PUSH HL		; Sauvegarde de l'adresse de retour

	LD HL,0		; Mise à blanc de HL pour le retour

	;Vérification des valeurs en entrée
	OR A		; Si A = 0 on sort
	JP z, _MATH_MUL_SP_16x8p_END
	ADC HL, DE	; Si DE = 0 on sort
	JP z, _MATH_MUL_SP_16x8p_END

	; Début du code lié à la multiplication
	LD HL, 0

_MATH_MUL_SP_16x8p_1

	BIT 0, A	; Vérification si le bit 0 = 0, si oui
			; on ne cumule pas le sous-produit courant
	JP z, _MATH_MUL_SP_16x8p_3
	ADD HL, DE	; Cumule du sous-produit courant

_MATH_MUL_SP_16x8p_3

	EX HL,DE	; Décalage du sous-produit courant
	ADD HL,HL	; de 1 bit vers le haut
	EX HL,DE	;
	SRL A 		; Décalage du multiplicateur de 1 bit
			; vers le bas
	OR A		; Vérification que tous les bits du
			; multiplicateur ont été traités
	JP nz, _MATH_MUL_SP_16x8p_1

_MATH_MUL_SP_16x8p_END

	PUSH HL		; Préservation du résultat
	EXX		; Restauration des registres courants BC, DE, HL
	EX AF, AF'	; Restauration de AF
	POP DE		; Récupération du résultat dans DE (ou tout autre registre sur 16 bits)
	RET





;***************************************************************
; Routine de division par sous-produits de 2 entiers non signés
; de 8 bits, avec un résultat sur 8 bits
;
; En entrée
;	D <=> Le dividende sur 8 bits
;	E <=> Le diviseur sur 8 bits
; En sortie
;	D <=> Quotient
;	E <=> Reste de la division entière
; Registres affectés
;	DE
; Remarques
;	- Si le dividende ou le diviseur = 0 en entrée => Le quotient et le reste = 0 en retour
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;

MATH_DIV_8x8:

	PUSH AF		; Sauvegarde des registres
	PUSH BC		;

	; Valeur de retour par défaut
	LD DE, 0

	; Test des valeurs en entrée
	LD A, B		; Test du dividende
	OR A		; Si le dividende = 0 on sort
	JP z, _MATH_DIV_8x8_END
	LD A, C 	; Test du diviseur
	OR A		; Si le diviseur = 0 on sort
	JP z, _MATH_DIV_8x8_END
	
	; Initialisation des registres
	LD D, B
	LD E, C
	LD B, 8	; Les 8 bits du dividende sont traités
	XOR A, A
	
_MATH_DIV_8x8_1

	SLA D	; Décalage du bit le plus haut, du dividende dans Carry
	RLA	; Récupération de Carry dans le sous-dividende (A)
		; (création du sous dividende)
	CP E	; Vérification si le sous-dividende est >= au diviseur.
		; Si oui le quotient = + 1, sinon on traite le bit suivant, du dividende
	JR c, _MATH_DIV_8x8_2
	INC D	; Incrémentation du quotient. Sachant que les bits de D
		; sortent vers le haut (la gauche), les bits du bas vont
		; servir pour stocker le quotient
	SUB E	; On soustrait le diviseur du dividende
	
_MATH_DIV_8x8_2

	DJNZ _MATH_DIV_8x8_1 ; Décrémentation de B de manière à
				; traiter les 8 bits du dividende

	LD E, A		; Récupération du reste dans E
			; La quotient se trouve dans D	

_MATH_DIV_8x8_END

	POP BC		; Restauration des registres
	POP AF		;
	RET




;***************************************************************
; Routine de division par sous-produits de 2 entiers non signés
; de 8 bits, avec un résultat sur 8 bits
;
; En entrée
;	[SP - 2] <=> Les deux paramètres D (le dividende) et E (le diviseur)
; En sortie
;	D <=> Quotient
;	E <=> Reste de la division entière
; Registres affectés
;	DE et les registres spécialisés
; Remarques
;	- Si le dividende ou le diviseur = 0 en entrée => Le quotient et le reste = 0 en retour
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;

MATH_DIV_SP_8x8:

	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde de registre AF

	POP HL		; Récupération des l'adresse de retour
	POP BC		; Récupération des deux paramètres D et E
	PUSH HL		; Préservation de l'adresse de retour

	; Valeur de retour par défaut
	LD DE, 0

	; Test des valeurs en entrée
	LD A, B		; Test du dividende
	OR A		; Si le dividende = 0 on sort
	JP z, _MATH_DIV_SP_8x8_END
	LD A, C 	; Test du diviseur
	OR A		; Si le diviseur = 0 on sort
	JP z, _MATH_DIV_SP_8x8_END
	
	; Initialisation des registres
	LD D, B
	LD E, C
	LD B, 8	; Les 8 bits du dividende sont traités
	XOR A, A
	
_MATH_DIV_SP_8x8_1

	SLA D	; Décalage du bit le plus haut, du dividende dans Carry
	RLA	; Récupération de Carry dans le sous-dividende (A)
		; (création du sous dividende)
	CP E	; Vérification si le sous-dividende est >= au diviseur.
		; Si oui le quotient = + 1, sinon on traite le bit suivant, du dividende
	JR c, _MATH_DIV_SP_8x8_2
	INC D	; Incrémentation du quotient. Sachant que les bits de D
		; sortent vers le haut (la gauche), les bits du bas vont
		; servir pour stocker le quotient
	SUB E	; On soustrait le diviseur du dividende
	
_MATH_DIV_SP_8x8_2

	DJNZ _MATH_DIV_SP_8x8_1 ; Décrémentation de B de manière à
				; traiter les 8 bits du dividende

	LD E, A		; Récupération du reste dans E
			; La quotient se trouve dans D	

_MATH_DIV_SP_8x8_END

	PUSH DE		; Préservation du résultat dans DE
	EXX		; Restauration des registres BC, DE, HL
	EX AF, AF'	; Restauration du registre AF
	POP DE		; Récupération du quotient et du reste dans DE (ou tout autre registre 16 bits)
	RET






;***************************************************************
; Routine de division d'un entier non signé de 16 bits par un
; entier non signé de 8 bits, avec un résultat sur 16 bits
;
; En entrée
;	DE <=> Dividende sur 16 bits
;	A  <=> Diviseur sur 8 bits
; En sortie
;	DE <=> Quotient (sur 16 bits)
;	A  <=> Reste de la division entière (8 bits)
; Registres affectés
;	DE, A et F
; Remarques
;	- Si le dividende ou le diviseur = 0 => DE = 0 et A = 0 en retour
;

MATH_DIV_16x8:

	PUSH BC		; Sauvegarde des registres
	PUSH HL		;

	LD H, D		; Transfert du dividende dans HL
	LD L, E		;

	; Test des valeurs en entrée
	LD A, B
	OR A
	JP nz, _MATH_DIV_16x8_1
	LD H, A
	LD L, A
	JP _MATH_DIV_16x8_END

_MATH_DIV_16x8_1
	
	LD C, B		; Stockage du diviseur dans C
	LD B, 16	; Les 16 bits de HL (le dividende) vont être traités
	XOR A, A	; On efface A pour initialiser le sous-dividende

_MATH_DIV_16x8_2

	SLA L	; Décalage du bit le plus haut, du dividende dans Carry
	RL H
	RLA	; Récupération de Carry dans le sous-dividende (A)
		; (création du sous dividende)
	CP C	; Vérification si le sous-dividende est supérieur ou
		; égal au diviseur. Si oui le quotient = + 1, sinon on
		; traite le bit suivant, du dividende
	JR c, _MATH_DIV_16x8_3
	INC HL	; Incrémentation du quotient (sachant que tous les bits
		; de HL sont décalé vers le haut (la gauche), les bits
		; venant du bas vont servir pour stocker le quotient
	SUB C	; On soustrait le diviseur du dividende
	
_MATH_DIV_16x8_3

	DJNZ _MATH_DIV_16x8_2 ; Décrémentation de B de manière à
			   	 ; traiter les 16 bits du dividende

_MATH_DIV_16x8_END

	EX HL, DE
	POP HL		; Restauration des registres
	POP BC		;
	RET



;***************************************************************
; Routine de division par sous-produit d'un entier non signé de 
; 16 bits par un entier non signé de 8 bits, avec un résultat sur 16 bits
;
; En entrée
;	[SP - 2] <=> Dividende, transféré dans HL
;	[SP - 4] <=> Diviseur, transféré dans B (8 bits de la partie haute de [SP - 4])
; En sortie
;	DE <=> Quotient (sur 16 bits)
;	A  <=> Reste de la division entière (8 bits)
; Registres affectés
;	A, DE et les registres spécialisés
; Remarques
;	- [SP - 2] et [SP - 4] sont dépilés
;	- Vous pouvez utiliser n'importe quel registre 16 bits en sortie
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;

MATH_DIV_SP_16x8:

	EXX		; Préservation des registre BC, DE, HL
	EX AF, AF'	; Préservation de AF

	POP DE		; Récupération de l'adresse de retour
	POP BC		; Récupération du diviseur dans B (partie haute à l'adresse [SP - 3])
	POP HL		; Récupération du dividende
	PUSH DE		; Sauvegarde de l'adresse de retour

	; Test des valeurs en entrée
	LD A, B
	OR A
	JP nz, _MATH_DIV_SP_16x8_1
	LD H, A
	LD L, A
	JP _MATH_DIV_SP_16x8_END

_MATH_DIV_SP_16x8_1
	
	LD C, B		; Stockage du diviseur dans C
	LD B, 16	; Les 16 bits de HL (le dividende) vont être traités
	XOR A, A	; On efface A pour initialiser le sous-dividende

_MATH_DIV_SP_16x8_2

	SLA L	; Décalage du bit le plus haut, du dividende dans Carry
	RL H
	RLA	; Récupération de Carry dans le sous-dividende (A)
		; (création du sous dividende)
	CP C	; Vérification si le sous-dividende est supérieur ou
		; égal au diviseur. Si oui le quotient = + 1, sinon on
		; traite le bit suivant, du dividende
	JR c, _MATH_DIV_SP_16x8_3
	INC HL	; Incrémentation du quotient (sachant que tous les bits
		; de HL sont décalé vers le haut (la gauche), les bits
		; venant du bas vont servir pour stocker le quotient
	SUB C	; On soustrait le diviseur du dividende
	
_MATH_DIV_SP_16x8_3

	DJNZ _MATH_DIV_SP_16x8_2
				 ; Décrémentation de B de manière à
			   	 ; traiter les 16 bits du dividende

_MATH_DIV_SP_16x8_END

	PUSH HL		; Sauvegarde du quotient sur la pile, le reste se trouve dans A
	EXX		; Restauration des registres BC, DE, HL
	LD D, A		; Sauvegarde du reste de l'opération dans A
	EX AF, AF'	; Restauration de F
	LD A, D		; A contient le reste de la division entière
	POP DE		; Récupération du résultat dans DE
			; (ou tout autre registre 16 bits)
	RET





;***************************************************************
; Routine de division par sous-produits d'un entier non signé 
; de 16 bits par un entier non signé de 16 bits, avec un résultat sur 16 bits
;
;En entrée
;	BC <=> Dividende sur 16 bits
;	DE <=> Diviseur sur 16 bits
;En sortie
;	DE <=> Quotient
;	BC <=> Reste de la division entière (sur 16 bits)
;Registres affectés
;	BC, DE
; Remarques
;	- Les registres DE et BC en sortie peuvent être remplacés par d'autres registres 16 bits
;

MATH_DIV_16x16:

	PUSH AF		; Sauvegarde des registres
	PUSH HL

	; Vérification des valeurs en entrée
	LD HL, 0	
	ADC HL, DE	; Si DE = 0 on sort
	JP nz, _MATH_DIV_16x16_1
	XOR A, A	; On efface A pour le retour
	LD C, A		; On efface C pour le retour
	JP _MATH_DIV_16x16_END

_MATH_DIV_16x16_1

	LD HL, 0	; Servira de sous-dividende
	LD A, B		; Stockage de la partie haute du dividende dans B
	LD B, 16	; Les 16 bits de HL (le dividende) vont être traités

_MATH_DIV_16x16_2

	SLA C		; Décalage du bit le plus haut de la partie basse du 
			; dividende, dans Carry
	RLA		; Récupération de Carry dans la partie haute du dividende
			; Et décalage de la partie haute du dividende dans Carry
	ADC HL, HL 	; Récupération éventuelle de Carry et création par la
		  	; même occasion du sous-dividende
	SBC HL, DE 	; On enlève le diviseur du sous-dividende, si Carry est
		  	; allumé c'est que le sous-dividende est inférieur
	JR c, _MATH_DIV_16x16_3
	INC C		; Incrémentation de C de manière à crée le quotient
			; (Remplacement des bits du dividende par le quotient)
	DJNZ _MATH_DIV_16x16_2
			; Décrémentation de B de manière à traiter les 16 bits du dividende

	JP _MATH_DIV_16x16_END

_MATH_DIV_16x16_3
	
	ADD HL, DE 	; Restauration du sous-dividende car celui-ci est 
		   	; inférieur au diviseur
	DJNZ _MATH_DIV_16x16_2 ; Décrémentation de B de manière à
			    	  ; traiter les 16 bits du dividende
_MATH_DIV_16x16_END

	LD B, A		; Partie haute du quotient dans B
			; La partie basse se trouve déjà dans C
	POP HL		; Restauration des registres
	POP AF		;
	RET




;***************************************************************
; Routine de division par sous-produits d'un entier non signé 
; de 16 bits par un entier non signé de 16 bits, avec un résultat sur 16 bits
;
;En entrée
;	[SP - 2] <=> Dividende transféré dans BC
;	[SP - 4] <=> Diviseur transféré dans DE
;En sortie
;	DE <=> Quotient
;	BC <=> Reste de la division entière (sur 16 bits)
;Registres affectés
;	BC, DE et les registres spécialisés
; Remarques
;	- [SP - 2] et [SP - 4] sont dépilés
;	- Les registres DE et BC en sortie peuvent être remplacés par d'autres registres 16 bits
;	- BF' est détruit en sortie, ce registre est utilisé pour stocker un vecteur par le sytème CPC
;

MATH_DIV_SP_16x16:

	EXX		; Sauvegarde des registres BC, DE, HL
	EX AF, AF'	; Sauvegarde de AF

	POP HL		; Récupération de l'adresse de retour
	POP DE		; Récupération du diviseur
	POP BC		; Récupération du dividende
	PUSH HL		; Préservation de l'adresse de retour

	; Vérification des valeurs en entrée
	LD HL, 0	
	ADC HL, DE	; Si DE = 0 on sort
	JP nz, _MATH_DIV_SP_16x16_1
	XOR A, A	; On efface A pour le retour
	LD C, A		; On efface C pour le retour
	JP _MATH_DIV_SP_16x16_END

_MATH_DIV_SP_16x16_1

	LD HL, 0	; Servira de sous-dividende
	LD A, B		; Stockage de la partie haute du dividende dans B
	LD B, 16	; Les 16 bits de HL (le dividende) vont être traités

_MATH_DIV_SP_16x16_2

	SLA C		; Décalage du bit le plus haut de la partie basse du 
			; dividende, dans Carry
	RLA		; Récupération de Carry dans la partie haute du dividende
			; Et décalage de la partie haute du dividende dans Carry
	ADC HL, HL 	; Récupération éventuelle de Carry et création par la
		  	; même occasion du sous-dividende
	SBC HL, DE 	; On enlève le diviseur du sous-dividende, si Carry est
		  	; allumé c'est que le sous-dividende est inférieur
	JR c, _MATH_DIV_SP_16x16_3
	INC C		; Incrémentation de C de manière à crée le quotient
			; (Remplacement des bits du dividende par le quotient)
	DJNZ _MATH_DIV_SP_16x16_2
			; Décrémentation de B de manière à traiter les 16 bits du dividende

	JP _MATH_DIV_SP_16x16_END

_MATH_DIV_SP_16x16_3
	
	ADD HL, DE 	; Restauration du sous-dividende car celui-ci est 
		   	; inférieur au diviseur
	DJNZ _MATH_DIV_SP_16x16_2 ; Décrémentation de B de manière à
			    	  ; traiter les 16 bits du dividende
_MATH_DIV_SP_16x16_END

	LD B, A		; Partie haute du quotient dans B
			; La partie basse se trouve déjà dans C
	PUSH BC		; Préservation du quotient
	PUSH HL		; Préservation du reste de la division
    	EXX		; Restauration des registres BC, DE, HL
	EX AF, AF'	; Restauration de AF
	POP BC		; Récupération du reste dans BC
	POP DE		; Récupération du quotient dans DE
	RET



;***************************************************************
; Routine de décalage vers la gauche d'un entier de 8 bits
;
; En entrée
;	E  <=> Entier de 8 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	E <=> Résultat du décalage des n bits
; Registres affectés
;	F,E
; Remarques
;

MATH_SLA_8:

	OR A		; Si A = 0 on sort
	JP z, _MATH_SLA_8_END
	PUSH BC		; Sauvegarde de BC pour le retour
	LD B, A		; B va contenir le nombre d'itération

_MATH_SLA_8_1

	SLA E
	DJNZ _MATH_SLA_8_1
	POP BC
	
_MATH_SLA_8_END

	RET



;***************************************************************
; Routine de décalage vers la gauche d'un entier de 16 bits
;
; En entrée
;	DE <=> Entier de 16 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	DE <=> Résultat du décalage des n bits
; Registres affectés
;	F, DE
; Remarques
;	- Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_SLA_16:

	OR A		; Si A = 0 on sort
	JP z, _MATH_SLA_16_END
	PUSH BC		; Sauvegarde de BC pour le retour
	LD B, A		; B va contenir le nombre de décalages
	LD C, A		; Sauvegarde de A
	LD A, D

_MATH_SLA_16_1

	SLA E
	RLA
	DJNZ _MATH_SLA_16_1
	LD D, A		; Partie haute du résultat dans D, E contient déjà la partie basse
	LD A, C		; Restauration de A
	POP BC		; Restauration de BC

_MATH_SLA_16_END

	RET



;***************************************************************
; Routine de décalage vers la droite d'un entier de 8 bits
;
; En entrée
;	E  <=> Entier de 8 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	E <=> Résultat du décalage des n bits
; Registres affectés
;	F, E
; Remarques
;	- Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_SRL_8:

	OR A		; Si A = 0 on sort
	JP z, _MATH_SRL_8_END
	PUSH BC		; Sauvegarde de BC
	LD B, A		; Le nombre d'itération est transféré dans B pour le décompte

_MATH_SRL_8_1

	SRL E		; Rotation
	DJNZ _MATH_SRL_8_1
	POP BC		; Restauration de BC

_MATH_SRL_8_END

	RET



;***************************************************************
; Routine de décalage vers la droite d'un entier de 16 bits
;
; En entrée
;	DE <=> Entier de 16 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	DE <=> Résultat du décalage des n bits
; Registres affectés
;	F, DE
; Remarques
;	- Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_SRL_16:

	OR A		; Si A = 0 on sort
	JP z, _MATH_SRL_16_END
	PUSH BC		; Sauvegarde de BC pour le retour
	LD B, A		; B va contenir le nombre de décalages
	LD C, A		; Sauvegarde de A
	LD A, E		; Partie basse de DE dans A

_MATH_SRL_16_1

	SRL D
	RRA
	DJNZ _MATH_SRL_16_1
	LD E, A		; Résultat de la partie basse dans E, D contient la partie haute
	LD A, C		; Restauration de A
	POP BC		; Restauration de BC

_MATH_SRL_16_END

	RET



;***************************************************************
; Routine de décalage vers la droite d'un entier de 8 bits
; carry est ré-injecté vers la gauche
;
; En entrée
;	E  <=> Entier de 8 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	E <=> Résultat du décalage des n bits
; Registres affectés
;	F, E
; Remarques
;	- Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_RRC_8:

	OR A		; Si A = 0 on sort
	JP z, _MATH_RRC_8_END
	PUSH BC		; Sauvegarde de BC pour le retour
	LD B, A		; Le nombre d'itération est transféré dans B pour le décompte
	LD C, A		; Sauvegarde de A
	LD A, E		; Valeur à décaler

_MATH_RRC_8_1

	RRCA
	DJNZ _MATH_RRC_8_1
	LD E, A		; Transfert du résultat dans E
	LD A, C		; Restauration de A
	POP BC		; Restauration de BC

_MATH_RRC_8_END

	RET



;***************************************************************
; Routine de décalage vers la gauche d'un entier de 8 bits
; carry est ré-injecté vers la droite
;
; En entrée
;	E  <=> Entier de 8 bits
;	A  <=> Nombre de bits à décaler
; En sortie
;	E <=> Résultat du décalage des n bits
; Registres affectés
;	F, E
; Remarques
;	- Cette fonction n'utilise pas la pile pour le passage de paramètres
;

MATH_RLC_8:

	OR A		; Si A = 0 on sort
	JP z, _MATH_RLC_8_END
	PUSH BC		; Sauvegarde de BC pour le retour
	LD B, A		; Le nombre d'itération est transféré dans B pour le décompte

_MATH_RLC_8_1

	RLC E
	DJNZ _MATH_RLC_8_1
	POP BC		; Restauration de BC

_MATH_RLC_8_END

	RET











