Robotrontechnik-Forum

Registrieren || Einloggen || Hilfe/FAQ || Suche || Mitglieder || Home || Statistik || Kalender || Admins Willkommen Gast! RSS

Robotrontechnik-Forum » Technische Diskussionen » KC-87-Emulator mit MIDI-Unterstützung » Themenansicht

Autor Thread - Seiten: -1-
000
25.06.2026, 18:51 Uhr
coignard



Hallo zusammen,

Grüße aus Wolfen-Nord.

Ich beschäftige mich mit experimenteller Orgelmusik. Manche Orgeln hier sind mit einem SINUA-System ausgestattet, über das sich das Instrument per MIDI ansteuern lässt. Dafür habe ich einen KC-87-Emulator geschrieben, mit MIDI-Unterstützung über die U855, um musikalische Sequenzen in Assembler zu schreiben und an die Orgel zu schicken.

Der Z80-Kern ist mein eigener, eine Portierung von z80.h, in die ich das Verhalten des U880 eingepflegt habe, sodass die Abweichungen des Klons vom Zilog-Original nachgebildet werden.
Dazu gibt es ein SDK assembliert mit fasmg.

https://github.com/coignard/kc87

Ein Beispiel mit Orgel gibt es bereits für meinen anderen Emulator, den des sowjetischen Apogee BK-01:

https://www.youtube.com/watch?v=m-vjX_T3D38

Quelltext:

https://github.com/coignard/apogee-sdk/blob/main/examples/hoehere-gewalt.asm

René Coignard
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
001
27.06.2026, 12:11 Uhr
coignard



Kassettenladevorgang Demo:

https://youtu.be/5vsnKAEvDwY

René Coignard
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
002
27.06.2026, 12:34 Uhr
Dresdenboy



Hallo René,

Das mit den Orgeln ist interessant - und überhaupt das Emulator-Projekt!

Ich habe das auch schon weitergeleitet, da ich jemanden kenne, der vllt. mal wieder etwas auf der Plattform machen würde.

VG,
Matthias
--
___________________________________
Produktionen im Rahmen der "The Computer Art Community" (Demoszene): https://demozoo.org/sceners/64936/, YT-Kanal: https://www.youtube.com/@4lpha0ne/videos
Aktuelle Projekte: GDC-Analysen für Grafikeffekte u. Demo/Game-Framework, universelles BIC-Modul auf Pico-Basis, Packer mit sehr kleinem 6502-Dekompressor
HW: BIC, MSX2+, KC87, KC85/2-4, KCC, LC-80, PC1715, C64, C16, Plus/4, A500, A1200, Mega 65, µCs ...
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
003
27.06.2026, 12:36 Uhr
coignard



Danke Matthias!

LG
René Coignard
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
004
27.06.2026, 16:45 Uhr
Bert



Interessante Idee!

Ich wundere mich nur über den Gedanken reale Orgeln mit virtueller Hardware anzusteuern.

Hast Du noch vor das ändern, René?
Würde Deine Steuersoftware auch auf einem realen Z9001 mit EA-Modul funktionieren?
https://hc-ddr.hucki.net/wiki/doku.php/z9001/module_robotron/ea-modul
--
Viele Grüße,
Bert
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
005
27.06.2026, 17:10 Uhr
HeikoS



Hallo René,

ein sehr schönes Projekt. Die Emulatoren werden immer mehr ... ;-)

Eine Frage: Du hast ja irgendwo geschrieben, dass du die Z80.h von Andre Weissflog angepasst hast auf den U880.

https://github.com/floooh/chips/blob/master/chips/z80.h

Welche konkreten Abweichungen hast du denn da angepasst? Wann spielen diese Unterschiede eine Rolle?

Viele Grüße, Heiko
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
006
27.06.2026, 17:12 Uhr
jmueller



Hallo René,

ich finde die MIDI-Schnittstelle am KC87 interessant.
Wie funktioniert das Steuerungsprogramm auf dem KC87?
Ist das ein MIDI-Sequenzer?
Kann man damit MIDI-Dateien abspielen?
Und vorallem: Sind die Schaltungsunterlagen für die MIDI-Schnittstelle
und das Steuerungsprogramm öffentlich verfügbar?
Wenn ja, dann könnte ich mir auch eine Umsetzung im JKCEMU vorstellen.
Statt realer Orgeln würde dann der im Java enthaltene MIDI-Synthesizer
die Musik abspielen.

