Der Nachfolger des WDR-Computerclub mit Wolfgang Back und Wolfgang Rudolph - ...und immer ein Bit übrigbehalten!


Das Forum zur C-Control-1
Welche C-Control-Varianten existieren?
Übersicht - Suchen - Neueste 50 Beiträge - Neuer Beitrag - Login - Registrieren
INFO - FAQ - CC2-Forum - CCPro-Forum 

 32Bit Arithmetik Kategorie: Open-Micro/Open-Mini/Open-Midi/Open-Macro/Open-Maxi (von Joe - 3.05.2015 16:55)
Joe nutzt:  CC1-M-Unit V1.1, Open-Micro, Open-Macro
Hallo OMICRO u. OMACRO Anwender,

im Rahmen eines Projektes habe ich mich auch mit Arithmetik geschrieben in Inline Assembler  fuer die OMACRO und OMICRO beschäftigt. Daraus ist das unten aufgefuehrte 32 Bit Programm fuer die OMACRO entstanden. Aehnlich aufgebaute Programme habe ich auch fuer 24 Bit fuer die OMACRO und fuer die OMICRO in 16, 24 und 32 Bit geschrieben. Das ganze Paket habe ich schon an Dietmar Harlos geschickt. Hier also nur die 32 Bit Auslegung fuer die OMACRO.
Die dabei verwendete Wurzelfunktion ist rel. langsam, da bei der Wurzel von 2^32 insgesamt 65535 Durchläufe erfoderlich sind.
Ein schnelleres Programm fuer die Wurzelfunktion zeige ich im naechsten Beitrag.

Viel Spass an den OMICROs und OMACROS wuenscht

Joe F

############### JF32ARIT.BAS #################################
' JF32ARIT.BAS vom Mo. 23.03.2015 Josef Fenk;
'
' Umfang: 1640 Basic Bytes; 0 Sys-Bytes; 17  RAM-Bytes
' 32 Bit Arithmetik
' mit Subroutinen fuer
' 32 Bit Addition bzw. Subtraktion,
' schnelle 16bit x 16 Bit Multiplikation mit Ergebnis in 32 Bit
' einfache Division geradzahlig 2,4,8,etc.
' schnelle Division 32 Bit durch 8 Bit (1...255) mit Ergebnis 32 Bit
' Division 32Bit durch 32 Bit mit Ergebnis 32 Bit
' 32 Bit Square root = Wurzel ziehen mit Ergebnis in 16 Bit gerundet
' jedoch ist die Wurzelfunktion bei 2^32 etwas langsam, da 65535 Durchlauefe erforderlich sind
' Printausgabe der Zahlen als ganzzahlige Integerwerte ohne Vorzeichen

' Zahlenwertebereich der 32 bit Arithmetik ohne Vorzeichen
' Dezimal       255   255  255  255    
' 32-Bit-Zahl $00ff $00ff 00ff 00ff dezimal ausgeben: 0 bis 4.294.967.295
' einige Teile des Programms basieren auf der
' Version 32BITASM.BAS von Dietmar Harlos ADPC vom 29. Juni 2006;

' ---------------------------------------------------------------------------
' --- Betriebssystem konfigurieren ------------------------------------------
INCLUDE "OMAC.DEF"           'Include-Datei mit Definitionen vom April 2010

' ---------------------------------------------------------------------------
' --- Definitionen Variable fuer das Hauptprogramm
DEFINE Ar_a  AS LONG   'Erster  32-Bit-Akkumulator (1. Operand & Rechenergebnis)
DEFINE Ar_b  AS LONG   'Zweiter 32-Bit-Akkumulator (2. Operand)
DEFINE Ar_c  AS LONG   'Dritter 32-Bit-Akkumulator (temp. fuer DIV und PRINT32)

