Bonsoir à tous,
Ce n'est pas que l'arithmétique 8 bits, même signée soit d'un grand intérêt. Je n'ai trouvé qu'une utilisation dans la conversion Celcius Farhenheit qui exige une multiplication par 9/5 et une addition sur des nombres signés (et oui, il peut faire froid). Encore faut-il pouvoir se contenter de la précision du degré et ne pas dépasser 52° celcius (53 converti en farhenheit c'est plus que 127 et 8 bits ne suffisent plus)
Je propose ci dessous un programme qui, sous le simulateur MPLABSIM, vous permet de tester toutes les opérations décrites plus loin.
Une fenêtre watch où on met les variables à observer, une exécution pas à pas et bon courage. Par curiosité, changez de pic d'une exécution à l'autre pour constater que les seules lignes à modifier sont les deux lignes définissant le pic mis en oeuvre. Pour l'instant, seuls les mid-range marchent, mais avec les infos reçues cet AM, je ne désespère pas propose le même programme pour les extended mid-range, en ne touchant qu'aux macros de gestion de banque.
► Afficher le texte
Code : Tout sélectionner
;*****************************************************************************
; Test_A8BS
; teste le module A8BS
; date création : 07/04/2019
; auteur : JJE
; description :
;*****************************************************************************
; *
; Fichier requis: P16F884.inc *
; *
; *
; *
;*****************************************************************************
LIST p=16F884 ; Définition de processeur
__CONFIG _CONFIG1, _INTOSCIO & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _DEBUG_OFF & _CP_OFF & _CPD_OFF
; XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN
; WDT disabled and can be enabled by SWDTEN bit of the WDTCON register end
; PWRT disabled
; BOR disabled
; RB3 pin has digital I/O, HV on MCLR must be used for programming
; In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
; Program memory code protection is disabled
; Data memory code protection is disabled
__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
; Write protection off
LIST x = ON,w = 0, st = ON
NbPages EQU 4
include "M:/Callx/callx.inc"
include "A8BS.inc"
errorlevel -302
;******************************************************************
; valeurs initiales des registres spéciaux
; valeur initiale de OPTIONREG
OPTIONVAL EQU B'00000001' ; bit 7 = 0 : PORTB pull-ups
; disabled
; bit 6 = 0 : sans objet
; bit 5 = 0 : internal cycle clock
; bit 4 = 0 : sans objet
; bit 3 = 0 : prescaler is assigned
; to TIMER0 module
; bit 2-0=001 : prescaler rate 1:4
; cf page 31 du DataSheet
; valeur initiale de OSCON
OSCONVAL EQU B'01101001' ; bit 7 = 0 sans objet
; bits 6-4 = 110 : 4MH
; bits 3-1 sans objets
; bit 0 = 1 Internal oscilateur used
; cf page 64 du DataSheet
; valeur initiale de TRISA
TRISAVAL EQU 0x00 ; tous les ports en sortie
ANSELVAL EQU 0x00 ; pas d'entrée analogique
; valeur initiale de TRISA
TRISBVAL EQU 0x01 ; tous les ports en sortie sauf RB0
WPUBVAL EQU 0x07 ; Pull-up enable sur RB0 à RB2
IOCBVAL EQU 0x01 ; ITOC active sur RB0
INTCONVAL EQU B'11000000' ; bit 7 = 1 : Enables unmasked
; interrupts
; bit 6 = 1 : Enables all
; peripheral interrupts
; bit 5 = 0 : disables TMR0 IT
; bit 4 = 0 : disables PORTB IT
; change
; change interrupt
; bit 3-0 = 0 sans objet
; cf page 32 du DataSheet
;******************************************************************
CBLOCK 0x20
w_temp : 1
status_temp : 1
A0_1 : 1
A0_2 : 1
REP0 : 1
endc
A8BS_VAR
CBLOCK 0xA0
A1_1 : 1
A1_2 : 1
REP1 : 1
endc
CBLOCK 0x120
A2_1 : 1
A2_2 : 1
REP2 : 1
endc
ORG 0
goto init
init
; sur le modèle des lignes suivantes
; laisser aller son imagination, éventuellement
; en ajoutant des variables
movlw -.3
movwf A0_1
movlw -.5
movwf A0_2
A8BS_ADDV A0_1, A0_2, REP0
nop
goto $
A8BS_CODE A8BS_METTOUT
END
Je sais bien qu'il ne fait rien ce programme, mais potentiellement, il peut faire n'importe quoi en arithmétique 8 bits signés. en un peu plus de 100 lignes
Bien sûr il y a des accessoires, qui sont introduits dans le code par quelques lignes (3) qui seront interprétées par l'assembleur :
La première (ligne 35)
informe l'assembleur du chemin du fichier contenant les informations du module
La deuxième (ligne 85)
invoque une macro qui va déclarer les variables nécessaires au module. Elle se développe en quelque chose comme :
les variables nécessaires au module sont donc en mémoire à l'adresse où a été écrite l'invocation de la macro A8BS_VAR.
Rien, n'interdit bien sûr de forcer une position particulière. si vous souhaitez qu'elles soient en début de la banque 1, il suffit de faire précéder l'invocation de la macro de :
J'ai préféré cette manière de faire à la mise en oeuvre d'un paramètre à la macro car je ne sais pas gérer des paramètres optionnels et bien souvent on n'a aucune raison de positionner les variables du module à un endroit particulier de la mémoire. Une seule contrainte, Les variables du module doivent être dans la même banque mais un test est fait qui signale le problème et sort l'assembleur en erreur. Il ne reste plus qu'à déplacer l'invocation.
La troisième (ligne 112)
C'est encore une macro dont l'invocation introduit le code du module. Ici, comme il est possible qu'on n'ait pas besoin de toutes les fonctionnalités, elle exige un paramètre précisant ce dont on a besoin, ici tout le code. Le module définit 5 valeurs
Code : Tout sélectionner
A8BS_METADD EQU 1
A8BS_METSUB EQU 2
A8BS_METMULT EQU 4
A8BS_METDIV EQU 8
A8BS_METTOUT EQU A8BS_METADD + A8BS_METSUB + A8BS_METMULT + A8BS_METDIV
dont les noms suffisent à informer de leur fonction.
Ces trois lignes étant insérées (l'endroit où elle le sont est important), il est possible d'utiliser les fonctionnalités retenues de ce module, par exemple par
Code : Tout sélectionner
movlw -.3
movwf A0_1
movlw -.5
movwf A0_2
A8BS_ADDV A0_1, A0_2, REP0
nop
le programme initialise deux de ses variables et invoque la macro A8BS_ADD. à l'instruction nop qui suit, la variable REP0 contiendra la valeur -8 (0xf8). Par curiosité, vous pouvez déplacer chacune de ces variables dans la banque e votre choix, charge à vous de les gérer, l'invocation de la macro A8BS_ADD n'aura aucunement à être modifiée
Une remarque notable est que ce programme test est opérationnel sur tous les pics mid-range
J'ai découvert récemment les pics extended mid_range auxquels je ne m'étais pas encore intéressé. Il me semble que dans ce module, seuls les changements de banque sont incompatibles entre les deux familles. Je ne désespère pas d'écrire des macros de changement de banque compatibles (au niveau du source) pour les deux.
Parlons un peu du fichier A8BS (pour Arithmétique 8 Buts Signés) que voici:
► Afficher le texte
Code : Tout sélectionner
; Module A8BS
; date création : 07/04/2019
; auteur : JJE
; description :
; incorpore les routines d'arithmétique 8 bits signés
; ressources utilisées
; 6 octets de données locales libérées entre deux appels
; 133 instructions dans la version complète
; 22 si addition seule
; 34 si soustraction qui exige l'addition
; 46 si multiplication seule
; (incorpore la multiplication non signée)
; 53 si division seule
; (incorpore la division non signée)
; deux niveaux de pile dont l'appel sauf pour l'addition qui
; n'en demande qu'un
; constantes utiles à filtrer le code installé
A8BS_METADD EQU 1
A8BS_METSUB EQU 2
A8BS_METMULT EQU 4
A8BS_METDIV EQU 8
A8BS_METTOUT EQU A8BS_METADD + A8BS_METSUB + A8BS_METMULT + A8BS_METDIV
include "M:/Callx/callx.inc"
;******************************************************************
; Macros
;******************************************************************
A8BS_VAR macro
; Déclarations des variables du module
ifndef _A8BS_VAR
CBLOCK
A8BS_DATA : 0
A8BS_O1 : 2
A8BS_O2 : 1
A8BS_RES : 2
A8BS_Temp1 : 1
A8BS_FIN_DATA
endc
; quelques étiquettes facilitant la lecture du code
A8BS_O1BP EQU A8BS_O1
A8BS_O1HP EQU A8BS_O1+1
A8BS_RESBP EQU A8BS_RES
A8BS_RESHP EQU A8BS_RES+1
A8BS_Quotient EQU A8BS_RES
A8BS_Reste EQU A8BS_RES
if (A8BS_DATA && 0x1800) != ((A8BS_FIN_DATA - 1) && 0x1800)
messg " "
error "Les données du module A8BS doivent être dans la même banque"
messg " "
endif
else
messg " "
messg "A8BS_VAR ne peut être invoquée qu'une seule fois"
messg "autres appels ignorés
messg " "
exitm
endif
endm
CHGBNK macro P1, P2
if (P1&0x80)!=(P2&0x80)
if (P1&0x80) == 0
bsf STATUS, RP0
else
bcf STATUS, RP0
endif
endif
if (P1&0x100)!=(P2&0x100)
if (P1&0x100) == 0
bsf STATUS, RP1
else
bcf STATUS, RP1
endif
endif
endm
;******************************************************************
; A8BS_8To16
;******************************************************************
A8BS_8To16 macro V
; transforme un 8 bits signés en 16 bits signés
; par extension du bit de signe
; si A8BS_O1BP,7 == 0, A8BS_O1HP est mis à 0
; si A8BS_O1BP,7 == 1, A8BS_O1HP est mis à 0xff
BANKSEL V
clrf V+1
btfsc V,7
decf V+1, f
endm
;******************************************************************
; A8BS_16To8
;******************************************************************
A8BS_16To8 macro V1
; retourne STATUS, C armé si A8BS_O1 n'est pas tronquable à 8 bits
; i.e. :
; A8BS_O1BP,7 == 1 et A8BS_O1HP != 0xff
; ou
; A8BS_O1BP,7 == 0 et A8BS_O1HP != 0x00
BANKSEL V1
bsf STATUS, C
btfss V1,7
goto A8BS_16To8_2
;cas 1
incfsz V1+1, w
goto A8BS_16To8_3
local A8BS_16To8_1
A8BS_16To8_1
bcf STATUS, C
goto A8BS_16To8_3
local A8BS_16To8_2
A8BS_16To8_2
; cas 2
movf V1+1, f
btfsc STATUS, Z
goto A8BS_16To8_1
local A8BS_16To8_3
A8BS_16To8_3
endm
;******************************************************************
; A8BS_ADDV
;******************************************************************
A8BS_ADDV macro V1, V2, V3
; A8BS_ADDV A, B, C est équivalent à
; C = A+B d'un langage évolué, A, B, C variables 8 bits
; STATUS, Z et C sont armés en fonction du résultat
; appelle A8BS_Add
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_Add
movf A8BS_RES, w
CHGBNK A8BS_DATA, V3
movwf V3
endm
;******************************************************************
; A8BS_ADDL
;******************************************************************
A8BS_ADDL macro V1, V2, V3
; A8BS_ADDL A, 0x56, C est équivalent à
; C = A+0x56 d'un langage évolué, A, C variables 8 bits
; STATUS, Z et C sont armés en fonction du résultat
; appelle A8BS_Add
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
movlw V2
movwf A8BS_O2
CALLX A8BS_Add
movf A8BS_RES, w
CHGBNK A8BS_RES, V3
movwf V3
endm
;******************************************************************
; A8BS_SUBV
;******************************************************************
A8BS_SUBV macro V1, V2, V3
; A8BS_SUBV A, B, C est équivalent à
; C = A-B d'un langage évolué, A, B, C variables 8 bits
; STATUS, Z et C sont armés en fonction du résultat
; appelle
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_Sub
movf A8BS_RES, w
CHGBNK A8BS_DATA, V3
movwf V3
endm
;******************************************************************
; A8BS_SUBL
;******************************************************************
A8BS_SUBL macro V1, V2, V3
; A8BS_SUBL A, 0x56, C est équivalent à
; C = A-0x56 d'un langage évolué, A, C variables 8 bits
; STATUS, Z et C sont armés en fonction du résultat
; appelle A8BS_Sub
BANKSEL V1
movf V1,W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
movlw V2
movwf A8BS_O2
CALLX A8BS_Sub
movf A8BS_RES, w
CHGBNK A8BS_DATA, V3
movwf V3
endm
;******************************************************************
; A8BS_OPP
;******************************************************************
A8BS_OPP macro V1, V2
; A8BS_OPP V1, V2 est équivalent à
; V2 = -V1
; retourne STATUS, C armé si V1 == -128, dépassement de capacité
; STATUS, Z armé si V1 == 0
; appelle A8BS_Opp
BANKSEL V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_Opp
movf A8BS_O2, w
CHGBNK A8BS_DATA, V1
movwf V1
endm
;******************************************************************
; A8BS_MULTV
;******************************************************************
A8BS_MULTV macro V1, V2, V3
; A8BS_MULTV V1, V2, V3 est équivalent à
; V3 = V1*V2 V1 et V2 8 bits, V3 16 bits
; appelle A8BS_Mult
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_Mult
movf A8BS_RESBP, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_RESHP, w
CHGBNK A8BS_DATA, V3+1
movwf V3+1
endm
;******************************************************************
; A8BS_MULTUV
;******************************************************************
A8BS_MULTUV macro V1, V2, V3
; A8BS_MULTV V1, V2, V3 est équivalent à
; V3 = V1*V2 V1 et V2 8 bits non signé, V3 16 bits non signé
; appelle A8BS_MultU
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_MultU
movf A8BS_RESBP, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_RESHP, w
CHGBNK A8BS_DATA, V3+1
movwf V3+1
endm
;******************************************************************
; A8BS_MULTL
;******************************************************************
A8BS_MULTL macro V1, V2, V3
; A8BS_MULTV V1, V2, V3 est équivalent à
; V3 = V1*(-12) V1 8 bits, V3 16 bits
; appelle A8BS_Mult
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
movlw V2
movwf A8BS_O2
CALLX A8BS_Mult
movf A8BS_RESBP, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_RESHP, w
CHGBNK A8BS_DATA, V3+1
movwf V3+1
endm
;******************************************************************
; A8BS_DIVV
;******************************************************************
A8BS_DIVV macro V1, V2, V3, V4
; A8BS_DIVV A, B, C, D est partiellement équivalent à
; C = A/B mais retourne en plus le reste de la division dans D
; retourne STATUS, C armé si B == 0, division par 0
; appelle A8BS_Div
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_Div
movf A8BS_Quotient, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_Reste, w
CHGBNK A8BS_DATA, V4
movwf V4
endm
;******************************************************************
; A8BS_DIVL
;******************************************************************
A8BS_DIVL macro V1, V2, V3, V4
; A8BS_DIVV A, .56, C, D est partiellement équivalent à
; C = A/56 mais retourne en plus le reste de la division dans D
; retourne STATUS, C armé si la constante == 0, division par 0
; appelle A8BS_Div
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
movlw V2
movwf A8BS_O2
CALLX A8BS_Div
movf A8BS_Quotient, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_Reste, w
CHGBNK A8BS_DATA, V4
movwf V4
endm
;******************************************************************
; A8BS_DIVV
;******************************************************************
A8BS_DIVU macro V1, V2, V3, V4
; A8BS_DIVU A, B, C, D est partiellement équivalent à
; C = A/B mais retourne en plus le reste de la division dans D
; A, B, C et D variables 8 bits non signées
; retourne STATUS, C armé si B == 0, division par 0
; appelle A8BS_DivU
BANKSEL V1
movf V1, W
CHGBNK V1, A8BS_DATA
movwf A8BS_O1
CHGBNK A8BS_DATA, V2
movf V2, W
CHGBNK V2, A8BS_DATA
movwf A8BS_O2
CALLX A8BS_DivU
movf A8BS_Quotient, w
CHGBNK A8BS_DATA, V3
movwf V3
CHGBNK V3, A8BS_DATA
movf A8BS_Reste, w
CHGBNK A8BS_DATA, V4
movwf V4
endm
;******************************************************************
;******************************************************************
; CODE
;******************************************************************
;******************************************************************
A8BS_CODE macro QuoiMettre
ifndef _A8BS_CODE
#DEFINE _A8BS_CODE
variable LocalQuoiMettre = QuoiMettre
if QuoiMettre & A8BS_METSUB
LocalQuoiMettre = QuoiMettre|A8BS_METADD
endif ; QuoiMettre & A8BS_METSUB
A8BS_DEBUT_CODE
if LocalQuoiMettre & A8BS_METADD
A8BS_Add
; équivalent de
; RES = A8BS_O1 + A8BS_O2
btfss A8BS_O1, 7
goto A8BS_O1Plus
btfss A8BS_O2, 7
goto A8BS_SignesDifférents
A8BS_memesigne
movf A8BS_O1, w
addwf A8BS_O2, w
movwf A8BS_RES
movlw b'10000000'
andwf A8BS_O1, w
xorwf A8BS_RES, w
bcf STATUS, C
movwf A8BS_Temp1
btfsc A8BS_Temp1, 7
bsf STATUS, C
return
A8BS_O1Plus
btfss A8BS_O2, 7
goto A8BS_memesigne
A8BS_SignesDifférents
movf A8BS_O1, w
addwf A8BS_O2, w
movwf A8BS_RES
bcf STATUS, C
return
endif ; LocalQuoiMettre & A8BS_METADD
if LocalQuoiMettre & A8BS_METSUB
A8BS_Sub
; équivalent de
; RES = A8BS_O1 - A8BS_O2
call A8BS_Opp
goto A8BS_Add
A8BS_Opp
; équivalent de
; A8BS_O2 = - A8BS_O2
; retourne C armé si A8BS_O2 == -128, dépassement de capacité
movlw -.128
subwf A8BS_O2, w
btfsc STATUS, Z
; STATUS, C == 1
return
movf A8BS_O2, w
xorlw 0xff
addlw .1
movwf A8BS_O2
bcf STATUS, C
return
endif ; LocalQuoiMettre & A8BS_METSUB
if LocalQuoiMettre & A8BS_METMULT
A8BS_Mult
clrf A8BS_Temp1
clrf A8BS_O1HP
btfsc A8BS_O1BP, 7
goto A8BS_Mult_2
A8BS_Mult_1
btfsc A8BS_O2, 7
goto A8BS_Mult_3
goto A8BS_Mult_4
A8BS_Mult_2
; OP1 < 0
movlw 0xff
xorwf A8BS_O1BP, f
incf A8BS_O1BP, f
incf A8BS_Temp1, f
goto A8BS_Mult_1
A8BS_Mult_3
; OP2 < 0
movlw 0xff
xorwf A8BS_O2, f
incf A8BS_O2, f
incf A8BS_Temp1, f
A8BS_Mult_4
; OP1 > 0 et OP2 > 0 A8BS_Temp1<1;0> renseignés
call A8BS_MultU
btfss A8BS_Temp1, 0
goto A8BS_Mult_5
; opérandes de signes différents
movlw 0xff
xorwf A8BS_RESBP, f
xorwf A8BS_RESHP, f
incf A8BS_RESBP,f
btfsc STATUS, C
incf A8BS_RESHP,f
A8BS_Mult_5
; opérandes de même signe
return
A8BS_MultU
; multiplication 8 bits non signés résultat 16 bits
; équivalent de
; RES = A8BS_O1 * A8BS_O2 (RES 16 bits)
clrf A8BS_RESBP
clrf A8BS_RESHP
clrf A8BS_O1HP
A8BS_MultU_1
btfss A8BS_O2, 0
goto A8BS_MultPair
A8BS_MultImpPair
movf A8BS_O1BP, W
addwf A8BS_RESBP, f
btfsc STATUS, C
incf A8BS_RESHP, f
movwf A8BS_O1HP
addwf A8BS_RESHP, f
A8BS_MultPair
bcf STATUS, C
rrf A8BS_O2, f
bcf STATUS, C
rlf A8BS_O1BP, f
rlf A8BS_O1HP, f
movf A8BS_O2, f
btfss STATUS, Z
goto A8BS_MultU_1
return
endif ; LocalQuoiMettre & A8BS_METMULT
if LocalQuoiMettre & A8BS_METDIV
A8BS_Div
bsf STATUS, C
movf A8BS_O2, f
btfsc STATUS, Z
return ; division par 0 retourne C armé
clrf A8BS_Temp1
btfss A8BS_O1, 7
goto A8BS_Div_2
; dividande négatif, on calcule son opposé et on mémorise
bsf A8BS_Temp1, 0
movlw 0xff
xorwf A8BS_O1, f
incf A8BS_O1, f
A8BS_Div_2
; ici dividande >0
btfss A8BS_O2, 7
goto A8BS_Div_3
; ici dividande >0 diviseur <0
; divieur négatif, on calcule son opposé et on mémorise
bsf A8BS_Temp1, 1
movlw 0xff
xorwf A8BS_O2, f
incf A8BS_O2, f
A8BS_Div_3
; ici, on opère sur les valeurs absolues
call A8BS_DivU
btfsc A8BS_Temp1, 0
goto A8BS_Div_4
btfsc A8BS_Temp1, 1
goto A8BS_Div_6
; ici, dividande >0 diviseur >0, rien à faire
goto A8BS_Div_8
A8BS_Div_4
; ici, dividande <0
btfss A8BS_Temp1, 2
goto A8BS_Div_5
; ici, dividande <0 diviseur <0
incf A8BS_Quotient, f
goto A8BS_Div_8
A8BS_Div_5
; ici, dividande <0 diviseur >0
incf A8BS_Quotient, f
movlw 0xff
xorwf A8BS_Quotient, f
incf A8BS_Quotient, f
goto A8BS_Div_7
A8BS_Div_6
; ici, dividande >0 diviseur <0
xorwf A8BS_Quotient, f
incf A8BS_Quotient, f
A8BS_Div_7
; dividande et diviseur de signe contraire
xorwf A8BS_Reste, f
incf A8BS_Reste, f
A8BS_Div_8
bcf STATUS, C
return
A8BS_DivU
; division 8 bits non signés
; méthode par soustractions successives
; A8BS_O1, dividande ; A8BS_O2, diviseur
; A8BS_Quotient, quotient ; A8BS_Reste, reste (>0 et <diviseur)
bsf STATUS, C
movf A8BS_O2, f
btfsc STATUS, Z
return ; division par 0 retourne C armé
clrf A8BS_Quotient
movf A8BS_O1, w
movwf A8BS_Reste
A8BS_DivU_1
movwf A8BS_O2
subwf A8BS_Reste, w
btfss STATUS, C
goto A8BS_DivU_2
; A8BS_Reste < A8BS_O2
return
A8BS_DivU_2
; A8BS_Reste >= A8BS_O2
movwf A8BS_Reste
incf A8BS_Quotient, f
goto A8BS_DivU_1
endif ; LocalQuoiMettre & A8BS_METDIV
A8BS_FIN_CODE
else
messg " "
messg "A8BS_CODE ne peut être invoquée qu'une fois"
messg "autres invocations ignorées"
messg " "
endif ;ndef _A8BS_CODE
if (A8BS_DEBUT_CODE & 0x1800) != ((A8BS_FIN_CODE-1) & 0x1800)
messg " "
error "A8BS doit résider dans une seule page de code"
messg " "
endif
endm
Il définit quelques macros qui permettent, entre autre, d'appeler les sous-programmes de traitement sur les variables
A lecture du code vous pourrez constater les précautions prises pour informer l'utilisateur de situations délicates.
Prenons dans l'ordre
ligne 64 macro CHGBNK : permet un changement de banque avec le strict minimum d'instructions, à la condition de savoir dans quelle banque on est au moment de l'invocation ce qui est le cas dans toutes les macros qui vont suivre.
suivent deux petits gadgets
A8BS_8To16 : les commentaires suffisent. Il n'est pas écrit que son usage nécessite que la variable sur laquelle on l'appelle doit avoir 2 octets
A8BS_16To8 : teste la faisabilité d'un tronquage. Se contente d'armer ou désarmer le bit C de STATUS
toutes les autres sont sur le même modèle
8 lignes de passage de paramètre, une ligne d'appel di sous-programme qui fait le travail, 3 lignes de passage du résultat.
Remarquons le premier BANKSEL qui ne peut pas être un CHGBNK puisqu'on ne peut pas savoir la banque active au début de la macro. Bien d'autres manières de faire étaient possibles, en particulier de demander à l'appelant d'être dans la banque mémoire contenant le premier paramètre d'appel au moment d'invoquer la macro mais comme ceci ne peut pas être testé par l'assembleur, j'aipréféré cette méthode plus coûteuse.
A8BS_ADDV
A8BS_ADDL
les commentaires décrivent leur fonction. Noter qu'il faut distinguer les cas où le deuxième opérande est une variable de celui où il est une constante. Je n'ai pas trouvé de méthode dans l'assembleur qui permettent de le faire
Les autres fonctionnalités suivent ;
A8BS_SUBV
A8BS_SUBL
A8BS_OPP calculer l'opposé, utile car A-B est traité comme A+(-B)
A8BS_MULTV
A8BS_MULTUV utile car A*B est traité comme ABS(A)*ABS(B) le signe étant traité à part
A8BS_MULTL
A8BS_DIVV
A8BS_DIVl
A8BS_DIVU
Quelques infos sur la division entière
ici,
Enfin, la dernière A8BS_CODE dont l'invocation introduira le code dans votre source.
Merci si vous êtes arrivé jusqu'à cette ligne

en espérant avoir retenu votre attention.
Qui s'y colle pour un module A16BS ? Temps-x qui nous a déjà fait la multiplication

?
petit complément, le code de l'autre module utilisé callx
► Afficher le texte
Code : Tout sélectionner
ifndef _CallX
; Module CallX
; Date création : 02/03/2019
; Auteur : JJE
; Historique
; version 1 : 15/03/2019
; Ce module définit les macros CALLX et GOTOX de BigOnOff
; en exploitant la possibilité de définir le nombre de pages
; de programme Pic utilisées par le programme. On fait l'hypothèse
; qu'elles sont utilisées dans l'ordre croissant.
; ceci permet de gagner jusqu'à 2 octets de code pour un GOTOX
; et jusqu'à 4 pour un CALLX
;
; utilise l'étiquette NbPages qui doit être définie comme égale à
; 1, 2, 3 ou 4. Toute autre valeur entraîne une erreur
; si elle n'est pas définie AVANT la lecture de ce fichier,
; elle est prise comme égale à 4
; version 2 : 17/03/2019
; ajout de PCLAX de CALLSX et de GOTOSX qui permettent d'enchaîner
; plusieurs CALL en limitant les changements de page
ifndef NbPages
messg " "
messg "Attention, NbPages n'est pas défini"
messg "on lui attribue la valeur 4"
messg " "
else
if NbPages==0 || NbPages >=5
messg " "
error "NbPages doit être compris entre 1 et 4, compris"
messg " "
endif ;if NbPages==0 || NbPages >=5
endif ; def NbPages
; goto inter-banques
; ------------------
; adapté de BigOnOff
; réalise un goto avec gestion de PCLATH
if NbPages == 4 || NbPages == 3
GOTOX macro ADRESSE
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
local BIT4 = (ADRESSE & 0x1000) ; voir bit 12
local ICI
ICI
local PICI = (ICI+2 & 0x1800) ; page du saut
IF BIT3 ; si ADRESSE dans page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE ; sinon
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
IF BIT4 ; si ADRESSE dans page 2 ou 4
bsf PCLATH , 4 ; b4 de PCLATH = 1
ELSE ; sinon
bcf PCLATH , 4 ; b4 de PCLATH = 0
ENDIF
goto (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
else ; NbPages == 4 || NbPages == 3
if NbPages == 2
GOTOX macro ADRESSE
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
local ICI
ICI
local PICI = (ICI+2 & 0x1800) ; page du saut
IF BIT3 ; si ADRESSE dans page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE ; sinon
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
goto (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
else
; Nombre de pages ==1
GOTOX macro ADRESSE
local ICI
ICI
local PICI = (ICI+1 & 0x1800) ; page du saut
goto (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
endif ; NbPages == 2
endif ; NbPages == 4 || NbPages == 3
; Sous-routines inter-banques
; ----------------------------
; tiré de BigOnOff
; réalise un call avec gestion de PCLATH
if NbPages == 4 || NbPages == 3
CALLX macro ADRESSE ; call inter-page
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
local BIT4 = (ADRESSE & 0x1000) ; voir bit 12
local ICI
ICI
local PICI = (ICI+2 & 0x1800) ; page du saut
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
IF BIT4 ; si page 2 ou 4
bsf PCLATH , 4 ; b4 de PCLATH = 1
ELSE
bcf PCLATH , 4 ; b3 de PCLATH = 0
ENDIF
call (ADRESSE & 0x7FF | PICI) ; adresse simulée
local BIT3 = (ICI+5 & 0x0800) ; voir bit 11
local BIT4 = (ICI+5 & 0x1000) ; voir bit 12
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 0
ELSE
bcf PCLATH , 3 ; b3 de PCLATH = 1
ENDIF
IF BIT4 ; si page 2 ou 4
bsf PCLATH , 4 ; b4 de PCLATH = 0
ELSE
bcf PCLATH , 4 ; b3 de PCLATH = 1
ENDIF
endm
else ; NbPages == 4 || NbPages == 3
if NbPages == 2
CALLX macro ADRESSE ; call inter-page
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
local ICI
ICI
local PICI = (ICI+2 & 0x1800) ; page du saut
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
call (ADRESSE & 0x7FF | PICI) ; adresse simulée
local BIT3 = (ICI+3 & 0x0800) ; voir bit 11
local BIT4 = (ICI+3 & 0x1000) ; voir bit 12
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 0
ELSE
bcf PCLATH , 3 ; b3 de PCLATH = 1
ENDIF
endm
else
CALLX macro ADRESSE ; call inter-page
; Nombre de pages ==1
local ICI
ICI
local PICI = (ICI+1 & 0x1800) ; page du saut
call (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
endif ; NbPages == 2
endif ; NbPages == 4 || NbPages == 3
; Changement de page
; -------------------
if NbPages == 4 || NbPages == 3
PCLAX macro ADRESSE ; positionne PCLATH pour les sauts sans le saut
local BIT4 = (ADRESSE & 0x1000) ; voir bit 12
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE ; sinon
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
IF BIT4 ; si page 2 ou 3
bsf PCLATH , 4 ; b4 de PCLATH = 1
ELSE ; sinon
bcf PCLATH , 4 ; b4 de PCLATH = 0
ENDIF
Endm
else ; NbPages == 4 || NbPages == 3
if NbPages == 2
PCLAX macro ADRESSE ; call inter-page
local BIT3 = (ADRESSE & 0x0800) ; voir bit 11
local ICI
ICI
local PICI = (ICI+2 & 0x1800) ; page du saut
IF BIT3 ; si page 1 ou 3
bsf PCLATH , 3 ; b3 de PCLATH = 1
ELSE
bcf PCLATH , 3 ; b3 de PCLATH = 0
ENDIF
Endm
else
PCLAX macro ADRESSE ; call inter-page
Endm
endif ; NbPages == 2
endif ; NbPages == 4 || NbPages == 3
; saut sans sélection de page
; évite le warning
; ----------------
GOTOSX macro ADRESSE ; saut sans sélection de PCLATH
local ICI ; adresse courante
local PICI = (ICI & 0x1800) ; page du saut
ICI
goto (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
; appel ssp sans sélection de page
; évite le warning
; ----------------
CALLSX macro ADRESSE ; appel sous-programme sans sélection de PCLATH
local ICI ; adresse courante
local PICI = (ICI & 0x1800) ; page du saut
ICI
call (ADRESSE & 0x7FF | PICI) ; adresse simulée
endm
endif ; def _CallX