The 4195A is an old network + spectrum analyzer. I’ve repaired mine a few years ago.
Extracting a bitmap font #
It started with the assumption that this machine would use a bitmap font; the alternative (a vector font) much less likely for such an instrument of the late 80’s.
Examining the schematics, the display board uses a NEC uPD7220 display controller (GDC). It is quite capable of drawing “hardware-accelerated” lines and curves, but it also has provisions for drawing plain bit-mapped characters.
The 4195 is a complex machine with a two processor boards (A6 and A8) each with their onboard CPU, ROM, and RAM, as well as a shared RAM bank. The service manual indicated that the A6 board is most likely the one driving the graphics interface.
The CPU on this board is an MC68000, with 24 bits of external address space and a 16 bit data bus. The ROM ICs are wired as two banks (upper + lower bytes). The mapping turned out to be a simple linear layout, but the schematics were missing some annotations and the chip-select logic was confusing to say the least. After a few iterations of combining ROM dumps, loading in Ghidra, and looking at disassembly, I have deduced the following memory map:
- program ROM at 0 (704 kB); all ROM “pages” are contiguous
- shared RAM at 0x40 0000
- backup RAM at 0x80 0000
Then, I spent some time defining areas of code near anything that looked like a printable string. This led me to a function that had all the characteristics I would expect for drawing characters. This involves writing a few commands/parameters into GDC registers at 0xf801c1/f80133, followed by 8+5 consecutive writes, taken from a large array in ROM :
pcVar10 = (char *)boot_err_stringtbl[errcode];
char_cnt = 0x2b;
do {
do {
/* range check on ASCII special chars < 0x20 */
bVar6 = (*pcVar10 & 0x7fU) - 0x20;
if ((char)bVar6 < '\0') {
p_bitmap = &charbit_space;
}
else {
p_bitmap = (&font_tbl)[bVar6];
}
...
// set cursor position
DAT_00f801c3 = CURS;
puVar9 = puVar8 + 1;
DAT_00f801c1 = *puVar8;
DAT_00f801c1 = 0x3c;
puVar8 = puVar8 + 2;
DAT_00f801c1 = *puVar9;
DAT_00f801c3 = 0x78;
/* 0x78 : subsequent writes go into &PRAM[8] == &GCHR[] */
DAT_00f801c1 = *p_bitmap;
DAT_00f801c1 = p_bitmap[1];
DAT_00f801c1 = p_bitmap[2];
DAT_00f801c1 = p_bitmap[3];
DAT_00f801c1 = p_bitmap[4];
DAT_00f801c1 = p_bitmap[5];
DAT_00f801c1 = p_bitmap[6];
DAT_00f801c1 = p_bitmap[7];
...
Initially I had tried simply viewing the entire ROM as a monochrome image, hoping to visually recognize patterns and avoid needing to work on disassembly, but the tools I tried for this were not well adapted and I quickly abandoned this approach. However, knowing exactly where to look, the bit patterns now emerged clearly:
It was then a simple matter of writing a quick tool to remap and extract the entire font. srecord and monobit helped with the final steps.
The final fontier #
This is a render of the entire font, implementing characters 0x00-0x7F with a few blank fillers:
Not sure where else to post this, so I at least submitted the font as a ‘YAFF’ file on Rob Hageman’s hoard-of-bitfonts repo.
Also available here.