DEFINE Ar_aw1 AS WORD[1] OF Ar_a  ' low word doppelbyte 1-ter Eingabewert
DEFINE Ar_aw2 AS WORD[2] OF Ar_a  ' high word
DEFINE Ar_a1 AS BYTE[1] OF Ar_a   'L_Byte
DEFINE Ar_a2 AS BYTE[2] OF Ar_a   'Mid_L_Byte  
DEFINE Ar_a3 AS BYTE[3] OF Ar_a   'Mid_H_Byte  
DEFINE Ar_a4 AS BYTE[4] OF Ar_a   'Higest Byte  

DEFINE Ar_bw AS WORD[1] OF Ar_b   ' 2-ter eingabe wert und benutzt bei Berechnun
DEFINE Ar_b1 AS BYTE[1] OF Ar_b   'L_Byte
DEFINE Ar_b2 AS BYTE[2] OF Ar_b   'Mid_L_Byte
DEFINE Ar_b3 AS BYTE[3] OF Ar_b   'Mid_H_Byte  
DEFINE Ar_b4 AS BYTE[4] OF Ar_b   'Highest Byte  

DEFINE Ar_cw AS WORD[1] OF Ar_c   ' Ausgabe Rest in div Proc
DEFINE Ar_c1 AS BYTE[1] OF Ar_c   'L_Byte benutzt bei div. Berechnung und Ausgabe
DEFINE Ar_c2 AS BYTE[2] OF Ar_c   'H_Byte bzw. Middle Byte von 32Bit wie oben
DEFINE Ar_c3 AS BYTE[3] OF Ar_c   'Mid_H_Byte  
DEFINE Ar_c4 AS BYTE[4] OF Ar_c   'Highest Byte  

DEFINE tem1 BYTE    ' benutzt bei Ausgabe
DEFINE tem2 BYTE
DEFINE tem3 BYTE
DEFINE tem4 BYTE

DEFINE i_z  BYTE        ' Zaehlbyte

'***** Definition der Digitalen Ein- / Ausgabeports
'DEFINE Tast_P4    PORT[04]       'Warte-Taste


' Hauptprogramm-----------------------------------------------

