Methoden zur optimierten Berechnung von Addition, Multiplikation,
Division und elementaren mathematischen Funktionen in
Hardware-
Es gibt wöchentlich auszuarbeitende Übungen. Anwesenheit ist wichtig. Es gibt drei kleine Tests, in denen genau die wöchentlichen Übungen unverändert auf Papier zu lösen sind. Die zu modifizierenden Programme sind dabei vorgedruckt verfügbar. Die Mini-Tests werden am 23. April, am 21. Mai und am 25. Juni stattfinden.
Der gesamte Sourcecode der Algorithmen aus dem Skriptum in einem File.
Alluvion, die Programmiersprache compiliert für Linux oder im Sourcecode.
bis 12.3.: Implementiere einen Subtrahierer (HalfSub, FullSub, Sub<n>) analog zum Addierer.
bis 19.3.: Modifiziere den RCLA_Add-Algorithmus so, dass
  das global hereinkommende Carry-Bit ohne Zwischenverarbeitung an
  jeder Bitstelle zur Berechnung verwendet wird. Also, dass
  z[i]=xor(or(g,and(p,c)),xor(x[i],y[i])) ist, wobei
  g,p die Generate- und Propagate-Bits des Blocks
  x[0:i-1]+y[0:i-1] sind. Letztere sollen
  aber nach wie vor in logarithmischer Komplexität berechnet
  werden.
bis 26.3.: Erzeuge eine Funktion analog zu
  CondSum_Add, die kein incoming carry annimmt
  (d.h. einfach Addition zweier Zahlen x+y). Der rekursive Aufruf mit
  fixem Carry 0 kann dann auch durch einen Aufruf dieser Funktion
  ersetzt werden. Für fixes Carry 1 empfiehlt sich dann eine eigene
  Funktion analog zu ersterer. 
 Hier noch die modifizierte Version
  der Funktion CondSum_Add aus der VL.
bis 16.4.: Erzeuge eine Funktion (p,z[0:n]) =
  RCS_Add<n> (x[0:n-1], y[0:n-1], c),
  die die CarrySkip-Addition rekursiv durchführt. Wenn
  n>1, dann müssen folgende Schritte durchgeführt
  werden: (1) Rekursiver Aufruf für untere Hälfte [0:m-1] (liefert
  p0 und c0). (2) Rekursiver Aufruf für
  obere Hälfte [m:n-1] unter Verwendung von c0. (3) p aus
  p0 und p1. (4) cout mit der
  CarrySkip-Formel aus cin, c1
  und p. Wenn n=1, p und
  z[0:1] berechnen wie üblich.
Implementiere einen (7,3)-Zähler
    (z[0,2]=Count7(x[0,6])) allein mit
    Hilfe von (3,2)-Zählern (also Aufrufen von
    FullAdd).
freiwillig: Verwende den (7,3)-Zähler in
    CS_Add_Gen.
bis 30.4.: Implementiere eine Funktion
  z[0,n+m-1]=RMul<n,m>(x[0,n-1],y[0,m-1]), die
  z=x*y berechnet, indem sie rekursiv für k=m/2
  zuerst RMul<n,k>(x[0,n-1],y[0,k-1]) und dann
  RMul<n,m-k>(x[0,n-1],y[k,m-1]) aufruft und dann
  die Ergebnisse richtig zusammenzählt (d.h. das zweite Ergebnis um
  k Stellen nach links verschoben). Falls
  m=1 ist (Rekursionsabbruch), soll das Ergebnis
  natürlich z[0,n-1]=And<n>(x[0,n-1],y[0])
  sein.
bis 7.5.: Implementiere die Funktion
  MulRadix8, die eine Multiplikation zur Basis 8
  realisiert. (Das modifizierte MulRadix4
  hätte ich fast vergessen.)
bis 14.5.: Implementiere die Funktion (q[0:n-2],
  r[0:1]) = Div3<n> (x[0:n-1]), die die Zahl x
  durch 3 dividiert und Quotient q und Rest
  r ausgibt. Anleitung: Wenn im Schritt
  i der Divisor 3 vom Zwischenrest r[i:i+2]
  subtrahiert wird (oder auch nicht), ergibt sich das Quotientenbit
  daraus, ob der Zwischenrest größer oder gleich 3 ist. Das ist genau
  dann der Fall, wenn r[i+2]='1' ist oder
  r[i:i+1]='11'. Das Subtrahieren von 3 (wenn das
  Quotientenbit 1 ist), entspricht einer Addition von
  '00' mit Carry-In '1'. Wenn
  nicht subtrahiert wird, kann man ebenfalls
  '00' addieren, aber es muss das Carry-In auch
  '0' sein. Dadurch wird das ganze einfach. Das
  Addieren führt man am besten händisch durch, d.h. ohne eine
  XY_Add-Funktion, weil der Summand ja eh
  '00' ist.
bis 21.5.: Implementiere analog zur vorigen Aufgabe eine
  Non-Restoring-Division durch 3. Achtung: Der ausgegebene Rest
  r[0:2] braucht ein Bit mehr, weil er negativ sein kann.
  Und am Anfang muss r[n] = x[n-1] gesetzt werden.
bis 4.6.: Verbessere die SRT-Division folgendermaßen:
Zeile 9-12: Führe die Addition s[0,3] =
      r[i+n-2,i+n+1] + rc[i+n-2,i+n+1] unter Verwendung von
      (g1,p1)=GP(r[i+n-1],rc[i+n-1]),
      (g2,p2)=GP(r[i+n],rc[i+n]), und
      (g,p)=GP_Op(g1,p1,g2,p2) durch.
Zeile 24-29: Ersetze Add durch
      RCLA_Add. Führe die Umwandlung von q1
      und q0 in q mittels einer (rekursiven)
      Funktion
      (g,p,q[0,n-1])=S2U<n>(q1[0,n-1],q0[0,n-1],c)
      durch. Diese Funktion ist analog zu RCLA_Add zu
      implementieren. Unterschied: im Fall n=1 ist
      q[0]=xor(q0[0],c), g=and(q0[0],q1[0])
      und p=and(not(q0[0]),not(q1[0])).
bis 11.6.: Modifiziere die Funktion Msf_Div
  so, dass bei der Multiplikation mit r
  (bzw. dc im Skriptum) die Struktur von r
  berücksichtigt wird: und zwar stehen die ersten k Bits
  von r fest (k vor der
  Multiplikation mit 2). Das erste ist 1, die nachfolgenden sind 0.
  Übergebe dazu k and PCS_Mul und lasse dort
  iy nur bis ny-k-1 gehen. Das vorderste
  Bit von y, das ja immer 1 ist, muss dann extra
  behandelt werden.
bis 18.6.: Modifiziere die Funktion
  Sqrt<n> so, dass sie auch für ungerade
  n funktioniert.
bis 25.6.: Wandle die Funktion Expsf in
  eine Funktion Pow2 um, die statt e-hoch-x 2-hoch-x
  berechnet. Dazu sind die Werte der Tabelle lntab
  durch 2-er-Logarithmen zu ersetzen.
I. Koren. Computer Arithmetic Algorithms. A.K. Peters Ltd., 2001. ISBN 1568811608. (45.2.1-77)
A. R. Omondi. Computer Arithmetic Systems: Algorithms, Architecture, and Implementation. Prentice Hall, 1994. ISBN 0-13-334301-4. (46.1.2-5)