Jens
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
007
27.06.2026, 17:35 Uhr
Enrico
Default Group and Edit


War MIDI nicht mal in der FA drin, per SIO?
--
MFG
Enrico
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
008
27.06.2026, 17:45 Uhr
jmueller




Zitat:
Enrico schrieb
War MIDI nicht mal in der FA drin, per SIO?



Hallo Enrico,

ich weiß jetzt nicht, an wen sich deine Frage richtet.
Sollte sie sich an mich richten, dann:
Es bringt nichts irgendeine irgndwo mal veröffentlichte MIDI-Schnittstelle zu emulieren.
Es muss schon die sein, mit der das Steuerungsprogramm etwas anfangen kann.
Und René hat von

Zitat:
MIDI-Unterstützung über die U855


geschrieben, nicht von SIO.

Jens

Dieser Beitrag wurde am 27.06.2026 um 17:46 Uhr von jmueller editiert.
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
009
27.06.2026, 19:26 Uhr
coignard




Zitat:
Eine Frage: Du hast ja irgendwo geschrieben, dass du die Z80.h von Andre Weissflog angepasst hast auf den U880. Welche konkreten Abweichungen hast du denn da angepasst? Wann spielen diese Unterschiede eine Rolle?



Ehrlich gesagt habe ich das hauptsächlich gemacht, weil ich Authentizität erreichen wollte, und nicht, weil ich irgendeine Software hätte, die diese Spezialfälle ausnutzt (mit Ausnahme von Tests wie z80test).

Kurz zu den Unterschieden: Erstens verändern die Block-I/O-Befehle INI, IND, INIR, INDR, OUTI, OUTD, OTIR, OTDR das Carry-Flag (CF) nicht. Das führt dazu, dass z80test fehlschlägt, aber genau das ist das erwartete Verhalten für den U880:

https://github.com/coignard/u880/blob/main/tests/z80test.rs

Alle übrigen Flags (N aus Bit 7 des Bytes, H aus dem Überlauf von t, P/V als Parität von (t&7) XOR B, S/Z/X/Y aus B) sind wie bei Zilog.

Die Datenblätter von Zilog und Mostek sagen, dass CY von diesen Befehlen nicht verändert wird. Das heißt, der U880 hält sich an die Spezifikation, während der echte Zilog einen undokumentierten Nebeneffekt hat. Letztlich haben die MME-Ingenieure den Z80 beim Nachbau also gewollt oder ungewollt verbessert. Das ist übrigens eine Eigenschaft des NMOS-MME-U880 (U880D/UA880D/UB880D). Der spätere CMOS-U84C00 hat das schon nicht mehr.

Zweitens habe ich die undokumentierten Flags X/Y (Bits 3/5) bei SCF und CCF ergänzt:


Quellcode:

match rev {
    Revision::Older => f.0 |= a & (Y|X),
    Revision::Newer => f.0 |= (a | f_in.0) & (Y|X),
}



Hier ist der Kontext wichtig. Patrik Rak hat schon 2012 gezeigt, dass bei jedem Zilog Z80 (sowohl NMOS als auch CMOS) X/Y bei SCF/CCF als Bits 5/3 von (Q ^ F) | A berechnet werden, wobei Q ein verborgener Zustand der ALU ist: nach einem Befehl, der die Flags nicht verändert, ist Q=0, nach einem Befehl, der sie verändert, ist Q=neues F. Das heißt, beim echten Zilog hängt das Ergebnis von SCF/CCF vom vorherigen Befehl ab. David Banks (2018) hat ergänzt, dass NEC NMOS beide Bits einfach aus A nimmt, und ST CMOS XF aus A, YF nach der Zilog-Formel (Letzteres kann ich allerdings weder bestätigen noch widerlegen).

Der U880 bildet die Zilog-Q-Logik überhaupt nicht nach. Der frühe MME-U880 verhält sich wie NEC (X/Y = A), das ist meine Variante Older. Der späte MME-U880 (und, dem Detektor z80type nach zu urteilen, die verwandten Thesys Z80 und der rumänische MMN 80CPU) hat X/Y = A | F, das ist mein Newer. Witzigerweise sind meine beiden Revisionen genau die zwei Grenzfälle der Zilog-Formel: bei Q=F ergibt sich A, bei Q=0 ergibt sich A|F, nur ist das beim U880 fest an die Revision gebunden und hängt nicht vom vorherigen Befehl ab.