' ---------------------------------------------------------------------------
#Start
     Ar_a3=255:Ar_a2=255:Ar_a1=255
     PRINT
     PRINT
     PRINT "Start Eingabe_Ar_a4=";Ar_a4
     GOSUB anzeigen
     PRINT
     PRINT "davon Wurzel"
     GOSUB sqrt_32
     Ar_a4=Ar_b4:Ar_a3=Ar_b3:Ar_a2=Ar_b2:Ar_a1=Ar_b1
     GOSUB anzeigen
     PAUSE 100
     
     PRINT
     PRINT "Eingabe_a 0...65535"
     INPUT Ar_aw1     'Eingabe 16 Bitzahl
     Ar_bw=Ar_aw1
     PRINT "Eingabe_Ar_aw=";Ar_aw1,"Ar_b=";Ar_bw
     GOSUB anzeigen
     PRINT
     GOSUB addieren
     PRINT "Ergebnis_Addition"
     GOSUB anzeigen
     GOSUB subtrahieren
     PRINT
     PRINT "Ergebnis_Subtraktion"
     GOSUB anzeigen
   
     Ar_a4=0:Ar_b4=0:Ar_a3=0:Ar_b3=0
     PRINT
     PRINT
     PRINT "Eingabe_Mult_a,b 0...65535"
     INPUT Ar_aw1     'Eingabe 16 Bitzahl
     Ar_bw=Ar_aw1      ' fuer quadratberechnung gleicher wert zugewiesen
     PRINT "Eingabe_Ar_aw1=";Ar_aw1,"Ar_bw=";Ar_bw
     GOSUB multi_16x16
     Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1  ' zuweisung der ergebnisse
     PRINT "Ausgabe_Mul_a*a=quadrat"
     GOSUB anzeigen
     GOSUB divid_8
     PRINT
     PRINT "Ausgabe_Div_8"
     GOSUB anzeigen
 
     Ar_a4=255:Ar_a3=255:Ar_a2=255:Ar_a1=255
     PRINT
     PRINT "Eingabe_Divisor 0...255"
     INPUT Ar_b1
     PRINT "Eingabe_Ar_b1=";Ar_b1
     GOSUB anzeigen
     PRINT
     PRINT "nun ./. Ar_b1"
     GOSUB div_8b
     Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1
     PRINT "Ostemp=";ostemp,"Rem_H_vor=";tem3,"Rem_H_nach=";tem2
     GOSUB anzeigen
     PAUSE 100
 
     Ar_a4=0:Ar_b4=0:Ar_a3=0:Ar_b3=0
     PRINT
     PRINT
     PRINT "Eingabe_Mult_a,b 0...65535"
     INPUT Ar_aw1     'Eingabe 16 Bitzahl
     Ar_bw=Ar_aw1      ' fuer quadratberechnung gleicher wert zugewiesen
     PRINT "Eingabe_Ar_aw1=";Ar_aw1,"Ar_b=";Ar_bw
     GOSUB multi_16x16
     Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1  ' zuweisung der ergebnisse
     PRINT "Ausgabe_Mul_a*a=quadrat"
     GOSUB anzeigen
     GOSUB sqrt_32    'Ergebnis in Ar_b
     PRINT
     PRINT "Ausgabe_Wurzel"
     Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1  ' zuweisung der ergebnisse
     GOSUB anzeigen

  #Div_Test    'ab hier divisionstest
     Ar_a4=0:Ar_b4=0:Ar_c4=0:Ar_a3=0:Ar_b3=0:Ar_c3=0:tem3=0:tem2=0:tem1=0
     PRINT
     PRINT
     PRINT "Eingabe_Mult_a,b nur 1xmal 0...65535"
     INPUT Ar_aw1     'Eingabe 16 Bitzahl
     Ar_bw=Ar_aw1      ' fuer quadratberechnung gleicher wert zugewiesen
     PRINT "Eingabe_Ar_aw1=";Ar_aw1,"Ar_bw=";Ar_bw
     GOSUB multi_16x16
     Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1  ' zuweisung der ergebnisse
     PRINT
     PRINT "Ausgabe_Mul_a*a=quadrat"
     GOSUB anzeigen
     PRINT
     PRINT "Eingabe_divisor_Ar_b: 0...65535"
     Input Ar_bw
     PRINT
     GOSUB div_32_16
     PRINT "Ausgabe_Division"
     GOSUB anzeigen
 
GOTO Start
End2Host=ON

END

' ****** Subroutinen ---------------------------------------------------------------------------
' Akkumulatoren ausgeben
PROC anzeigen
  PrintHex=ON
  PRINT "Akku_a: $";Ar_a4;Ar_a3;Ar_a2;Ar_a1;" dezimal ausgeben: ";
  print32
  PRINT
  tem4=Ar_a4:tem3=Ar_a3:tem2=Ar_a2:tem1=Ar_a1 ' Zwischenspeichern, damit Werte erhalten bleiben
  Ar_a4=Ar_b4:Ar_a3=Ar_b3:Ar_a2=Ar_b2:Ar_a1=Ar_b1
  PRINT "Akku_b: $";Ar_b4;Ar_b3;Ar_b2;Ar_b1;" dezimal ausgeben: ";
  print32
  PRINT
  Ar_a4=Ar_c4:Ar_a3=Ar_c3:Ar_a2=Ar_c2:Ar_a1=Ar_c1
  PRINT "Akku_c: $";Ar_c4;Ar_c3;Ar_c2;Ar_c1;" dezimal ausgeben: ";
  print32
  Ar_a4=tem4:Ar_a3=tem3:Ar_a2=tem2:Ar_a1=tem1
  PrintHex=OFF
