16bit * 8bit Multiplikation - Hilfe

  • 16bit * 8bit Multiplikation - Hilfe

    Hi zusammen,

    ich bin weiter fleissig am lernen und coden und habe ein kleines Problem.

    Ich verwende folgenden Code aus der Codebase64: 16bit * 8bit

    In meinem Projekt kommt dann folgendes als Code dabei raus:

    Quellcode

    1. Speicherinhalte: fa: #$01
    2. fb: #$40
    3. fd: #$06
    4. lda #$00
    5. tay
    6. beq enter
    7. doAdd clc
    8. adc $fa
    9. tax
    10. tya
    11. adc $fb
    12. tay
    13. txa
    14. loop asl $fa
    15. rol $fb
    16. enter lsr $fd
    17. bcs doAdd
    18. bne loop
    19. stx $fa
    20. sty $fb
    Alles anzeigen
    Als Ergebnis würde ich nun #$0780 erwarten, also in fa #$07 und in fb #$80 - aber ich habe als Ergebnis im Speicher dann #$0680 stehen ?(

    Hab ich jetzt einen Fehler drin (den ich selbst nach Stunden des intensiven Anstarrens nicht entdecke) oder ist der Codeschnipsel schon fehlerhaft?



    Grüße,
    Schnippe
  • Damit die 16-Bit-Addition mit Carry-Übertrag funktioniert, muss $fa das Lowbyte und $fb das Highbyte sein (also little-endian, wie auf dem 6502 üblich).

    Außerdem solltest Du das STX am Ende durch STA ersetzen, sonst kann man nicht mit Null multiplizieren.
    Yes, I'm the guy responsible for the ACME cross assembler
  • Nur mal so als Frage:

    Was machst du auf der Zeropage in der Adresse $fa? Da sitzt das Highbyte (MSB) der Adresse des Ausgabebuffers der RS232-Schnittstelle.

    Üblicherweise nimmt man doch $fb bis $fe, zur Vermeidung von Seiteneffekten, die Stellen sind dafür gedacht.
  • Deus schrieb:

    Was machst du auf der Zeropage in der Adresse $fa? Da sitzt das Highbyte (MSB) der Adresse des Ausgabebuffers der RS232-Schnittstelle.

    Üblicherweise nimmt man doch $fb bis $fe, zur Vermeidung von Seiteneffekten, die Stellen sind dafür gedacht.
    Die Belegungen kann man nur beachten, wenn man sie auch kennt. Früher (tm) habe ich auch $fa bis $ff für eigene Daten benutzt, aber ich hab keine Ahnung, woher die (falsche) Bereichsinformation ursprünglich stammt.
    Da die wenigsten Programme gleichzeitig mit RS232 eingesetzt werden, macht sich der Fehler normalerweise auch nie bemerkbar (bei $ff sieht das schon anders aus, das hat mindestens einmal Probleme gemacht).
    Yes, I'm the guy responsible for the ACME cross assembler
  • Also ich bin ziemlich neu im Asm für den C64, ich hab einfach mal nachgefragt.

    In seiner Quelle (codebase64) werden nur Labels verwendet. Vielleicht wäre da auch was gewesen "was ich nicht weiß" ™.

    Danke für die Antwort.
  • Ich wollte einfach für das ganze Projekt (die Multiplikation ist hier nur ein kleiner Teil) einen möglichst zusammenhängenden Block an ZP-Adressen haben, deswegen habe ich einfach die ZP-Adressen mitgenommen welche für RS232 benutzt werden. Denn das kommt mir hier ganz sicher nicht in die Quere. :D

    Bezüglich der Geschwindigkeit habe ich noch keine Tabellenversion implementiert, ich wollte eigentlich so platzsparend wie möglich sein da es im Projekt (zumindest im Moment) nicht auf Geschwindigkeit ankommt. Aber danke für den Hinweis - wird sicher auch noch mal getestet.
  • peiselulli schrieb:

    Das, was Du da jetzt umgesetzt hast, ist die langsamere, dafür aber speichersparende Variante. Die Tabellen-Versionen gehen DEUTLICH schneller.
    Wenn die Multiplikation laufzeitmäßig zu einem "Hotspot" wird, sollte man aber schon überdenken, ob man nicht "versehentlich" eine Multiplikation verwendet, obwohl eigentlich eine Aufsummierung (im Anwendungscode!) in den Iterationen auch funktionieren würde. Sprich, in:

    1. FORT=1TO100:PRINT10*T:NEXT

    2. S=10:FORT=1TO100:PRINTS:S=S+10:NEXT

    ... ist die Multiplikation im ersten Fall erheblich "teurer" als die laufende Summation im zweiten Fall.

    ...

    Für eine Routine zum Zeichnen von Ellipsen brauchte ich auch mal eine 8 Bit x 24 Bit -> 32 Bit Multiplikation. Vier Zeropage-Adressen dienen als 32-Bit-Ergebnis/Akkumulator, der 24-Bit-Faktor steht immer bei höheren Adressen, die aber innerhalb einer Page mit dem Y-Register indexiert werden (das sind also die Arbeitsvariablen), der andere Faktor steht im Akku und es gibt eine Routine, um das 32-Bit-Ergebnis/Akkumulator in eine der Arbeitsvariablen (zurück) zu übertragen (wieder ebenfalls Y-indexiert):

    Quellcode

    1. .Mult
    2. STA $06
    3. LDA #0:STA $03:STA $04:STA $05
    4. LDX #8
    5. .Mult_00
    6. ASL $03:ROL $04:ROL $05:ROL $06
    7. BCC Mult_01
    8. CLC
    9. LDA $03:ADC Base+0,Y:STA $03
    10. LDA $04:ADC Base+1,Y:STA $04
    11. LDA $05:ADC Base+2,Y:STA $05
    12. LDA $06:ADC #0 :STA $06
    13. .Mult_01
    14. DEX:BNE Mult_00
    15. RTS
    16. .Move
    17. LDA $03:STA Base+0,Y
    18. LDA $04:STA Base+1,Y
    19. LDA $05:STA Base+2,Y
    20. LDA $06:STA Base+3,Y
    21. RTS
    Alles anzeigen
    Die Ellipsen-Routine führt nur ein paar Multiplikationen am Anfang aus, der Rest der Routine arbeitet dann mit 32-Bit-Additionen, -Subtraktionen, -Absolutwertbildungen und -Vergleichen. :)


    P.S. $03..$06 sind ebenfalls frei. Sie werden zwar vom Interpreter mit Adressen zu Umwandlungsroutinen FAC <-> Integer belegt, aber nie benutzt. Und alle Programme, die mir so untergekommen sind, springen die Routinen auch direkt an. ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Mike ()