
OpenType-Schriftart, die Z80-Befehle disassembliert
Was ist dein Lieblings-Disassembler? Meiner ist eine Schriftart:
https://github.com/user-attachments/assets/bb6ceb18-c2fd-40a9-be4f-202321a214d9
Diese Schriftart wandelt Folgen von hexadezimalen Kleinbuchstaben in disassemblierte Z80-Befehle um, indem sie umfassend von OpenTypes Glyph Substitution Table (GSUB) und Glyph Positioning Table (GPOS) Gebrauch macht.
Wenn du es einfach ausprobieren möchtest, eine Kopie ist unter ./test/z80-sans.ttf verfügbar.
Getestet auf Debian GNU/Linux 12. Beachte, dass diese Debian-Version mit Ruby Version 3 ausgeliefert wird, während fontcustom für Ruby Version 2 geschrieben wurde und mit späteren Versionen inkompatibel ist (z.B. Syntaxfehler). Eine Ruby-Installation erfordert außerdem eine kompatible OpenSSL-Version. Daher kann RVM verwendet werden, um sowohl Ruby als auch eine lokale Installation von OpenSSL zu verwalten.
apt install imagemagick potrace
pip install fonttools
git submodule update --init --recursive
# fontforge
(
cd ./modules/fontforge/
git checkout 4f4907d9541857b135bd0b361099e778325b4e28
git apply ../../resources/fontforge.diff
mkdir -p build
cd build
cmake -GNinja ..
ninja
ninja install
)
# woff2
(
cd ./modules/woff2/
make clean all
)
# fontcustom
rvm use 2.7
rvm pkg install openssl
rvm install 2.4 --with-openssl-dir=$HOME/.rvm/usr
gem update --system 3.3.22
(
export PATH=$PWD/modules/woff2/build:$PATH
cd ./modules/fontcustom/
git apply ../../resources/fontcustom.diff
gem build fontcustom.gemspec
gem install ./fontcustom-2.0.0.gem
)
cp ./resources/droid-sans-mono.ttf /tmp/base.ttf
./gen.py ./resources/instructions.json
Die .ttf-Schriftartdatei wird nach ~/.local/share/fonts/ kopiert, was z.B. von LibreOffice verwendet wird.
Im Vergleich zu anderen verfluchten Schriftarten hat Z80 Sans folgende Herausforderungen:
CALL), dies hängt jedoch auch mit dem nächsten Punkt zusammen...65536 * 7 = 458752 mögliche Kombinationen haben kann;0x80..0xff müssen als negative Zweierkomplementzahl gerendert werden;All dies lädt zu einer programmatischen Lösung ein. Während fontcustom und ImageMagick die Generierung von Glyphen übernehmen, scheint das .fea-Format eine bequeme Möglichkeit zum Schreiben von Lookup-Regeln zu sein, aber ich fand keinen Weg, es in das .ttx-Format von fonttools (das im Grunde XML ist) zu integrieren. Ich habe den Ansatz des kleinsten gemeinsamen Nenners gewählt, indem ich das .ttx von Noto Sans Mono direkt bearbeitet habe (obwohl die Glyphenformen aus Droid Sans Mono berechnet werden, da ich damit begonnen habe, als ich FontForge patchte).
Ein rekursiver Abstiegsparser wird verwendet, um alle möglichen Glyphen zu generieren, was bei der Auswertung von Ausdrücken in Kodierungen hilft (z.B. SET b,(IX+o) benötigt ein Bit und eine Verschiebung, kodiert als Ausdruck DD CB o C6+8*b). Diese Kodierungen wurden dann auf alle möglichen Werte erweitert, die Operanden annehmen können, bevor schließlich 1 oder mehrere hexadezimale Bytes jedem Disassemblierungsglyphen zugeordnet wurden, der zum Rendern eines erweiterten Befehls erforderlich ist.
Es gibt einige nette Referenzen für OpenType-Features, aber sie sind auf hohem Niveau oder im .fea(?)-Format geschrieben:
Es ist nie ganz klar, wie man sie in .ttx übersetzt, also habe ich am Ende einfach die gesamte Noto Sans Familie konvertiert und den guten alten Brute-Force-Ansatz des "Lernens durch Beispiele" verwendet. Das macht sogar mehr Spaß, als es klingt, dank zahlreicher stiller Fehlschläge bei der Konvertierung von .ttx nach .ttf, bei denen Lookups aufgrund einiger Annahmen, die von fonttools nicht validiert werden, nicht übereinstimmen (z.B. müssen Klassendefinitionen für kontextuelle Verkettungssubstitutionen mindestens ein Coverage-Glyph mit class value="1" haben).
So ziemlich die meisten Herausforderungen wurden mit kontextuellen Verkettungsregeln gelöst. Um Adressen zu handhaben, wurde jedes Nibble im Bereich 0..f mit unterschiedlichen Glyphen kodiert, wobei Abstandszeichen verwendet wurden, um mehrere Substitutionen zu erstellen, ein Zeichen nach dem anderen. Verschiebungen haben auch zusätzliche vorzeichenbehaftete Varianten. Das ergibt insgesamt (4 + 2) * 16 Glyphen für Zahlen. Das war bereits ausreichend, um die Schriftartdatei unter der Grenze von 65536 Glyphen zu halten.
Der schlimmste Teil waren natürlich die außerhalb der Reihenfolge liegenden Operanden. Aufgrund der begrenzten Anzahl von Variationen, die diese in Befehlen haben, konnten sie jedoch mit der gleichen Strategie abgedeckt werden wie Befehle mit mehrdeutig kodierten Präfixen, z.B.
["SET b,(IX+o)", "DD CB o C6+8*b"],
["SET b,(IY+o)", "FD CB o C6+8*b"],
Wird von denselben Lookup-Regeln abgedeckt wie:
["SRA (IX+o)", "DD CB o 2E"],
["SRA (IY+o)", "FD CB o 2E"],
["SRL (IX+o)", "DD CB o 3E"],
["SRL (IY+o)", "FD CB o 3E"],
Eine interessante Eigenschaft im Z80-ISA ist, dass Bits und Register bis zu 8 Variationen haben, und diese Out-of-Order-Fälle betreffen nur Offsets und einen dieser spezifischen Operanden. Daher können wir Bits oder Register als Literale kodieren. Mit ausreichenden Lookaheads können wir bis zum letzten hexadezimalen Byte abgleichen und für jeden Fall dedizierte Lookups erstellen. Die letzten Literale können reduziert werden, indem eine Ligatur erzeugt wird, die mit dem Suffix-Glyphen übereinstimmt. Das Endergebnis waren Dutzende weitere generierte Lookups für diese Fälle (die wahrscheinlich gruppiert werden könnten, um diese Anzahl zu reduzieren).
LD (IX+o),r wird als LD (IX+o r), gerendert;SET b,(IX+o) wird als SET b,(IX+o)) gerendert;FontForge unterstützt die skriptgesteuerte Modifikation von Features mit den Befehlen GenerateFeatureFile() und MergeFeature() (kurz behandelt in The Terrible Secret of OpenType Glyph Substitution - Ansuz - mskala's home page). Ich wusste erst davon, nachdem ich die .ttx-basierte Implementierung erstellt hatte, aber es hätte möglicherweise vermeiden können, mit .ttx-Dateien herumzuhantieren.
Für komplexere Befehlssätze ist ein alternativer Ansatz, der weniger Einschränkungen zu haben scheint, die Verwendung von Font Shapern. Einige Beispiele:
./resources/instructions.json wurde von maziac/z80-instruction-set angepasst;./resources/instructions.json steht unter der GNU Lesser General Public License Version 3;