RETURN
' *******************************************************************
' ab hier 32Bit Arithmetik
' Subroutinen Addition, Subtraktion,Multiplikation,
' einfache Division geradzahlig 2,4,8,etc.und beliebige Division gerundet
' sowie Square root = Wurzel ziehen
' sowie ausgabe der Ergabniszahl als integer wert ohne vorzeichen
'********************************************************************
' Subroutine zur 32-Bit-Addition
' Eingabewerte_1 muess in Ar_a4 bis Ar_a1 sein
' Eingabewerte_2 muess in Ar_b4 bis Ar_b1 sein
' Ausgabewerte sind in    Ar_a4 bis Ar_a1
PROC addieren INLASM  
! lda Ar_a+3  ' lowest byte in accu
! add Ar_b+3
! sta Ar_a+3
! lda Ar_a+2
! adc Ar_b+2
! sta Ar_a+2
! lda Ar_a+1  ' Mid_hi byte in accu
! adc Ar_b+1
! sta Ar_a+1
! lda Ar_a    ' highest byte in accu
! adc Ar_b
! sta Ar_a
! rts
END PROC

' Subroutine zur 32-Bit-Subtraktion
' Eingabewerte_1 muess in Ar_a4 bis Ar_a1 sein
' Eingabewerte_2 muess in Ar_b4 bis Ar_b1 sein
' Ausgabewerte sind in    Ar_a4 bis Ar_a1
PROC subtrahieren INLASM
! lda Ar_a+3
! sub Ar_b+3
! sta Ar_a+3
! lda Ar_a+2
! sbc Ar_b+2
! sta Ar_a+2
! lda Ar_a+1
! sbc Ar_b+1
! sta Ar_a+1
! lda Ar_a      ' highest byte in accu
! sbc Ar_b
! sta Ar_a
! rts
END PROC

' ---------------------------------------------------------------------------
' Schnelle Multiplikation 16Bit Wordvariable mit 16Bit Word Variable
' mit 32-Bit-Ergebnis
' von Josef Fenk Mo. 22.03.2015
' Eingabewerte_1=Multiplikand  muess in Ar_a2 bis Ar_a1 sein
' Eingabewerte_2=Multiplikator muess in Ar_b2 bis Ar_b1 sein
' Ausgabewerte=Produkt       sind in    Ar_c4 bis Ar_c1

' Verfahren der Multiplikation s. auch ATMEL application note AVR201
' Prod         Eingabe_A     Eingabe_B  Ergebnisse
'            A_H:A_L  x   B_H:B_L    C_H  C_ML C_ML C_L
'----------------------------------------------------------------------
' 1-te Mul.        A_L    x       B_L ==>            P1_H P1_L
' 2-te Mul.      A_H      x      B_L  ==> +c   P2_H P2_L
' 3-te Mul.          A_L  x B_H     ==> +c   P3_H P3_L
' 4-te Mul.      A_H      x  B_H     ==> P4_H P4_L
'-------------------------------------------------------------------------
' Summation der 4 Multiplikationen         C_M:C_MH:C_ML:C_L
'                   uebertragen in           Ar_c4:Ar_c3:Ar_c2:Ar_c1
' C_H bzw. P4_H wird beruecksichtigt, um 32 Bit Ergebnis auszugeben

PROC multi_16x16 INLASM
' 1-te Multiplikation
! lda Ar_a+3    ' Eingabe a1 low byte in accu
! ldx Ar_b+3    ' Eingabe b1 low byte in x register
! mul          ' Mul_1 P1_H byte in x; P1_L in accu
! sta Ar_c+3    ' accu=P1_L low byte in Ausgabe Ar_c1    
! stx Ar_c+2    ' P1_H high byte in Ar_c2
' 2-te Multiplikation
! lda Ar_a+2    ' Eingabe a1 high byte in accu
! ldx Ar_b+3    ' Eingabe b1 low byte in x
! mul           ' Mul_2  P2_H high byte in x-register; P2_L low byte in accu
! stx Ar_c+1    ' P2_H high byte in Ausgabe Ar_c3 mid_high byte abspeichern
! add Ar_c+2    ' P1_H zwischengespeichert in Ar_c2 zu P2_L low byte in accu addieren
! sta Ar_c+2    ' Ergebnis abgespeichert
! lda Ar_c+1    '
! adc #0        ' Ar_c3+ c ev. carry von add Ar_c+2 uebertragen
! sta Ar_c+1
! lda Ar_c      ' falls carry von vorher
! adc #0        ' nun carry uebertagen
! sta Ar_c      ' accu zurueck in c