Wichtige Einschränkung: Die-Fotos verschiedener U880-Revisionen habe ich nicht, deshalb habe ich das Verhalten selbst aus den Quellen von z80test und aus dem Detektor z80type übernommen. Den echten Zilog ((Q^F)|A) und ST CMOS emuliere ich bewusst nicht, weil der U880 sich so nicht verhält, ich habe dazu in den Tests einen Hinweis hinterlassen: "SCF (ST) FAILED // ST CMOS not emulated".

Auf echter Hardware sind X/Y während SCF/CCF schlicht instabil (ich habe irgendwo darüber gelesen, entweder hier oder anderswo): derselbe Chip kann je nach Temperatur, Spannung und Taktsignal unterschiedliche Werte liefern, sogar in verschiedenen Maschinen unterschiedlich. Als Referenz habe ich daher dieses beobachtbare stabile Verhalten genommen und modelliere es als feste Revisionen, statt zu versuchen, die Zilog-Q-Logik nachzubilden.

Jetzt zur z80.h. Hier habe ich das Durchsickern von PC_H in X/Y bei den sich wiederholenden Block-Befehlen ergänzt (LDIR/LDDR/CPIR/CPDR/INIR/INDR/OTIR/OTDR): bei der Wiederholung wird PC um 2 verringert, und die Bits 3/5 von PC_H sickern in X/Y durch. Das ist kein spezielles U880-Verhalten, das gab es auch beim Z80. Und um die Contention beim KC 87 korrekt umzusetzen, habe ich die WAIT-Abtastung auf den Daten-T-Zustand der Nicht-M1-Zyklen gelegt: Beim KC 87 / Z 9001 setzt der Videocontroller den echten WAIT-Pin bei Zugriffen auf das Video- bzw. Farb-RAM (adressbasierte Contention über den echten Pin, also weder das RDY des CPC noch der angehaltene Takt des Spectrum). floooh hat bestätigt, dass die Platzierung von WAIT in der z80.h ein Kompromiss zugunsten der Performance ist.


VG
René Coignard

Dieser Beitrag wurde am 27.06.2026 um 19:27 Uhr von coignard editiert.
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
010
27.06.2026, 19:52 Uhr
coignard




Zitat:
Hast Du noch vor das ändern, René?
Würde Deine Steuersoftware auch auf einem realen Z9001 mit EA-Modul funktionieren?



Ich habe über echte Hardware nachgedacht, aber ich denke, ich bleibe beim Emulator, weil es mir so vertrauter ist und weil mein restliches Musik-Setup ebenfalls virtuell ist, auf meinem macOS. Ich meine damit Cubase, Dorico, Max/MSP und ORCA. Bei der Albumaufnahme nächstes Jahr ist es für mich und das Team viel einfacher, wenn alles an einem Ort ist. Ich schließe aber nicht aus, dass ich in Zukunft vielleicht doch zu echter Hardware übergehe. Anfangen wollte ich allerdings mit dem Apogee BK-01.

Auf echter Hardware käme bei meinen Programmen kein MIDI heraus, weil 89h dort das Datenregister von Port B des System-PIO ist. Man bräuchte eine serielle Schaltung (31250 Baud, 8N1, optogekoppelte Stromschleife), und das EA-Modul wäre genau dafür geeignet. Man könnte das Programm einfach von 89h auf den PIO des EA-Moduls umbiegen und entweder die Leitung per PIO bit-bangen mit dem Takt vom CTC, oder einen SIO/UART für die Serialisierung nehmen. Ich habe darüber allerdings nicht groß nachgedacht, das ist also nur eine Vermutung.


Zitat:

Wie funktioniert das Steuerungsprogramm auf dem KC87?
Ist das ein MIDI-Sequenzer?
Kann man damit MIDI-Dateien abspielen?
Und vorallem: Sind die Schaltungsunterlagen für die MIDI-Schnittstelle
und das Steuerungsprogramm öffentlich verfügbar?



Das ist kein Sequenzer und kein MIDI-Datei-Player, es ist, würde ich sagen, eine Alternative zum "Live-Coding", also "Offline-Assembling". Man schreibt ein Assembler-Programm, das bestimmte MIDI-Sequenzen algorithmisch ausgibt. Das ist alles.

