Z80 Assembler Beispiel treibt mich zum Wahnsinn

  • Hallo Leute,

    Ich versuchte heute mein ersten Z80 codeseqment zu Programmieren. Da ich von der 6502 seite komme habe ich irgendwie Verständisschwierigkeit das umzusetzen:

    Ich möchte ein Programm in den Speicher schreiben welches

    dec RamWertAusSpeicherzelle FE80

    springe wenn ungleich 0 nach Weiter

    setze Speicherzelle auf 16

    Springe zu $0038

    Weiter:

    Springe $0010

    Habe das so ausformuliert:

    ld a,(fe80)

    dec a

    ld (fe80),a ; zurückschreiben

    jr nz, weiter

    ld fe80,$10

    jp $0038

    Weiter:

    jp $0010

    Irgendwie kann ich das nicht fehlerfrei assemblieren....

    Weiß jemand wie so ein einfaches Beispiel laufen kann ?

    grüße

    Mos

    • Offizieller Beitrag

    Zilog Mnemonics kennt kein $

    Hex-Werte bekommen ein h am Ende.

    Erstes Zeichen bei Hexwerten muss 0-9 sein. (Wird sonst als Label interpretiert.)

    also 0FE80h

    ld fe80,$10

    geht nicht. Musst du ueber den Akku machen.

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Ist das Progrämmchen - als File vorhanden - oder ich denke sowas haust du die Instruktionen in einen ART DEBUGER wie z.B. ZSID... oder.. anders in den Speicher?

    Egal wie auch immer : Diese Speicherzelle ist offenbar eine HEXA- Adresse, oder?

    Je welche Tools du benutzt sind für HEXA Konstanten in diversen schreibweisen zu beachten.

    BEi manchen 0FE80h oder manche etwa so $FE80 oder auch 0xFE80 .. und mehr Varianten beim Tool beachten.

    Wenn dieses SYMBOL FE80 nicht definiert war - offenbar einfach da ein "HEX Wert FE80" als Speicher-Adresse "ansagen".

    Deine Toolumgebung ist unbekannt - also selber forschen bitte.

    Ich meine da ich extrem von der 8080/8085/8086 Assembler-Seite komme - aber schon kleine Z80 mal damit vor 30 Jahren gespielt;

    In deiner Anweisung ld fe80,$10 - soll deine Bedeutung auf der Speicheradresse hexa fe80 der WERT mit hexa 10 belegt werden. ( vermutlich) .

    Eine Konstante auf eine direkte Speicheradress zu übertragen geht in der Z80 / oder 8080/8085 bei der Befehlsmatrix nicht.

    1) Methode

    Es geht über den Accu zuerst LD A,16 da hast du kein Prefix bei der dezimal 16, dann mit

    LD (word),A - "word" muss in deinem Tool die Speicheradress richtig benennen.

    2) Methode

    HL Registerpaar mit der Adresse von wert laden ( LD HL,wert ), und dann unter der Adress von momentan ( HL) also ( LD (HL),byte ) die Konstante byte speichern.

  • Vielen Dank für die nützlichen Infos.

    Danke für den Tip über den Akku eine Speicherzelle zu decrementieren.

    Ich habe mein Beispiel in verschiedenen Online Assembler(in ermangelung eines passenden Windows Z80 ASM) websites eingegeben und keine hat es fehlerfrei assembliert.

    Meine alten DOS Z80 Assembler habe ich verloren da mein alter 1995 Laptop das zeitliche inzwischen gesegnet hat (Dalls Uhrbatterie im Eimer)

    BIOS kommt nicht klar weil ich die Festplattenparameter (heads,cylinder,bla bla) inzwischen vergessen habe und damals zu dumm war

    das auf die Platte zu schreiben (analog meine ich)

    also ich habe jetzt meinen code entsprechend modifiziert, per Hand assembliert und denke das er nicht richtig funktioniert.

    Mein Ziel ist es den Code in ein Arcade Spiel am Mame hinein zu integrieren.

    Warum das ganze:

    Ich portiere ein Arcade Spiel auf eine andere Spielplatine des gleichen Herstellers.

    Der Spielcode braucht IRQ0 (RST 38) und IRQ10 (RST 10) um die Spielfiguren zu animieren und musik zu spielen (welche auf einem 2. Z80 Läuft)

    verbunden mit der ersten über ein Soundlatch (=communikationsspeicherzelle) und einen IRQ.

    In meiner aktuellen Spielplatine wird aber nur RST 38 verwendet und den RST 10 nie, da die Hardware dazu fehlt.

    alle 16 Vertical Blanks (RST10) führe ich einen RST 38 aus um den Rest des Spiels updaten zu lassen.

    Einmal editiert, zuletzt von mos6581 (5. Mai 2020 um 14:44) aus folgendem Grund: typo

  • Am CPC (z.B. in Locomotive BASIC und MAXAM) wird hexadezimal oft ein & vorangestellt.

    Die Adresse &0010 liegt in unteren Sprungleiste, da kommst Du der Firmware in die Quere, so Du auf diese Wert legst.

    Der Emulator WinAPE hat einen Assembler eingebaut.

  • ja und sauber ist es dann so.......
    Danke Daybyter, dein Approach war in die richtige Richtung ;)


    4 Mal editiert, zuletzt von mos6581 (7. Mai 2020 um 15:07)

  • Ja klar :)

    das ist für mich nicht so ein Problem da ich schon verschiedenste Computer unter den Pfoten hatte..

    Jetzt ist bei Mir Zilog Zeit :)
    Habe mich durch Wüsten von z80 Assembler code gewühlt die letzten Tage...
    Der Debugger ist ein Freund :)
    Der allerschlimmste CPU war ein Signetics 2650 ... Das war ein Aas.

    (Bally Las Vegas Automat)

  • Um zu testen, ob ein Wert im Register A = 0 ist muss man nicht extra den CP Befehl nutzen. Es geht auch mit OR

    LD A,(Adresse)

    OR A

    JR Z,Wert _ist_Null

    .. hier weiter wenn der Wert ungleich Null ist


    Oder:

    Um zu testen, ob ein Wert im Register A = 0 ist muss man nicht extra den CP Befehl nutzen. Es geht auch mit OR

    LD A,(Adresse)

    OR A

    JR NZ,Wert _NICHT_Null

    .. hier weiter wenn der Wert gleich Null ist

  • In der Z80-Zeit wurde sehr platz- und Performance bewußt programmiert.

    Der Befehl CP 0 braucht 2 Byte und 7 Takte

    Der Befehl OR A braucht nur 1 Byte und 4 Takte.

  • Nein, definitiv nicht. Ich habe halt nachvollziehen wollen, warum man das macht.

    Ich kenne das vom 6502 so, daß der Load Befehl eh das Flag setzt. Da macht man überhaupt keine solchen Vergleiche an der Stelle. Und hier war dann in der Tabelle eigentlich jedes OR eigentlich genauso schnell wie die vielen CP, die da drin stehen.


    Ok, du wolltest also nur mal 10 (20? 50?) andere Mitleser beschäftigen, die sich jetzt Gedanken gemacht haben, warum man das tun sollte oder nicht.

    Eigenartige Annahme ...

    ich weiß auch nicht, warum heutzutage soviele Leute immer erstmal irgend eine schlechte Intention beim Anderen annehmen. Ist irgendwie wie eine Seuche ...

    denk mal drüber nach. Man kann es ja auch einfach überlesen und sich darüber freuen, daß jemand (und vllt auch ein bestimmter Anteil der 50 vermuteten Mitleser), der nicht >= 10 Z80 Bücher gelernt hat, vielleicht auch was an Tricks mitnimmt.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Ich kenne das vom 6502 so, daß der Load Befehl eh das Flag setzt. Da macht man überhaupt keine solchen Vergleiche an der Stelle. Und hier war dann in der Tabelle eigentlich jedes OR eigentlich genauso schnell wie die vielen CP, die da drin stehen.

    Gerade bei Assembler sollte man die bekannten "Vermutungen" sehr genau kontrollieren. Und über Familiengrenzen (6xxx vs Intel/Zilog) komplett über Board werfen.

    Aber meist ist der Mesch froh über seine Erfahrung. ;)

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Z80 hat ein paar Opcodes mit überraschendem Verhalten, IN A,(nn) lässt die Flags unverändert, IN A,(C) setzt P,S,Z entsprechend, das hat mit dem Datenfluss zu tun, im zweiten Fall müssen die Daten durch die ALU mit 12 Takten weil als Ziel jedes 8-Bit-Register möglich ist, also auch IN B,(C) - mit allen Konsequenzen, im ersten Fall nehmen sie den direkten Weg in 11 Takten. Es gibt sogar den undokumentierten Fall IN (C) ohne Zielregister (Opcode ED 70), da werden nur die Flags gesetzt und der Wert wird ignoriert. Und das undokumentierte Pendant OUT (C),0 mit Opcode ED 71 legt 0x00 auf den Datenbus - aber nur bei NMOS-CPUs, CMOS schreibt 0xFF, damit kann man beide Technologien unterscheiden.

  • Z80 hat ein paar Opcodes mit überraschendem Verhalten

    Was ist an einem dokumentierten Verhalten "überraschend" ?

    Die von dir beschriebener Opcodes ausser IN A,(nn) gibt's nur bei der Z80, nicht beim Vorgänger 808x. Vielleicht liegt da ader Unterschied.

    Z.B. werden auch bei den Opcodes IN0 A,(nn) der Z180 die Flags beeinflusst, was mir eine Woche Fehlersuche eingebrockt hat.

    Undokumentierte Opcodes mögen Überraschungen enthalten, wie der Unterschied NMOS / CMOS. Den kannte ich noch nicht, aber die undokumentierten Opcodes habe noch nie benutzt.

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Mein Wissen stammt noch aus den 80ern, als ich meine ersten Treiber für 8"-Floppies geschrieben habe, da kam alle 16 (?) µs ein Datenwort und zwischendrin musste ein Statusbit kontrolliert werden, das ging ohne DMA nur über IN (C) IIRC.

    Und das Wissen ist heute noch wichtig, denn unsere kreativen „Freunde” in Asien schicken immer mal wieder tolle NMOS-CPUs, die per Schleifscheibe und Lasermarkierung ein „Upgrade“ auf CMOS erhalten haben, gerne mit 20 MHz. Siehe auch meinen Z80-Dongle.

    Dokumentiertes Verhalten ist nur dann nicht überraschend, wenn man die Dokumentation nicht nur gelesen, sondern auch verstanden hat. Dabei hatte ich in meinem vorigen Posting das Wort "überraschend" schon extra kursiv ausgezeichnet, um die Ironie zu kennzeichnen. Sätze, die mit „Ich gehe davon aus..." beginnen sind der Weg zur Hölle.

  • Ja, Doku lesen ist schon ein Ding. Verstehen dann manchmal auch eine große Hürde.

    Das kursive habe ich wirklich nicht gesehen, passt zum Thema. ;)

    Dein Z80-Dongle muss ich mir mal in Ruhe anschauen. Das sieht interessant aus.

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Siehe auch meinen Z80-Dongle.

    Zitat


    scf ; Will give us 0 for NEC clones, 28 for Zilog

    Die 28h muss ich mir anschauen. Aber eine 0 ist doch koomplett falsch.

    Nach Set Carry Flag muss doch min1 bit gesetzt sein.

    Das ist eine Überraschung! ;)

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • The flag register has the following structure:

    Bit76543210
    FlagSZF5HF3P/VNC

    Wir maskieren mit 0x28, d.h betrachten nur die undokumentierten Flags F5 und F3.

    Siehe Codeschnipsel, das anschließende out schreibt das Byte in den Speicher vom Dongle, wo ich es später mit den Monitorbefehlen anschauen kann.

    scf ; Will give us 0 for NEC clones, 28 for Zilog

    nop

    push af

    pop bc

    ld a,c

    and $28

    out (1),a

  • Ah, ja, ich habe den Kommentar auf das scf bezogen. Richtig bezieht er sich aber auf die Ausgabe.

    Ok, danke fuer die Klarstellung.

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Ich habe die Tage übrigens ein paar Bücher aus Ende der 70ern zum Z80 und Assembler eingscannt. Falls interesse besteht

    • Z80_Einführung_und_Programmierung
    • Z80_Interface-Technik_und_Anwendung
    • Zilog_Applikationssammlung_77-78
    • Zilog_Datenbuch_77-78
    • Zilog_Z80_Assembler_Sprache_Benutzerhandbuch