' 3-te  Multiplikation
! lda Ar_a+3    ' Eingabe a1 low byte in accu
! ldx Ar_b+2    ' Eingabe b2 high byte in x register
! mul          ' Mul_3 P3_L low byte in accu; P3_H high byte in x
! add Ar_c+2   ' P3_L + (P2_L+P1_H) addition
! sta Ar_c+2    ' additionsergebnis accu in Ausgabe mittel byte speichern
! txa           ' P3_H in accu
! adc Ar_c+1    ' Ar_c3 + carry von voher addieren
! sta Ar_c+1
! lda Ar_c
! adc #0
! sta Ar_c      'alle uebertrage in c

' 4-te Multiplikation
! lda Ar_a+2   ' Eingabe high byte in accu
! ldx Ar_b+2   ' Eingabe b1 high byte in x
! mul          ' Mul4 P4_L low byte in accu; P4_H high byte in x-register, wird genutzt
! add Ar_c+1   ' P2_H in Ar_c3 zwischengespeichert nun zu P4_L in accu addieren
               ' P2_H+P4H mit ev. carry von vorherigen Additionen in Ar_c
! sta Ar_c+1   ' accu ergebnis in Ar_c3                
! lda Ar_c
! adc #0
! sta Ar_c
! txa          ' transfer x-register = P4_H in accu
! add Ar_c     'Ar_c zu accu addieren
! sta Ar_c     ' accu nach Ar_c4 highest byte kopieren
! rts
END PROC

' Subroutine fuer 32 bit Zahl; Division durch 8 mit Rundung
' Eingabewerte_1 muess in Ar_a4 bis Ar_a1 sein
' Ausgabewerte sind in    Ar_a4 bis Ar_a1
PROC divid_8 INLASM
! lda Ar_a+3     ' Nun halben divisor zu dividend addiert zwecks Rundung
! add #4         ' halben Teilerwert addieren
! sta Ar_a+3
! lda Ar_a+2
! adc #0         ' falls carry dann uebertrag von carry
! sta Ar_a+2
! lda Ar_a+1
! adc #0         ' falls carry dann uebertrag von carry
! sta Ar_a+1      
! lda Ar_a
! adc #0
! sta Ar_a       'Ende vorbereitung fuer Rundung des Ergebnisses
! lda #3         ' division :/.2 dazu fuer./.4==#2; ./.8==#3; ./.16==#4 etc. einfuegen
#Div_schl        ' divisionsschleife
! lsr Ar_a       ' MSB verschoben um eins nach rechts;  Bit0= in carry
! ror Ar_a+1     ' carry in Bit 7 von Ar_a+1 =uebertragen in drittes byte
! ror Ar_a+2     ' carry in Bit 7 von Ar_a+2 =in = zweites  byte
! ror Ar_a+3     ' carry in Ar_a1 uebertragen
! dbnza Div_schl 'wiederholt div_schl bis accu = 0 ist
! rts
END PROC

