;************************************************************************ ; Rechnen im internen RAM ;************************************************************************ ; Vereinbarungen ;Eingabe: R0: Zeiger auf 1.nutzbaren Speicherplatz (LSB) ; d.h. Nach Eingaben zeigt R0 auf das n„chste freie Byte ; nach der eingegebenen Zahl ; alle weiteren Parameter werden nach Aufruf bergeben ;Operationen: 1.Operand = 1.Operand (+,-,/,*) 2.Operand ; Pufferzeiger wird decrementiert ;Benutzte Register: A, B, DPTR, R0, R1, R2, R3, R4 ; Flags: CY, AC, OV ;************************************************************************ ;Precision SET 4 ;default 4 Byte ;APointer EQU R1 ;Zeiger auf Arithmetik-Speicher ;HPointer EQU R0 ;Hilfszeiger ;****************************** Load Variable from ********************** ; 16bit signed from internal memory (LSB first) ;Input after call: 8bit address $IF( _ALOADM_ ) ALOADM: MCALL GETARG1 ;get address MOV HPointer, A MOV A, @HPointer ;get LSB INC HPointer MOV B, @HPointer ;get MSB SJMP ALOADBA endif ; 16bit signed from program memory ;Input after call: 16Bit-Address (MSB first) $IF( _ALOADP_ ) ALOADP: MCALL GETARG2 ;get address CLR A MOVC A, @A+DPTR ;get MSB MOV B, A MOV A, #1 MOVC A, @A+DPTR ;get LSB SJMP ALOADBA $ENDIF ; 16bit signed constant from program memory (MSB first) ALOADC: MCALL GETARG2 ;get value to BA ; 16bit signed from BA ALOADBA: MOV @APointer, A ;LSB INC APointer MOV A, B ;MSB MOV R2, #Precision-1 ALOAD1: MOV @APointer, A ;Erweiterung auf 4 Byte RLC A SUBB A, ACC ;Vorzeichenerweiterung INC APointer DJNZ R2, ALOAD1 RET ; 8bit signed from A ALOADA: MOV R2, #Precision SJMP ALOAD1 ;ALOADWE ;32bit signed from I2C-EEPROM (MSB first ???) ;****************************** Store Variable to *********************** ; 16bit signed to internal memory (LSB first) ;Eingabe: nach Aufruf: Zeiger auf Speicher (LSB) ;Ausgabe: Puffer-- $IF( _ASTORM_ ) ASTORM: MCALL GETARG1 ;get address MOV HPointer, A MCALL ASTORBA ;get value MOV @HPointer, A ;store LSB INC HPointer MOV @HPointer, B ;store MSB RET $ENDIF ; 16bit signed to external memory (MSB first !) ;Input after call: address of ext. RAM (MSB) ;Output: Puffer-- $IF( _ASTORX_ ) ASTORX: MCALL GETARG2 ;get address MCALL ASTORBA ;get value XCH A, B MOVX @DPTR, A ;store MSB XCH A, B INC DPTR MOVX @DPTR, A ;store LSB RET $ENDIF ; 16bit signed to BA ASTORBA: MOV A, APointer ADD A, #1-Precision MOV APointer, A MOV B, @APointer DEC APointer MOV A, @APointer RET ;ASTOREWE ;32bit to I2C-EEPROM ;********************** Operations with 1 operand *********************** ; Division 2^N $IF( _ASRN_ ) ASRN: ACALL GETARG1 ;Schiebefaktor ASRN1: MOV B, APointer ASR1: MOV R3, A MOV R2, #Precision DEC APointer MOV A, @APointer CJNE R3, #4 ASR2 ASR2: JNC ASR3 ;********************** Schieben um 1 Bit ******************************* ASR11: RLC A ASR12: MOV A, @APointer RRC A MOV @APointer, A DEC APointer DJNZ R2 ASR12 MOV A, #-1 SJMP ASR5 ASR3: CJNE R3, #8 ASR4 ;********************** Schieben um 8 Bit ******************************** ASR81: RLC A SUBB A, ACC ;Vorzeichenerweiterung ASR82: XCH A, @APointer ;Verschieben um 1Byte DEC APointer DJNZ R2 ASR82 MOV A, #-8 SJMP ASR5 ASR4: JNC ASR81 ;********************** Schieben um 4 Bit ******************************* ASR41: RLC A ;Vorzeichen nach CY SUBB A, ACC ;ACC = S,X @APointer = H3,L3 ASR42: XCH A, @APointer ;H3,L3 S,X SWAP A ;L3,H3 S,X XCHD A, @APointer ;L3,X S,H3 DEC APointer ;L3,X H2,L2 DJNZ R2 ASR42 MOV A, #-4 ASR5: ADD A, R3 ;Schiebefaktor abziehen MOV APointer, B ;Pufferzeiger restaurieren JNZ ASR1 RET $ENDIF ;********************** Division / 10 for decimal input ***************** ;Attention: Input must be positive ! ;Output: X = X / 10, ACC = X % 10 $IF( _ADIVR10_ ) ADIVR10: MOV R2, #Precision CLR A ADIVR11: DEC APointer XCH A, @APointer JZ ADIVR12 CLR F0 ;Vornull-flag clear ADIVR12: XCHD A, @APointer SWAP A MOV B, #10 DIV AB ;H-Digit /10 SWAP A XCH A, @APointer SWAP A ADD A, B SWAP A MOV B, #10 DIV AB ;L-Digit /10 XCHD A, @APointer MOV A, B DJNZ R2, ADIVR11 MJMP APINC ;restore APointer $ENDIF ;********************** Multiplication * 10 for decimal output ********** ;Output: X = X * 10 + ACC $IF( _AMULA10_ ) AMULA10: MCALL APDEC ;APointer auf LSB MOV R2, #Precision AMULA2: MOV R3, A ;Ziffer merken MOV A, @APointer MOV B, #10 MUL AB ADD A, R3 ;+ Ziffer oder Uebertrag MOV @APointer, A CLR A ADDC A, B ;Uebertrag bilden INC APointer DJNZ R2, AMULA2 RET $ENDIF ;********************** Operations between 2 operands ******************* ; Addition $IF( _AADD_ ) AADD: MCALL APDEC ;Zeiger rcksetzen MOV A, APointer MOV HPointer, A ;HPointer zeigt auf LSB des 2.Operanden MCALL APDEC ;APointer zeigt auf LSB des 1.Operanden MOV R2, #Precision CLR C AADD1: MOV A, @APointer ;1.Operanden holen ADDC A, @HPointer ;Adddieren 2.Operanden MOV @APointer, A ;Ergebnis zurck INC APointer INC HPointer DJNZ R2, AADD1 ;und n„chstes Byte RET $ENDIF ;********************** Subtraktion ************************************* $IF( _ASUB_ ) ASUB: MCALL APDEC ;Zeiger rcksetzen MOV A, APointer MOV HPointer, A ;HPointer zeigt auf LSB des 2.Operanden MCALL APDEC ;APointer zeigt auf LSB des 1.Operanden MOV R2, #Precision CLR C ASUB1: MOV A, @APointer ;1.Operanden holen SUBB A, @HPointer ;Subtraieren 2.Operanden MOV @APointer, A ;Ergebnis zurck INC APointer INC HPointer DJNZ R2, ASUB1 ;und n„chstes Byte RET $ENDIF ;------------------------------------------------------------------------ ; Multiplikation ohne šberlauftest ; funktioniert auch Vorzeichenrichtig $IF( _AMUL_ ) AMUL: MCALL APDEC MCALL APDEC ;point at LSB of 1.Operand MOV R2, #Precision CLR A AMUL1: PUSH ACC ;leeren Ergebnispuffer anlegen DJNZ R2, AMUL1 MOV R2, #Precision ;! n AMUL2: MOV R3, AR2 ;Beginn auessere Schleife MOV HPointer, SP ;SP zeigt auf LSB MOV R4, #0 ;Uebertragsspeicher AMUL3: MOV A, R2 ;Berechnung 2.Faktor ADD A, R2 ;CY = 0, da R2 < 128 SUBB A, R3 ADD A, APointer ;2 * R2 - R3 + APointer XCH A, APointer MOV B, @APointer ;hole 2.Faktor XCH A, APointer MOV A, @APointer ;hole 1.Faktor MUL AB ;Multiplikation ADD A, R4 ;+ Uebertrag MOV R4, B ;neuen Uebertrag nach R4 JNC AMUL4 INC R4 ;+ Uebertrag aus Addition AMUL4: ADD A, @HPointer ;+ Summe JNC AMUL5 INC R4 ;+ Uebertrag aus Addition AMUL5: MOV @HPointer, A DEC HPointer DJNZ R3 AMUL3 ;Abschneiden hoeherwertiger Teil POP ACC MOV @APointer, A ;Ergebnisbyte holen INC APointer DJNZ R2, AMUL2 ;aeussere Schleife RET $ENDIF ;***************************** Division ***************************** ;Divident / Divisor = Quotient + Rest ;neue Version: Stack = Precision (alte Version: 2*Precision) $IF( _ADIV_ ) ADIV: MCALL ABET ;Betrag 2.Operand MOV F0, C MCALL APDEC ;R0 zeigt hinter 1.Operand (Divident) MCALL ABET ;Betrag 1.Operand JNC ADVV1 CPL F0 ;F0 gesetzt = neg. Vorzeichen ADVV1: MOV R2, #Precision ADVV2: CLR A XCH A, @APointer ;Wert holen, und loeschen PUSH ACC INC APointer DJNZ R2 ADVV2 MOV A, APointer ADD A, #-Precision*2 MOV R4, A ;R4 = Schiebepointer CLR C MOV R3, #Precision*8 ADVV3: MOV R2, #Precision*2 ;Schieben: 2*n Byte MOV APointer, AR4 ADVV4: MOV A, @APointer RLC A MOV @APointer, A INC APointer DJNZ R2 ADVV4 MOV R2, #Precision ;Testen X-Y MOV HPointer, SP ; CLR C ;MSB = 0 -> CY = 0 ADVV5: DEC APointer MOV A, @APointer SUBB A, @HPointer JC ADVV10 ;X < Y -> nicht abziehen DEC HPointer JNZ ADVV7 ;X > Y -> abziehen (nach Pointerkorrektur) DJNZ R2 ADVV5 SJMP ADVV8 ;X = Y -> abziehen ADVV6: DEC APointer DEC HPointer ADVV7: DJNZ R2 ADVV6 ADVV8: MOV R2, #Precision ;Abziehen ; CLR C ;CY = 0 ADVV9: INC HPointer MOV A, @APointer SUBB A, @HPointer MOV @APointer, A INC APointer DJNZ R2 ADVV9 ADVV10: CPL C DJNZ R3 ADVV3 MOV R2, #Precision MOV APointer, AR4 ADVV11: MOV A, @APointer RLC A ;Letztes Ergebnisbit einschieben MOV @APointer, A INC APointer DJNZ R2 ADVV11 MOV A, SP ADD A, #-Precision ;Stack aufraeumen MOV SP, A JNB F0, ADVV12 MJMP ANEG ;Komplement, wenn Ergebnis negativ ADVV12: RET ;********************** Division mit Rest ******************************* ; Operand1 / Operand2 = Operand1 ; Operand1 MOD Operand2 = Operand2 ADIVR: MCALL ADIV MJMP APINC $ENDIF ; Vertauschen der Operanden $IF( _ASWAP_ ) ASWAP: MOV A, APointer ADD A, #-Precision MOV APointer, A ADD A, #-Precision MOV HPointer, A MOV R2, #Precision ASWAP1: MOV A, @APointer XCH A, @HPointer MOV @APointer, A INC APointer INC HPointer DJNZ R2 ASWAP1 RET $ENDIF ;********************** remove higher value ****************************** ;Output: max(X,Y) $IF( _AMin_ ) AMIN: MCALL ACOMP JNC AMAX1 RET $ENDIF ;********************** remove lower value ****************************** ;Output: max(X,Y) $IF( _AMAX_ ) AMAX: MCALL ACOMP JC AMAX1 RET AMAX1: MCALL APINC MCALL ASWAP MJMP APDEC $ENDIF ;********************** Test Operations ********************************* ;******************* Test bzw. Begrenzung ******************************* ;Input after call: lower limit, upper limit ;Output: CY = 1: Value outer limits $IF( _ATEST_ ) ; only Test ATEST: CLR F0 ;nur Test SJMP ALIM1 ; Test and limitation ALIMIT: SETB F0 ;Test und Begrenzung ALIM1: MCALL GETARG2 ;Lade Minimalwert MCALL ALOADBA MCALL ACOMP ;Vergleich MCALL GETARG2 ;Lade Maximalwert JC ALIM3 ;< Minimum MCALL ALOADBA MCALL ACOMP ;Vergleich JC ALIM2 ;< Maximum JNZ ALIM3 ;> Maximum ALIM2: CLR C RET ALIM3: JNB F0, ALIM4 MCALL APINC MCALL ASWAP ;Vertauschen mit Grenzwert MCALL APDEC ALIM4: SETB C ;CY = 1 -> Bereich ueberschritten RET $ENDIF ;******************** Initialisierung Datenspeicher ********************* ;AINIT: MOV APointer, #ADATA ; RET ;************** Pufferzeiger decrement (L”schen Zahl) ******************** APDEC: XCH A, APointer ADD A, #-Precision XCH A, APointer ;dadurch bleibt ACC erhalten RET ;************** Pufferzeiger increment (fr Eingabefunktionen) *********** ; und restaurieren letzten Operanden APINC: XCH A, APointer ADD A, #Precision XCH A, APointer RET ;********************** Wert duplizieren **************************** $IF( _ACOPY_ ) ACOPY: MOV A, APointer ADD A, #-Precision XCH A, HPointer MOV R3, A ;HPointer sichern MOV R2, #Precision ACOP1: MOV A, @HPointer MOV @APointer, A INC APointer INC HPointer DJNZ R2, ACOP1 MOV A, R3 MOV HPointer, A ;HPointer restaurieren RET $ENDIF ;--------------------------------------------------------------------- ;********************** Vergleich mit Konstante ************************* $IF( _ACOMP_ ) ACOMPC: MCALL GETARG2 ;Hole Wert MCALL ALOADBA ;Abspeichern und weiter mit Vergleich ;********************** Vergleich zweier Operanden ********************** ;Ausgabe: CY = 1: 1.Operand < 2.Operand ; A = 0: 1.Operand = 2.Operand ; A = 0FFh: 1.Operand != 2.Operand if(0) ACOMP: MOV A, APointer MOV HPointer, A ;HPointer zeigt hinter 2.Operanden MCALL APDEC ;APointer zeigt hinter 1.Operanden MOV R2, #Precision ACOMP1: DEC APointer DEC HPointer ;MSB zuerst MOV A, @APointer MOV B, @HPointer CJNE R2, #Precision, ACOMP2 ;Vorzeichen bercksichtigen CPL ACC.7 CPL B.7 ACOMP2: CJNE A, B, ACOMP4 ;Vergleich DJNZ R2, ACOMP1 MOV APointer, #0 ;beide Zahlen gleich SJMP ACOMP5 ACOMP3: DEC HPointer ;HPointer muá hinter 1.Operanden zeigen ACOMP4: DJNZ R2, ACOMP3 MOV APointer, #0FFH ACOMP5: MOV A, HPointer XCH A, APointer ;Zeiger hinter 1.Operanden RET else ACOMP: MOV A, APointer ADD A, #-Precision MOV HPointer, A ;HPointer zeigt hinter 1.Operanden MOV R2, #Precision ACOMP1: DEC APointer DEC HPointer ;MSB zuerst MOV A, @HPointer MOV B, @APointer CJNE R2, #Precision, ACOMP2 ;Vorzeichen bercksichtigen CPL ACC.7 CPL B.7 ACOMP2: CJNE A, B, ACOMP4 ;Vergleich DJNZ R2, ACOMP1 CLR A ;beide Zahlen gleich RET ACOMP3: DEC APointer ;APointer muá hinter 1.Operanden zeigen ACOMP4: DJNZ R2, ACOMP3 MOV A, #0FFh RET endif $ENDIF ;********************** Vorzeichen ermitteln **************************** ;Ausgabe: CY = 1: Zahl ist negativ $IF( _ASIGN_ ) ASIGN: DEC APointer MOV A, @APointer INC APointer RLC A RET $ENDIF ;************************* Betrag bilden ****************************** ;Ausgabe: CY = 1: Zahl war negativ ABET: DEC APointer MOV A, @APointer ;Hole MSB INC APointer CLR C JNB ACC.7, ANEG3 ;Teste Vorzeichen ;************************* Zweierkomplement **************************** ANEG: MCALL APDEC ;Setze APointer auf LSB CLR C ANEG1: MOV R2, #Precision ANEG2: CLR A SUBB A, @APointer ;Operand abziehen MOV @APointer, A ;Ergebnis zurck INC APointer DJNZ R2, ANEG2 ;und n„chstes Byte ANEG3: RET ;************************* Bitweises Komplement ************************ ACPL: MCALL APDEC SETB C SJMP ANEG1