Hallo Besucher, der Thread wurde 2,1k mal aufgerufen und enthält 13 Antworten

letzter Beitrag von faddie am

(mulitbyte) BCD Subtraktion: 1-2 = 99 ?!

  • Huhu,


    ich stehe gerade vor diesem Problem.
    Ich habe einen Counter, der irgendwann mal 32bit groß werden soll - momentan übe ich mit 16 bit. Dieser Counter soll auch negativ werden können und hier besteht auch schon das Problem. Sobald ich den Nullpunkt durchschreite, fängt der Counter bei 9999 wieder an.


    Irgendwas scheine ich also zu vergessen.
    Die Subtraktion ist eigentlich ganz simpel: pro Byte mache ich das hier (was auch bis 0 funzt)


    sed
    sec
    lda Urspungswert
    sbc Wert
    sta neuer Wert
    cld



    Aber was mache ich ab 0? V Flag prüfen und ab wieder addieren? Oder irgendwas Schlaues mit FF in der Anzeige?
    Hat jemand eine Idee?

  • hm also ich wuerde das genau wie bei hex machen.


    jetzt weis ich aber nicht inwiefert der dezimal modus das carry richtig setzt, das muessten evtl die profis klaeren koenne.


    noch was zum 16bit dezimal modus. normaler weise geh ich davon aus das im DEZIMAL MODUS die groesste zahl 9999 ist.
    da ja jedes byte nur bis 9 statt bit 16 zaehlt. ergo gehe ich auch davon aus das wenn ich unter 0 zaehle ich ein 9999 oder
    kleinere zahl herraus bekomme. bei hex kmm ich ja auch bei ffff oder kleiner raus ne.


    hoffe ich konnte helfen auch wenn ich vom dezmodi nich wirklich plan hab.


    salute

  • Hat jemand eine Idee?

    a) keinen Dezimalmodus verwenden
    b) vor der Subtraktion die Größen vergleichen (inklusive der Vorzeichen), ggfs. die Operatoren vertauschen und ein Flag für "beim Ergebnis das Vorzeichen ändern" setzen.
    c) nach dem letzten Byte per BCC zur Fehlerbehandlung springen
    d) auf negative Zahlen verzichten...


    Ich empfehle a)
    :D

  • @Haubitze: Das klappt auch, aber bei < 0 müsste es doch auch wieder 'überlaufen' .


    @Mac Bacon: Im Falle von a) ist dann aber eben 0x01 - 0x02 = 0xFF
    Nach a) ist also noch nicht das Ende der Fahnenstange.


    In meinem "Spiel" soll es möglich sein, dass man Schulden machen kann. Ich könnte natürlich auch noch einmal 4 Bytes für ein Schuldenkonto aufmachen, aber irgendwie will ich's auch verstehen ;)



    Am Dezimalmodus soll es aber nicht scheitern, ich nehme auch gerne Hex.

  • also gut dann halt in hex ;)



    nun brauchts nur noch eine hex2ascii routine und du hasst deine kontofunction ;D
    edit:sehe gerade das meine check_minus routine wohl noch nicht ganz ausgereift ist... naja

  • Grundsätzlich ist es natürlich egal, ob Du den Dezimalmodus verwendest oder nicht, lösen lässt sich das Problem in beiden Fällen: Du brauchst nur eine interne Repräsentation für negative Zahlen. Bei Integers wird üblicherweise das oberste Bit als Vorzeichenbit benutzt, im BCD-Modus ist mir kein so schöner "Standard" für die Markierung bekannt.


    Als Beispiel mit 16 Bits:


    unsigned int:
    $0000 steht für 0
    $7fff steht für 32767
    $8000 steht für 32768
    $ffff steht für 65535



    BCD (unsigned):
    $0000 steht für 0
    $9999 steht für 9999


    signed int:
    $8000 steht für -32768
    $ffff steht für -1
    $0000 steht für 0
    $7fff steht für 32767


    "signed BCD", wenn man es äquivalent zum signed int macht:
    $5000 steht für -5000
    $5001 steht für -4999
    $9998 steht für -2
    $9999 steht für -1
    $0000 steht für 0
    $4999 steht für 4999


    Egal ob BCD oder nicht: Die Ausgaberoutine muss das Vorzeichen überprüfen und ggfs. ihr Verhalten anpassen (also bei INT vom Zahlenwert das Zweierkomplement bilden, oder bei BCD die Zahl von 10000 subtrahieren), denn in der internen Repräsentation ist das Ergebnis von "1 minus 2" in beiden Fällen völlig korrekt.


    Natürlich kann man es auch noch machen wie bei den Floats und ein Extra-Vorzeichen mitschleppen:
    BCD mit Extra-Vorzeichen:
    "-" $9999 steht für -9999
    "-" $0001 steht für -1
    "-" $0000 steht für 0
    "+" $0000 steht für 0
    "+" $0001 steht für 1
    "+" $9999 steht für 9999


    Jetzt ist die Ausgabefunktion trivial einfach, dafür muss man aber vor jeder Rechnung die möglichen Vorzeichenwechsel überprüfen und beachten. Außerdem gibt es bei dieser Variante die zusätzliche Komplikation, dass es zwei verschiedene Darstellungen für die Null gibt.

  • wieder mal schoen auf den punkt gebracht Mac Bacon, besser koennte ich das auch nicht erklaeren. :thnks:
    ergo einfach signed int benutzen und man muss sich beim rechnen nicht noch um irgenwelchen probleme
    kuemmern. gut man braucht halt eine ausgaberoutine die vorher von hex zu dez convertiert
    aber das ist ja auch eher trivial ;D

  • Nur so ein bisschen zu Thema praktische Assemblerprogrammierung ...

    • subtract_16bit:
    • lda konto_low
    • clc <- hier gehört sec (immer bei Subtraktion)
    • sbc wert_low
    • sta konto_low
    • lda konto_high
    • sec wert_high <- muss wohl sbc wert_high heißen (ist wohl ein Typo)
    • sta konto_high
    • rts
    • check_minus:
    • lda konto_high
    • bpl plus
    • lda #01
    • sta flag
    • rts
      [..]


      Das Flag würde ich in Bit 7 abbilden, weil man das ohne ein Register anzupatzen prüfen kann (bit flag; bpl/bmi ...)
      Das braucht man dann nur honto_high übernehmen, eventuell mit isoliertem Bit 7, wenn man unbedingt will (oder
      einem ein Prüfen auf Zero wichtig ist), also


      lda konto_high
      and #$80 ; optional
      sta flag
      rts


      Das Flag löschen kann man dann auch leicht ohne ein Register zu benutzen, nämlich mit lsr flag oder setzen mit sec; ror flag


      Man könnte sich auch gleich das Flag "flag" ersparen, indem man gleich konto_high prüft, wie schon oben angedeutet:


      bit konto_high
      bpl plus
      bmi minus

  • Jetzt hab ich doch noch eine doofe Frage:
    Wie stelle ich denn -0001 dar?


    0000 ist ja plus 0
    und
    ffff ist minus 1


    Wenn ich das zweier Komplement bilde, kommt bei ffff dann leider -0101 heraus


    Der Hintergrund ist der, dass ich versuche, das alles in ein schlaues Makro zu stecken. Und weil es hauptsächlich von 64bites geklaut ist und auch noch in Kickassembler Syntax, ist es mir peinlich, hier zu posten ;)


    Ach, egal :schande:


    Da habe ich jetzt einen Fix drin, der es aber nicht bringt. Das wäre jetzt 3, 2, 1, 0, -0 ,- 2, -3 usw.
    ohne cmp #$00 kommt besagtes -0101 bei raus.

  • Wie stelle ich denn -0001 dar?


    0000 ist ja plus 0
    und
    ffff ist minus 1


    Wenn ich das zweier Komplement bilde, kommt bei ffff dann leider -0101 heraus

    Das Zweierkomplement wird gebildet, indem sämtliche Bits invertiert werden und anschließend "1" zu der Zahl hinzuaddiert wird. Also zu der Zahl, nicht zu jedem Byte!
    Alternativ kann man auch "1" subtrahieren und dann alle Bits invertieren, das funktioniert natürlich auch.
    Ich würde die beiden Dinge (Negation und Ausgabe) in separate Funktionen packen, das wird sonst zu unübersichtlich.

  • Ich wollte nur schnell Erfolg zurückmelden. Vielen Dank an alle!