' *******************************************************************
' ab hier 32Bit Arithmetik Division durch 8 Bit mit Div Befehl u. Rundung
'********************************************************************
' Subroutine zur 32-Bit-Division; 4 Byte-Wert / 1 Byte-wert=Ergebnis in 4 Byte
' geaendert Sa. 14.03.2015 von JF, um integerzahlen ohne neg. Werte zu erhalten
' Wertebereich fuer Ausgabe begrenzt  
' auf  2^32 = 4.294.967.295==Hex: ff ff ff ff
' Urversion von Dietmar Harlos ADPC am 29. Juni 2006 in 32BITASM.BAS
PROC div_8b INLASM
! mov Ar_a+3,Ar_c+3       'Akkumulator a nicht veraendern
! mov Ar_a+2,Ar_c+2
! mov Ar_a+1,Ar_c+1
! mov Ar_a,Ar_c
! ldx Ar_b1 '#100       ' divisior = 10 in x register laden
! clr OSTEMP
#print10_2
! inc OSTEMP    ' zaehlt hoch
! clrh          ' high byte of dividend =0 gesetzt
! lda Ar_c      ' lade dividend highest byte in accu
! div           ' Division durch 10;quotient in accu; remainder in H
! sta Ar_c
! lda Ar_c+1
! div
! sta Ar_c+1
! lda Ar_c+2
! div
! sta Ar_c+2
! lda Ar_c+3
! div          ' ergebnis in accu und remainder in H
! sta Ar_c+3
! pshh        ' remainder in stack
! pula        ' nun in accu
! sta tem3    ' nun  h-register in tem3
! txa         ' x-registor= divisor in accu
! lsra        ' accu inhalt um 1 nach rechts, divisor halbiert
! add tem3     ' divisor/2 + tem3== divisor/2 + remainder
! clrh        ' H register loeschen
! div         ' quotient in accu, remainder in H
! add Ar_c+3  '
! sta Ar_c+3  ' ergebnis accu zurueck in Ar_c+3    
! pshh        ' remainder in stack
! pula        ' nun in accu
! sta tem2    ' h-register nach rundung in tem2    
! rts
END PROC

' 32-Bit-Division mit 32-Bit Ergebnis integerzahlen ohne Vorzeichen
' Eingabewert Dividend muss in Ar_a1 bis Ar_a4 sein==Hex:     = 0...
' Eingabewert Divisor  muss in Ar_b1 bis Ar_b4 sein= 0...
' Ausgabewert Quotient   in    Ar_a1 bis Ar_a4     = 0...
' geaendert Di. 17.03.1015 von JF,
' Urversion von Dietmar Harlos ADPC am 29. Juni 2006 aus 32BITASM.BAS
PROC div_32_16 INLASM
 ! clr Ar_c
 ! clr Ar_c+1      'Akkumulator c loeschen
 ! clr Ar_c+2
 ! clr Ar_c+3
 ! mov #32,OSTEMP ' schleifenzaehler zuweisen der variablen ostemp (ist in OM_FW.PRO)
#div32_1
 ! lsl Ar_a+3      'Dividend (= Quotient, Ergebnis) a nach links ...
 ! rol Ar_a+2
 ! rol Ar_a+1
 ! rol Ar_a
 ! rol Ar_c+3      'in den Akkumulator c schieben
 ! rol Ar_c+2
 ! rol Ar_c+1
 ! rol Ar_c
 
 ! lda Ar_c+3      'Akkumulator c minus Divisor b
 ! sub Ar_b+3
 ! lda Ar_c+2
 ! sbc Ar_b+2
 ! lda Ar_c+1
 ! sbc Ar_b+1
           
 ! tax            'Zwischenspeichern ergebnis accu Ar_c2 in x register
 ! lda Ar_c
 ! sbc Ar_b
 ! bcs div16_2    'carry ist gesetzt, wenn Akkumulator kleiner als Divisor
 ! sta Ar_c       'accu in Ar_c3
 ! stx Ar_c+1     'voriges ergebnis von accu, zwischengespeichert in x nun zurueck in Ar_c2
 ! lda Ar_c+3     'Ar_c1 in accu
 ! sub Ar_b+3     'Ar_b1 subtrahieren
 ! sta Ar_c+3     'ergebnis in accu zurueck in Ar_c1
 ! lda Ar_c+2
 ! sbc Ar_b+2
 ! sta Ar_c+2
 ! inc Ar_a+3      ' und LSB vom Quotienten setzen
#div16_2
 ! dbnz OSTEMP,div32_1
 ! rts
END PROC

