Aus Basic gelesenen Wert in HexWord ändern

  • Hallo!


    Ich möchte einen Hexadezimal-Word, dass ich aus der Basic Eingabe habe und nun in 4 Bytes steht in ein 16-Bit-Hexwert abspeichern.


    Irgendwie denk ich da aber zu umständlich oder ist es so schwierig?


    Beispiel:


    Im Speicher steht:
    $31,$41,$30,$30


    Ich möchte im Speicher als Ergebnis:
    $1A,$00


    Kann mir da jemand weiterhelfen? Achja, dieses Beispiel soll auf nem 6502 laufen.


    Gruss
    Thomas

    -------------------------------------------------------------------------------------------------------------------


    Ich bin immer auf der Suche nach Ersatzteilen und Elekronikrestposten.
    Bitte an mich denken, wenn Ihr über Angebote stolpert!

  • Mir ist ja ein bißchen unklar, wie Du von den vier Einzelwerten auf das Wunschergebnis kommst.
    Ich könnte das Problem evtl. nachvollziehen, wenn Du möchtest, daß da immer zwei von den 4 Werten in einem Wert zusammengefaßt werden sollen. Das würde natürlich voraussetzen, daß die Eingabewerte immer kleiner als $80 sind. Dafür würde man den ersten Wert laden, das Register shiften und den zweiten draufaddieren. Mit dem Pärchen drei/vier macht man das genauso.


    Ungefähr sowas ??


    .d1 $31
    .d2 $41
    .d3 $30
    .d4 $30
    .ergebnis


    CLC
    LDA d1
    SBC #$30
    ROLA
    ROLA
    ROLA
    ROLA
    STA ergebnis
    LDA d2
    CLC
    SBC #$30
    ADC ergebnis
    STA ergebnis


    edit: DECrement versucht zu berücksichtigen - nach Hinweis von Joe_IBM.
    Kann immer noch Blödsinn sein, was das steht ... aber so die Richtung müßte passen. Zumindest aber sollte das .ergebnis in der Zeropage stehen, damits was schneller wird.

  • Ich würde erstmal einen DEC #$30 auf alle Stellen machen, gibt $01, $11, $00, $00.
    Dann mit der ersten Stelle 4 mal ein Shift Left: $01 -> $10
    Bei der zweiten Stelle prüfen, ob sie >$10 ist, dann DEC #$06: $11 -> $0A
    Schließlich die beiden Stellen addieren: $10 + $0A = $1A


    Für die beiden hinteren Stelle das Gleiche. Wenn Du Fragen dazu hast,kann ich das ganze mal in meinen Apple tippen und testen. Sollte aber so wie beschrieben funktionieren...


    Gruß, Jochen


    ThoralfAsmussen: Du warst 2 Minuten schneller ... hast aber den Decrement vergessen, um auf die Werte zu kommen, die guenner braucht.

  • Das sieht doch sehr gut aus. Vielen Dank euch beiden!


    Wobei mein Code natürlich für verschiedene Werte stimmen soll, da es nur ein Beispiel war. Also muss ich folgende Reihenfolge durchführen:
    Von allen 4 Bytes $30 abziehen, dann auf groesser 10 testen. Wenn ja, die $11-$16 gegen $0A-$0F (DEC #$06) austauschen und dann beim 1. und 3. Wert das Shifting machen. Danach muss ich nur noch Byte 1+2 und 3+4 addieren und bin fertig.


    Richtig?

    -------------------------------------------------------------------------------------------------------------------


    Ich bin immer auf der Suche nach Ersatzteilen und Elekronikrestposten.
    Bitte an mich denken, wenn Ihr über Angebote stolpert!

  • Moin,


    da musste ich gleich an die seligen C64-Zeiten denken, als man Assembler noch direkt am Rechner per Hexcodes programmieren konnte... "64 intern" als Tageszeitungsersatz... ;-)


    Ich hab mal versucht, das obige "Problem" etwas universell aufzubauen. Zwar hab ich ewig nicht mehr 6502/6510-Assembler geschrieben, aber das ist wie Radfahren - verlernt man nie so ganz.


    Ich denke, in der obigen Version sind noch kleinere Fehlerchen drin: vor SBC gehört ein SEC, kein CLC, sonst wird ein Übertrag gerechnet; von ASCII "A" muss man nach #$30 noch #$07 (nicht #$06) abziehen, um wie gewünscht #$0a zu erhalten; man sollte unbedingt auf gültige Zeichen prüfen und dann die Nibbles mit OR verknüpfen, sonst kommt bei Addition und gleichzeitig "böswilliger" Eingabe ungültiger Zeichen nur Müll raus...


    Herrlich, so wieder in die Mitt-80er versetzt zu werden.


    Hier also mal mein Vorschlag - ohne Garantie, dass da nicht auch noch ein Fehler den Nebel des Erinnerns genutzt haben könnte... (Leider entfernt der Editor hier alles, was eine Kommentierung übersichtlicher machen könnte...)


    Data:
    $31, $41, $30, $30
    Highbyte:
    $00
    Lowbyte:
    $00


    Main:
    LDA Data ; Erstes Byte aus Speicher (oder von Tastatur) holen
    JSR Convert ; per Subroutine konvertieren
    BCS Was_Invalid_Char ; Carry-Flag=1 heisst, dass das Zeichen keiner Hex-Zahl entspricht, also Fehler
    ASL A ; ROL A ginge hier auch, obwohl der Befehl den Zustand des Carry-Flags mit in den Akkumulator hineinrollt - das Carry ist aber hier eh = 0
    ASL A ; 4x Arithmetical Shift Left (also ohne das Carry-Flag versehentlich reinzurollen)
    ASL A
    ASL A
    STA Highbyte ; Oberes Nibble des Highbyte für das 16-Bit-Wort zwischenlagern
    LDA Data+1 ; nächste "Text-Zahl" holen
    JSR Convert ; und konvertieren
    BCS Was_Invalid_Char ; war es eine Zahl ("0" bis "9" oder "A" bis "F")? Dann ist Carry = 0, sonst ist Carry = 1
    ORA Highbyte ; Logisches Oder mit dem gespeichtern oberen Nibble des Bytes, vermeidet erneut Probleme mit Carry-Flag etc.
    STA Highbyte ; und fertig ist das erste (= High) Byte...


    LDA Data+2 ; Gleiches Spiel mit den folgenden 2 Zeichen, die das LowByte generieren
    JSR Convert
    BCS Was_Invalid_Char
    ASL A
    ASL A
    ASL A
    ASL A
    STA Lowbyte
    LDA Data+3
    JSR Convert
    BCS Was_Invalid_Char
    ORA Lowbyte
    STA Lowbyte


    ; Ab hier steht die Adresse im gewünschten Format in den beiden Speicherzellen "Highbyte" und "Lowbyte" im Speicher und kann genutzt werden.
    ; Macht ggf. Sinn, die Adressen in die Zeropage zu legen, damit man sie dort direkt über die indirekte Adressierung nutzen könnte...
    ..
    ..
    ..


    Was_Invalid_Char:
    ; Ab hier dann Fehlerbehandlung - es könnte unerwünscht sein, wenn z.B. ein "X" oder ein Steuerzeichen von der Routine automatisch als "0" oder eine andere Zahl gewertet würde.
    ; Deshalb werden unzulässige Zeichen bei der Konvertierung ausgesiebt. Behandlung dann ab hier (Fehlermeldung ausgeben etc.).
    ..
    ..
    ..



    ; Subroutine zur Konvertierung


    Convert:
    SEC ; Carry-Flag setzen (ein UNgesetztes Carry signalisiert bei SBC einen Überlauf der vorherigen Operation)
    SBC #$30 ; ASCII "0" subtrahieren
    BCC Error ; Überlauf, also war das Zeichen keine Zahl
    CMP #$0A ; Rest größer als #$09?
    BCC Number ; Nein, also gültige Zahl zwischen 0 und 9!
    SBC #$07 ; von "A" wäre nach der 1. Subtraktion #$11 übrig, also müssen für #$0A weitere #$07 abgezogen werden
    CMP #$0A ; Ergebnis kleiner als #$0A?
    BCS Error ; falls ja, dann Fehler - die gültigen Zahlen kleiner als 10 waren oben schon durch...
    CMP #$10 ; Ergebnis größer als #$0F?
    BCC Number ; Nein, also gültige Ziffer, nun zwischen #$0A und #$0F


    Error: ; Einsprung bei Fehler
    SEC ; Carry-Flag setzen als Zeichen für Error


    Number: ; Einsprung bei erkannter Zahl - hier ist das Carry als Flag IMMER ungesetzt
    RTS ; Rückkehr aus Subroutine





    Sooooo, hoffentlich nix übersehen... die Flags beim 6502 waren früher schon immer lustig.


    Vielleicht hilft der Ansatz ja weiter.


    Liebe Grüße aus Frankfurt,


    Ralph.

  • Hmm, alles so kompliziert dargestellt


    Im Grunde genommen hast Du einen String, (im Beispiel "1A00") den Du in ein 2-Byte Integer speichern willst.


    Ich kenn jetzt Deinen Basic-Dialekt nicht, aber es sollte so aussehen: S$: Dein String, E: Ergebnis

    Code
    1. (AppleSoft BASIC)
    2. INPUT S$
    3. E = 0
    4. FOR I=1 TO LEN(S$)
    5. C$=E = E * 16 + (ASC(MID(S$,I,1)) - 48) : REM Bisheriges Ergebnis mit 16 multiplizieren und den Wert des I. Zeichens aufaddieren
    6. NEXT I
    7. PRINT E


    -- Klaus


    EDIT: Ups - man sollte vorher testen, bevor man etwas schreibt - wenn das Zeichen zwischen "A" und "F" ist, muss man natuerlich 55 statt 48 abziehen

    [ ... to boldly code where no byte has gone before ... ]

    Edited 2 times, last by ktf ().

  • Hmm, alles so kompliziert dargestellt


    [..]



    Stimmt, es ist ein wenig unklar, was das Ziel und die zu wählende Programmiersprache betrifft. Allerdings haben wir wohl aus dem direkten Verweis auf im Speicher abgelegte Bytes (die bzgl. der Quelle "aus der Basic Eingabe" kommen, und insbesondere wegen der gewünschten Lauffähigkeit auf einem 6502 auf Assembler (hoffentlich richtig) geschlossen. In Basic ist die Lösung des "Problems" natürlich trivial und in wenigen Zeilen erledigt.


    Ich denke mal, Guenner wird irgendwas hiervon schon nutzen können. Achja, noch ein Hinweis - den DEC-Befehl des 6502 gibt es nicht in einer Immediate-Adressierung. Der Inhalt der als Argument angegebenen Adresse (bzw. des Registers) wird von dem Befehl immer fix um den Wert 1 vermindert. Um 6 (oder korrekter hier: 7) abzuziehen, muss man entweder eine entsprechende Anzahl an DEC-Befehlen aufreihen, oder man macht das mit der Kombi aus SEC (Set Carry Flag) und SBC #Wert (Wert von Akkumulator-Register subtrahieren).


    Ohje, die Erinnerung kommt schlagartig zurück...


    Raster-Interrupts... undokumentierte Opcodes des 6510... Zeropage-Tricks... eigene Basic-Erweiterungen... herrlich.


    Grüße,
    Ralph.

  • Ok, ok, ich hab das etwas kompliziert ausgedrueckt. Aber dank Ralph muss ich ja nicht mal mehr selber denken.


    Es geht darum, dass ich verschiedene kleine Tools in Assembler programmiert habe (für C16 und C64) und da übergebe ich mittels SYS 1234,3000 Parameter. Dezimal ist das mit Kernalroutinen kein Problem. Aber ich wollte es auch in Hex machen. Wenn ich also SYS 1234,$1A00 übergebe, soll das auch funktionieren. Die Dollar-Auswertung ist erledigt.


    Ich freue mich schon, wenn ich den Code ausprobieren kann. Heute muss ich leider lange arbeiten.

    -------------------------------------------------------------------------------------------------------------------


    Ich bin immer auf der Suche nach Ersatzteilen und Elekronikrestposten.
    Bitte an mich denken, wenn Ihr über Angebote stolpert!