Hier ein Beispiel, das ich zur Überprüfung des Timings geschrieben habe:

https://github.com/coignard/kc87-sdk/blob/main/examples/midi.asm

Jetzt dazu, wie genau das im Emulator gemacht ist. Die MIDI-Bytes landen im Datenregister von Port B des System-PIO, der Emulator schnappt sich jeden dieser Schreibzugriffe und reicht das Byte an das MIDI des Hosts weiter (auf dem Mac über CoreMIDI mit Zeitstempel, sonst über midir). Die serielle Strecke mit 31250 Baud emuliere ich nicht, das macht der Host.


Quellcode:

let user_write = (pins & (u855::CE | pins::IORQ | pins::M1 | pins::RD))
    == (u855::CE | pins::IORQ)
    && (pins & u855::BASEL) != 0
    && (pins & u855::CDSEL) == 0;
// Woran merkt man, dass die Stasi Robotron-Wanzen bei einem einsetzt?
if user_write
    && !self.prev_user_write
    && let UserPeripheral::Midi(midi) = &mut self.user_slot
{
    midi.push_byte(pins::data(pins), self.current_cycle);
}
self.prev_user_write = user_write;



Zu JKCEMU: erstens nochmals danke dafür. Ich habe mich schon in unserer E-Mail-Korrespondenz bedankt, aber ich wiederhole es gern. Und um die Frage zu beantworten: für JKCEMU ist das kinderleicht nachzubauen, man muss nur die OUT-Zugriffe auf 89h abgreifen und den Wert als rohes MIDI-Byte an den Java-Synthesizer schicken. Alles ist offen (der Emulator unter GPL, das SDK unter zlib). Hier kann man reinschauen: src/core/peripherals/midi.rs (der Puffer), src/core/bus.rs (der Abgriff selbst), kc87-sdk/examples/midi.asm (das komplette Beispielprogramm). Bei Fragen antworte ich gern.


Zitat:

War MIDI nicht mal in der FA drin, per SIO?



Ja, das ist der richtige Hardware-Weg. Aber der KC 87 hatte keinen U856, zumindest ist mir nichts davon bekannt. Höchstens auf Erweiterungskarten. Möglicherweise füge ich übrigens irgendwann einen U856 in das chips/-Verzeichnis meines Projekts ein, aber das steht momentan nicht auf meiner Liste.

VG
René Coignard

Dieser Beitrag wurde am 27.06.2026 um 19:54 Uhr von coignard editiert.
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
011
27.06.2026, 19:56 Uhr
HeikoS



Interessant, tolle Arbeit ! So im Detail habe ich das noch nicht betrachtet, es gibt aber hier Experten, die sich mit CPU-Testern beschäftigen, da spielt das natürlich eine große Rolle.

Contention hat mich auch schon viel beschäftigt. Der original Speccy hält den Takt an, die Amstrad-Modell nutzen aber wohl auch WAIT. Im KC85/4 wird auch WAIT benutzt.

Da der Z8 kein WAIT hat, hatte ich beim Ju-Te 6K die Logik für's "Taktanhalten" zusätzlich entwickelt, getestet und eingebaut. Ist hier dokumentiert:

https://github.com/haykonus/JU-TE-6K-Video-HW-Patch

Wenn ich das richtig verstanden habe, wird in der Z80.h WAIT platziert, um das Verhalten der asynchron auftauchenden WAIT's, ausgelöst durch die Videosteuerung, zu simulieren. Aber wann wird es plaziert? Das muss ja irgendwie statistisch so gemacht werden, dass der reale Betrieb simuliert wird. Vielleicht habe ich das auch falsch verstanden. Ist ein interessantes Thema !

Grüße, Heiko
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
012
27.06.2026, 20:01 Uhr
coignard




Zitat:

Wenn ich das richtig verstanden habe, wird in der Z80.h WAIT platziert, um das Verhalten der asynchron auftauchenden WAIT's, ausgelöst durch die Videosteuerung, zu simulieren. Aber wann wird es plaziert? Das muss ja irgendwie statistisch so gemacht werden, dass der reale Betrieb simuliert wird. Vielleicht habe ich das auch falsch verstanden. Ist ein interessantes Thema !