' Procedure Wurzel aus 32 Bit Zahl
' Eingabewert=Radikand muss in Ar_a1 bis Ar_a4 sein
' Ausgabewert=Wurzelwert    in Ar_b1 bis Ar_b2
' Quadratwurzel von einer 32-Bit-Zahl, mathematisch korrekt gerundet!
' Wertebereich fuer Wurzeleingabe begrenzt auf
' bei 0...4.278.190.079==H: fe ff ff ff ==> Ausgabe 0...65408
' bei     4.294.967.295==H: ff ff ff ff ==> Ausgabe 256
' erweitert von JFenk auf 32 Bit; Mo. 23.03.2015
' nach DHarlos-SQR-Funktion aus dem Open-Micro-Betriebssystem fuer 8Bit Zahl
' Ur-Algorithmus stammt von Rene Stadler alias Topmail
' angewendetes Verfahren, von Zahl a soll die Quadratwurzel gebildet werden
' 1. SQRT (a) = (a-1)/2; dies ist die Einstiegsberechnung;wobei b das Ergebnis durch schleifennaeherung ermittelt wird
' 2. SQRT (a) = (Ergebnis aus 1.) - b; b=1 beim erstenmal;
' 3. SQRT (a) = (Ergebnis aus 2.) - b; b=b+1 usw.
' hier als Beispiel z.B. a=15
' 1-te Iteration  SQRT(a) = ((15-1)/2) -1 = (14/2) -1 = 7-1 = 6
' 2-te    "       SQRT(a) = 6 - 2 = 4 '
' 3-te    "       SQRT(a) = 4 - 3 = 1
' 4-te    "       SQRT(a) = 1 - 4 = -3  ; hier endet die Berechnung, da das Ergebnis negativ ist
' b=4 ist mathematisch korrekt gerundet; die Anzahl der Schleifendurchlaeufe = dem Ergebnis b
' es ist fuer grosse Zahlen nicht das schnellste Verfahren,
' da z.B. bei voller 32 Bit Zahl= 65408 schleifendurchlaeufe erfolgen
' in meiner Anwendung ist das Ergebnis jedoch meistens unter 1000

PROCEDURE sqrt_32 INLASM '!!!
! ldhx Ar_aw1      ' kopiert Ar_aw1 high byte=2 in H u. low Byte1 in X; index reg. H:X u setzt Flag Z, wenn wert=0 ist
! bne Test1_0     'wenn Ar_a nicht 0 ist , wird Z Flag nicht gesetzt und Sprung erfolgt
! lda #0         ' accu auf 0 gesetzt, damit Z Flag wieder zurueckgesetzt werden kann
! tap            ' accu kopiert in CCR register, damit Z bit auf 0 setzen
! lda Ar_aw2      ' kopiert Ar_aw2 high byte inH u. low byte in X; setzt Z-Flag, wenn wert Ar_a3=0 ist
' nur wenn beide Ar_aw1 und Ar_aw2=0 sind, dann soll sprung nach sqrint_2 erfolgen
! beq sqrint_2   'wenn Ar_aw1= 0 und Ar_aw2=0 branch if equal bzw. Z-bit equal=0
#Test1_0         '
! clrx           ' loescht x register
! clrh           ' loescht h-register
! lda Ar_a+3      ' erstes Byte in accu
! sub #1         ' subtrahiert von Ar_a1=accu-1; ja nicht #-1 eingeben
! sta Ar_a+3      ' neuen accuwert zurueck kopieren
! lda Ar_a+2      '
! sbc #0         ' falls carry vorher gesetzt wurde uebrtragen in accu
! sta Ar_a+2      ' neuen accuwert zurueck kopieren in a2
! lda Ar_a+1      '
! sbc #0         ' falls carry vorher gesetzt wurde uebrtragen in accu
! sta Ar_a+1      ' neuen accuwert zurueck kopieren in a2
! lda Ar_a      '
! sbc #0         ' falls carry vorher gesetzt wurde, uebertragen in accu
! sta Ar_a      '
! lsr Ar_a      ' logic shift right MSB-byte von 3byte Zahl und Bit0 in carry
! ror Ar_a+1
! ror Ar_a+2      ' roll right low word byte bzw. middle byte von 3byte wort, dabei carry von Ar_a3 in Ar_a2 bit 7 bertragen
! ror Ar_a+3      ' roll right low byte von 3byte wort, dabei carry von Ar_a2 in Ar_a1 bit 7 bertragen u. wert halbiert
                 ' (eingabewert -1)/2 berechnet
