
Fuente OpenType que desensambla instrucciones Z80
¿Cuál es tu desensamblador favorito? El mío es una fuente:
https://github.com/user-attachments/assets/bb6ceb18-c2fd-40a9-be4f-202321a214d9
Esta fuente convierte secuencias de caracteres hexadecimales en minúsculas en instrucciones Z80 desensambladas, haciendo un uso extensivo de la Tabla de Sustitución de Glifos (GSUB) y la Tabla de Posicionamiento de Glifos (GPOS) de OpenType.
Si solo quieres probarla, hay una copia disponible en ./test/z80-sans.ttf.
Probado en Debian GNU/Linux 12. Ten en cuenta que esta versión de Debian incluye ruby versión 3, mientras que fontcustom fue escrito para ruby versión 2 y es incompatible con versiones posteriores (por ejemplo, errores de sintaxis). Una instalación de ruby también requiere una versión compatible de OpenSSL. Por lo tanto, se puede usar RVM para gestionar tanto ruby como una instalación local de OpenSSL.
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
El archivo de fuente .ttf se copia a ~/.local/share/fonts/, que es usado por ejemplo por LibreOffice.
En comparación con otras fuentes malditas, Z80 Sans tiene estos desafíos:
CALL), sin embargo esto también está ligado al siguiente punto...65536 * 7 = 458752 combinaciones posibles.0x80..0xff deben renderizarse como un número negativo en complemento a dos.Todo esto requiere una solución programática. Mientras que fontcustom e ImageMagick se encargan de generar glifos, parece que una forma conveniente de escribir reglas de búsqueda es el formato .fea, pero no encontré una manera de integrarlo con el formato .ttx de fonttools (que es básicamente xml). Tomé el enfoque del mínimo común denominador editando directamente el .ttx de Noto Sans Mono (aunque las formas de los glifos se calculan a partir de Droid Sans Mono, ya que fue con lo que empecé al parchar FontForge).
Se utiliza un analizador de descenso recursivo para generar todos los glifos posibles, lo que ayuda a evaluar expresiones en codificaciones (por ejemplo, SET b,(IX+o) toma un bit y un desplazamiento, codificado como la expresión DD CB o C6+8*b). Luego, estas codificaciones se expandieron a todos los valores posibles que pueden tomar los operandos, antes de asociar finalmente 1 o más bytes hexadecimales a cada glifo de desensamblado necesario para renderizar una instrucción expandida.
Hay algunas buenas referencias sobre las características de OpenType, pero están escritas a un nivel alto, o en formato .fea(?):
Nunca está muy claro cómo traducirlas a .ttx, así que al final simplemente convertí toda la familia Noto Sans y usé el viejo y confiable enfoque de "aprender con el ejemplo". Esto es incluso más divertido de lo que parece, gracias a los numerosos fallos silenciosos al convertir de .ttx a .ttf, donde las búsquedas no coinciden debido a algunas suposiciones no validadas por fonttools (por ejemplo, las definiciones de clase para sustituciones de encadenamiento contextual deben tener al menos un glifo de cobertura con valor de clase="1").
Prácticamente todos los desafíos se resolvieron con reglas de encadenamiento contextual. Para manejar direcciones, cada nibble en el rango 0..f se codificó con glifos distintos, utilizando caracteres espaciadores para crear múltiples sustituciones, un carácter a la vez. Los desplazamientos también tienen variantes con signo adicionales. Esto nos da un total de (4 + 2) * 16 glifos para números. Esto ya fue suficiente para mantener el archivo de fuente por debajo del límite de 65536 glifos.
La peor parte fueron, por supuesto, los operandos fuera de orden. Sin embargo, debido al número limitado de variaciones que estos tienen en las instrucciones, se pudieron cubrir con la misma estrategia que las instrucciones con prefijos codificados de manera ambigua, por ejemplo:
["SET b,(IX+o)", "DD CB o C6+8*b"],
["SET b,(IY+o)", "FD CB o C6+8*b"],
Se cubre con las mismas reglas de búsqueda que:
["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"],
Una propiedad interesante en el ISA Z80 es que los bits y los registros tienen hasta 8 variaciones, y estos casos fuera de orden solo involucran desplazamientos y uno de esos operandos específicos. Por lo tanto, podemos codificar bits o registros como literales. Con suficiente anticipación, podemos coincidir hasta el último byte hexadecimal y crear búsquedas dedicadas para cada caso. Los últimos literales se pueden reducir generando una ligadura que coincida con el glifo del sufijo. El resultado final fueron docenas de búsquedas generadas adicionales para estos casos (que probablemente se puedan agrupar para reducir este número).
LD (IX+o),r se renderiza como LD (IX+o r),;SET b,(IX+o) se renderiza como SET b,(IX+o));FontForge admite la modificación programática de características mediante los comandos GenerateFeatureFile() y MergeFeature() (brevemente cubierto en The Terrible Secret of OpenType Glyph Substitution - Ansuz - mskala's home page). Solo me enteré de esto después de hacer la implementación basada en .ttx, pero podría haber evitado tener que tocar los archivos .ttx.
Para conjuntos de instrucciones más complejos, un enfoque alternativo que parece tener menos restricciones es usar moldeadores de fuentes. Algunos ejemplos:
./resources/instructions.json fue adaptado de maziac/z80-instruction-set../resources/instructions.json está bajo GNU Lesser General Public License versión 3;