Das WAIT wird im Emulator nicht statistisch modelliert. Die CPU erzeugt es nicht, sondern tastet es nur in einem festen Takt ab, gesetzt wird das WAIT vom Bus. Wie das bei mir konkret funktioniert: Bei einem Zugriff auf das Video- bzw. Farb-RAM im sichtbaren Teil der Zeile hält der Bus das WAIT bis zum Ende des sichtbaren Bereichs, und das Timing ist aus dem Master-Takt bzw. dem Bildaufbau abgeleitet (312/192 Zeilen, 79 von 157 T-States sichtbar).

In der z80.h wird das "wann abgetastet wird" angepasst. Vorher wurde das WAIT bei Nicht-M1-Zyklen abgetastet, bevor die Adresse anlag, und der Bus konnte nicht anhand der Adresse entscheiden. Ich habe die Abtastung auf den Daten-T-State verlegt, wenn die Adresse bereits auf dem Bus liegt.

Danke!

VG
René Coignard
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
013
27.06.2026, 20:28 Uhr
HeikoS




Zitat:
coignard schrieb

... Wie das bei mir konkret funktioniert: Bei einem Zugriff auf das Video- bzw. Farb-RAM im sichtbaren Teil der Zeile hält der Bus das WAIT bis zum Ende des sichtbaren Bereichs, und das Timing ist aus dem Master-Takt bzw. dem Bildaufbau abgeleitet (312/192 Zeilen, 79 von 157 T-States sichtbar). ...

VG
René Coignard



Ist das wirklich so beim KC87 ? Oder wird nicht nur bis zum Abschluss des Schreibvorgangs der Videosteuerung, das WAIT gehalten? Ich denke beim KC85/4 ist das so. Ich habe es aber nicht selbst gesehen oder gemessen.

EDIT: Da es heute so heiß ist, kann man draussen eh nichts machen, endlich mal Zeit für wichtige Sachen ;-)

Dieser Beitrag wurde am 27.06.2026 um 20:30 Uhr von HeikoS editiert.
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
014
27.06.2026, 20:31 Uhr
coignard




Zitat:

Ist das wirklich so beim KC87 ? Oder wird nicht nur bis zum Abschluss des Schreibvorgangs der Videosteuerung, das WAIT gehalten? Ich denke beim KC85/4 ist das so. Ich habe es aber nicht selbst gesehen oder gemessen.



Ich bin von den Informationen ausgegangen, die ich habe, insbesondere aus meiner eigenen Recherche. Aber wie gesagt, ich habe keinen echten KC 87, deshalb kann ich nicht garantieren, dass es in der Realität eins zu eins so ist. Die Daten, die mir vorliegen, lassen aber durchaus vermuten, dass es so ist.

Dein Einwand klingt aber plausibel. Bei mir halte ich das WAIT aktuell bis zum Ende des sichtbaren Bereichs der Zeile, und das ist möglicherweise eine Vereinfachung. Dass das WAIT in Wirklichkeit nur bis zum Abschluss des Zugriffs der Videosteuerung gehalten wird, wie du es beim KC85/4 vermutest, wäre durchaus möglich. Falls du dazu eine Messung oder eine Quelle hast, nehme ich die sehr gern.


Zitat:

Da es heute so heiß ist, kann man draussen eh nichts machen, endlich mal Zeit für wichtige Sachen ;-)



Ist echt so :-)

VG
René Coignard

Dieser Beitrag wurde am 27.06.2026 um 20:33 Uhr von coignard editiert.
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
015
27.06.2026, 20:38 Uhr
HeikoS



Da ich sowas ja selbst gebaut habe, auch schon früher, würde ich sagen, dass der KC87 u. KC85/4 viel langsamer wären, bei vielen Videozugriffen, wenn bis zum Ende der Zeile gewartet wird. Das kann man im Schaltplan ja sehen.

Wir hatten so eine Diskussion schon mal, Bert aus dem Forum hat das, meine ich, bestätigt.

https://www.robotrontechnik.de/html/forum/thwb/showtopic.php?threadid=21874#239691

Grüße, Heiko
Seitenanfang Seitenende
Profil || Private Nachricht || Suche Zitatantwort || Editieren || Löschen
Seiten: -1-     [ Technische Diskussionen ]  



Robotrontechnik-Forum

powered by ThWboard 3 Beta 2.84-php5
© by Paul Baecher & Felix Gonschorek