! clr Ar_b+3      ' loescht Ergebnisbyte Ar_b1
! clr Ar_b+2      ' loescht Ergebnis Byte 2
#sqrint_1        ' Schleife
! lda Ar_b+3     ' Ar_b1 in accu
! add #1         ' accu + 1 zaehlt den Wurzelergebiswert hoch durch naeherung  
! sta Ar_b+3     ' accu in Ar_a1
! lda Ar_b+2     ' Ar_b2 in accu
! adc #0         ' accu+carry von vorher
! sta Ar_b+2     ' accu in Ar_a2 zurck
                 ' nun SQRT-Naeherung berechnen
! lda Ar_a+3      ' Eingabe Ar_a1 in accu
! sub Ar_b+3      ' accu - Ar_b1    
! sta Ar_a+3      ' accu in Ar_a1
! lda Ar_a+2      ' Ar_a2 in accu
! sbc Ar_b+2      ' accu- Ar_b2-carry von vorher
! sta Ar_a+2      ' accu in Ar_a2 zurueck
! lda Ar_a+1      ' Ar_a3 in accu
! sbc #0
! sta Ar_a+1
! lda Ar_a       ' Ar_a in accu
! sbc #0         ' accu - #0 - carry von vorheriger subtraction  
! sta Ar_a      ' accu in Ar_a4 zurueck
! bcc sqrint_1   ' branch if carry bit clear; sobald carry bit gesetzt ist wird beendet
#sqrint_2    
! rts           ' Ergebnis wird ausgegeben in Ar_b
END PROCEDURE

' Subroutine zur dezimalen Ausgabe von 32-Bit-Zahlen= dez 10 stellig ohne Vorzeichen
' geaendert Sa. 14.03.2015 von JF, um integerzahlen ohne neg. Werte zu erhalten
' Wertebereich fuer Ausgabe begrenzt  
' auf  2^32 = 4.294.967.295==Hex: ff ff ff ff
' Urversion von Dietmar Harlos ADPC am 29. Juni 2006 in 32BITASM.BAS

PROC print32 INLASM
! mov Ar_a+3,Ar_c+3       'Akkumulator a nicht veraendern
! mov Ar_a+2,Ar_c+2
! mov Ar_a+1,Ar_c+1
! mov Ar_a,Ar_c
! ldx #10       ' divisior = 10 in x register laden
! clr OSTEMP
#print32_2
! inc OSTEMP    ' zaehlt hoch
! clrh          ' high byte of dividend =0 gesetzt
! lda Ar_c      ' lade dividend low byte in accu
! div           ' Division durch 10;quotient in accu; remainder in H
! sta Ar_c
! lda Ar_c+1
! div
! sta Ar_c+1
! lda Ar_c+2
! div
! sta Ar_c+2
! lda Ar_c+3
! div
! sta Ar_c+3
! pushh         'pushh = pshh  remainder in H auf stack speicher
! ora Ar_c+2    ' vergleich accu mit ar_c+2
! ora Ar_c+1
! ora Ar_c
! bne print32_2 'branch if not equal; test Z bit of CCR and branch if Z=0
#print32_3
! popa          'Ziffern holen von stack und ausgeben;  popa=0pula
! add #"0"
! jsr FwPutSci
! cli           ' clears interrupt bit I = bit 3 of CCR  
! dbnz OSTEMP,print32_3 'decrement and branch if not zero; wenn OSTEMP>0 sprung zu print32_3
! rts
END PROC

' ---------------------------------------------------------------------------
INCLUDE "OM_FW.PRO"

 Antwort schreiben

Bisherige Antworten: