/* * hello.c -- the VT1200's first C program. * * Writes the word HELLO straight into video RAM, no X11 involved: * * framebuffer bit 0x04000000, 256-byte row pitch on the real unit * (the emulator uses 128; this image is linked for the real one) * pixels 1 bpp, LSB-first within each byte * text area black 256x72 box at x=40 y=800, white 5x7 glyphs scaled 8x * * The program also leaves a marker word at 0x018A8000 so the host can tell the * C runtime reached main(): 0x48454C4C == 'HELL'. * * K&R C only: no prototypes, no '//', no unsigned suffixes, declarations first. * The tables are filled in code, not by static initializers, because this image * is entered through entry.asm and does not run boot.obj's .cinit pass. */ #define VRAM_BASE 0x04000000 /* bit address of the framebuffer */ #ifndef ROW_BYTES #define ROW_BYTES 256 /* real unit: 256-byte row pitch */ #endif #define ROW_BITS (ROW_BYTES * 8) #define BOX_X 40 /* box left edge, pixels (1 bit per pixel) */ #define BOX_Y 800 /* box top edge, pixels */ #define BOX_W 256 /* 32 bytes */ #define BOX_H 72 #define MARKER 0x018A8000 /* free RAM, outside .text and .bss */ static unsigned char font[4][7]; /* H E L O (HELLO uses L twice) */ static unsigned char order[5]; static unsigned char box[BOX_H][BOX_W / 8]; /* 5x7 glyphs, bit 4 = leftmost pixel */ static void build_font() { font[0][0] = 17; font[0][1] = 17; font[0][2] = 31; font[0][3] = 17; font[0][4] = 17; font[0][5] = 17; font[0][6] = 17; /* H */ font[1][0] = 31; font[1][1] = 16; font[1][2] = 16; font[1][3] = 30; font[1][4] = 16; font[1][5] = 16; font[1][6] = 31; /* E */ font[2][0] = 16; font[2][1] = 16; font[2][2] = 16; font[2][3] = 16; font[2][4] = 16; font[2][5] = 16; font[2][6] = 31; /* L */ font[3][0] = 14; font[3][1] = 17; font[3][2] = 17; font[3][3] = 17; font[3][4] = 17; font[3][5] = 17; font[3][6] = 14; /* O */ order[0] = 0; order[1] = 1; order[2] = 2; order[3] = 2; order[4] = 3; } int main() { int c, r, gx, dx, dy, px, py; unsigned int v; unsigned int addr; build_font(); /* 1. prove we are here */ *(unsigned int *)MARKER = 0x48454C4C; /* 2. clear the box (black) */ for (py = 0; py < BOX_H; py++) for (px = 0; px < BOX_W / 8; px++) box[py][px] = 0; /* 3. draw HELLO, each glyph pixel as an 8x8 block */ for (c = 0; c < 5; c++) { for (r = 0; r < 7; r++) { v = font[order[c]][r]; for (gx = 0; gx < 5; gx++) { if (!(v & (16 >> gx))) continue; for (dy = 0; dy < 8; dy++) { for (dx = 0; dx < 8; dx++) { px = 8 + c * 48 + gx * 8 + dx; py = 8 + r * 8 + dy; box[py][px >> 3] |= 1 << (px & 7); } } } } } /* 4. blit the box into video RAM, one byte at a time. * * Pointers here are BIT addresses and pointer arithmetic scales by the * object size, so a `char *` step is 8 bits: p + n is n bytes, not n*8. * Address the bytes as addr + px*8 bits and cast, which is unambiguous. */ for (py = 0; py < BOX_H; py++) { addr = VRAM_BASE + (BOX_Y + py) * ROW_BITS + BOX_X; for (px = 0; px < BOX_W / 8; px++) { *(unsigned char *)(addr + px * 8) = box[py][px]; } } /* 5. second marker: the blit finished */ *(unsigned int *)(MARKER + 0x20) = 0x444F4E45; /* 'DONE' */ return 0; }