neilobremski
Experienced Member
Even back on the original IBM PC you could get read-only access to the glyph pixel data for the standard ASCII character set, extended ASCII, and control characters with codes less than 32 (0x20) [SUP][1][/SUP].
Each character glyph is 8 bytes where every byte represents a row and every bit represents a column. The horizontal bits start in the most significant bit, so the font pixel for column 0, row 0 is bit 7 in byte 0 which follows the style for monochrome graphics modes.
The font tables themselves are split in two. The first 128 characters (0 - 127) contain a couple dozen special DOS glyphs followed by standard ASCII; you'll find them starting at the specific memory address 0xF000:FA6E. For the second half of the character data there is some indirection: the vector table entry 0x1F contains a pointer to the actual memory address of the data.
Below is a C function I wrote for the original Magenta's Maze which returns a far pointer to the character of choice:
Now that I'm writing a version in assembler I had to create something similar there. Below is one I wrote over a month ago and it shows!
Footnotes:
[SUP][1][/SUP]. https://en.wikipedia.org/wiki/Code_page_437 . I'd like to add that although the symbols and their dimensions are the same across all IBM compatibles, their representations are not. This makes the textures a bit of a surprise in Magenta's Maze because they depend on the underlying machine.
Each character glyph is 8 bytes where every byte represents a row and every bit represents a column. The horizontal bits start in the most significant bit, so the font pixel for column 0, row 0 is bit 7 in byte 0 which follows the style for monochrome graphics modes.
The font tables themselves are split in two. The first 128 characters (0 - 127) contain a couple dozen special DOS glyphs followed by standard ASCII; you'll find them starting at the specific memory address 0xF000:FA6E. For the second half of the character data there is some indirection: the vector table entry 0x1F contains a pointer to the actual memory address of the data.
Below is a C function I wrote for the original Magenta's Maze which returns a far pointer to the character of choice:
Code:
/* returns start address of bios character glyph (each one is 8 bytes) */
unsigned char far *bioschar(unsigned char c)
{
/* INT 0x1F refers to a block of memory for codes 128+ */
static unsigned long far *vector1f = (unsigned long far*)(0x1f * 4);
/* F000:FA6E contains first 127 ASCII characters */
unsigned char far *p = (unsigned char far*)0xF000FA6E;
if (252 == c) { /* patch for ^3 superscript */
static unsigned char superscript3[8] = {
0x70, 0x08, 0x30, 0x08, 0x70, 0x00, 0x00, 0x00 };
return (unsigned char far *)superscript3;
}
/* upper ASCII (128 - 255) retrieved with INT 1F vector */
if (c > 127) {
p = (unsigned char far*)(*vector1f);
c -= 128;
}
return p + (((int)c) << 3);
}
Now that I'm writing a version in assembler I had to create something similar there. Below is one I wrote over a month ago and it shows!
Code:
a 370
; ----------------------------------------------------------------------------
; BIOSCHAR () :BIOSCHAR
;
; AL = character
;
; modifies DS:SI!
;
CMP AL, FC ; 370
JNZ 037A ; 372
MOV SI, 03B0; 374
RET ; 377
NOP ; 378
NOP ; 379
CMP AL, 80 ; 37A
JAE 0392 ; 37C
XOR AH, AH ; 37E
SHL AX, 1 ; 380
SHL AX, 1 ; 382
SHL AX, 1 ; 384
MOV SI, FA6E; 386
ADD SI, AX ; 389
MOV DX, F000; 38B
MOV DS, DX ; 38E
RET ; 390
NOP ; 391
XOR AH, AH ; 392
SUB AL, 80 ; 394
SHL AX, 1 ; 396
SHL AX, 1 ; 398
SHL AX, 1 ; 39A
MOV DX, 0000; 39C
MOV DS, DX ; 39F
MOV SI, [007C] ; 3A1
ADD SI, AX ; 3A5
MOV DX, [007E] ; 3A7
MOV DS, DX ; 3AB
RET ; 3AD
NOP ; 3AE
NOP ; 3AF
e 3b0 70 08 30 08 70 00 00 00
Footnotes:
[SUP][1][/SUP]. https://en.wikipedia.org/wiki/Code_page_437 . I'd like to add that although the symbols and their dimensions are the same across all IBM compatibles, their representations are not. This makes the textures a bit of a surprise in Magenta's Maze because they depend on the underlying machine.