Friday, October 31, 2014

More work towards hardware proportional fonts

I have spent a bit more time tonight working on hardware support for proportional fonts.

For those coming in late, the VIC-IV already has the ability to draw skinny characters 2, 4 or 6 pixels wide as well as the usual 8.  This can be used to construct large characters from one or more 8x8 character blocks to make any even number of pixels in width on screen.  For a large type face, each character may be several 8x8 character blocks wide.

This means that a row of proportional text may have a variable number of characters, because if there are skinny characters, then more will fit on a line.  Conversely, if there is no text on the right of the display, then it doesn't make sense to waste RAM describing empty characters.  Thus I have followed Jeremy's idea of implementing a special end of line marker, so that each row can differ in length, and we can hopefully use RAM much more efficiently when faced with large high-resolution text displays.

In the previous post I describe the work on skinny characters.

Now I have just about finished implementing the end of line markers, although as I write there is one remaining bug which is quite obvious in the screenshot below in the form of the vertical bars that shouldn't be there:

At first glance, this looks mostly like a normal C64 text mode display.  However the entire screen is described using only about 80 bytes each of screen and colour RAM:

The screen RAM:

:0400 01 C0 02 00 03 00 04 00 05 00 FF FF 06 00 07 00
:0410 08 00 FF FF FF FF FF FF FF FF FF FF 09 00 0A 00
:0440 0B 00 FF FF 0C 00 FF FF 0D 00 FF FF

The colour RAM:

:D800 00 01 02 03 04 05 07 01 02 02 02 02 02 0E 0F 0E
:D810 0E 0E 0E 0E 00 00 00 00 02 03 04 05 02 08 01 02
:D820 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E
:D830 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E
:D840 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E
:D850 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E

To follow what is going on, remember that in this mode ($D054 = $01), two bytes are used to describe each character.  The first byte is the low 8 bits of the character number, and the low nybl of the second byte are extra character number bits.  The top two bits of the second byte set the width of the character as it is displayed on screen.

Thus $01 $C0 at $0400 draws only the left two pixels of the letter A, which shows up as the stumpy black line in the screen shot.  The rest of the row of text is now offset by 6 pixels compared to normal.

Normal characters are encoded from $0402 - $0409.  This is followed by $FF $FF which tells the VIC-IV that there is an early end of line.  Thus the letter F described by $06 $00 at $040C-$040D appears at the beginning of the next line, and no other characters appear to the right of the letter E.

Colour RAM is drawn in a somewhat strange way, that I will probably fix.  Within a row, the colour RAM bytes are read one per character, and so $D801 has $01 (white), and this is applied to the letter B encoded in $0402-$0403.  That seems quite reasonable.  But following an end of line, the colour RAM address catches up with the screen RAM.  What I intend to do is make the colour RAM address advance two bytes for each character, so that the extra byte of information can be used.  I might use this to allow skinny characters to be odd widths, and also to have a kind of super-extended-background-mode, where the other bits select the background colour.

However, before I do any of that, I need to fix the bug that happens when a character row consists only of a $FF $FF end of row marker. In that case the length of the character data is incorrectly set to the maximum value, instead of zero, and so whatever rubbish was hanging around in the character raster buffer gets redrawn.

Although, as I write that, I am not entirely convinced that this is the whole story.  Indeed, it seems that the three bars are the contents of $3894, $300C, and $80CB. Very strange.

Hopefully my little bug-fix will work, otherwise I will just specify that each row must have at least one character, so you would use something like $20 $00 $FF $FF to make a row empty with one space at the beginning.


  1. You just keep surprising us... first computer ever with proportional fonts 100% in hardware? Reading this I was thinking the following: All this magic is done with the old PETSCII font. It is a very good charset, with many possibilities for ASCII art. However, data interchance with other computers is not so easy with PETSCII as PC's cannot directly display PETSCII correctly and the C64/C65 cannot display PC charsets directly. Perhaps a very simple but damn usefull addition to your computer would be a "ROM" with an IBM font inside, available to the programmer with a simple poke. Of course the programmer can always load a font from disk into RAM, but having such a thing in ROM would make it much more accessible and therefore usable.

    1. Hello,

      No idea if other computers have hardware support for proportional fonts. Would be interesting to find out.

      With internal SD card storage, it is probably just as easy to allow people to load any character set they like from there. Of course, if I get around to making the proportional font engine, then this will provide an easy second route to using a PC font (fixed or proportional).


  2. I am really not want to be rude or so, but I don't see the advantage of prop. font in text mode, it's more annoying than useful. But that's _my_ opinion only :) In graphical mode it makes sense more, but there you can draw anything pixel by pixel, so no hardware support is needed. However it's another question if there is hardware support for fast (even proportional) character "renderer". Or I should be more open, ie a quite interesting WYSIWYG-like editor can be written in text mode with your hw text mode prop. font support, that's true as well :)

    1. Hello,
      I'm not offended, so don't worry. I should probably write a post about the rationale for proportional text mode, but here is the quick summary: 128KB chipram = 1,048,576 bits. 1920x1200 = 2,304,000 pixels. This means that in bitmap mode you could never even have a monochrome image -- you need some way to reuse pieces of memory to make a big image. In other words, you need some sort of souped-up text mode. The same problem applies to displaying proportional text. If it were on a bitmap, we have the same problem of less than one bit per pixel. Making characters variable width provides a nice solution to this problem, and the change to the hardware is surprisingly small. It also means that even at 1MHz you could manipulate large anti-aliased proportional text displays. The other option is to increase the size of chipram, which simply too expensive (the FPGA I am using is already expensive enough at the moment). But anyway, I should make that post, but not right now.