This is kinda broken right now, but it displays something.  It puts up
an X11 window and does the scan conversion from 80x25 to 640x400.


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



/***************************************************************************/
/* This section pretends to be the bridge to the S3 */
/***************************************************************************/


#define _MEM_B 0
#define MEM_CMDQ_FREE   ( _MEM_B + 0x00 )
#define MEM_SEND_ADDR_MEM       ( _MEM_B + 0x08 )
#define MEM_SEND_ADDR_ENG       ( _MEM_B + 0x09 )
#define MEM_SEND_READ_COUNT     ( _MEM_B + 0x0f )
#define MEM_SEND_DATA_0000      ( _MEM_B + 0x10 )
#define MEM_SEND_DATA_1111      ( MEM_SEND_DATA_0000 + 15)
#define MEM_READQ_AVAIL ( _MEM_B + 0x02 )
#define MEM_READQ_DATA  ( _MEM_B + 0x03 )

unsigned int s3_memory[258048];
unsigned int s3_addr = 0;
unsigned int s3_queue = 0;

int write_io(int addr, unsigned int data)
{
    switch (addr) {
        case MEM_SEND_ADDR_MEM:
            s3_addr = data;
            break;
        case MEM_SEND_READ_COUNT:
            s3_queue = data;
            break;
        default:
            if (addr >= MEM_SEND_DATA_0000 && addr <= MEM_SEND_DATA_1111) {
                s3_memory[s3_addr++] = data;
            }
            break;
    }
}

int read_io(int addr)
{
    switch (addr) {
        case MEM_CMDQ_FREE:
            return 16;
        case MEM_READQ_AVAIL:
            return s3_queue;
        case MEM_READQ_DATA:
            return s3_memory[s3_addr++];
    }
    return 0;
}

/***************************************************************************/
/* End of S3 emulator */
/***************************************************************************/


/***************************************************************************/
/* X11 stuff to display in window */
/* WARNING:  Blindly assumes your X server is 32-bit truecolor */
/***************************************************************************/

Display *display;
int screen;
Window win;
GC gc;
Colormap cmap;
Visual *visual;
XFontStruct *font_info;
int depth;

init_x11()
{
    XEvent event;
    XColor closest, exact;

    display = XOpenDisplay(NULL);
    screen = DefaultScreen(display);
    cmap = DefaultColormap(display, screen);
    gc = DefaultGC(display, screen);
    visual = DefaultVisual(display, screen);
    depth = DefaultDepth(display, screen);
    win = XCreateSimpleWindow(display, RootWindow(display, screen),
            0, 0, 640, 400, 1, BlackPixel(display, screen),
            WhitePixel(display, screen));
    XSelectInput(display, win, ExposureMask | KeyPressMask);
    XMapWindow(display, win);

    /* Wait for the first expose event */
    do {
        XNextEvent(display, &event);
    } while (event.type != Expose);
}

bye_x11()
{
    XCloseDisplay(display);
}

XFontStruct *load_font(char *name)
{
    XFontStruct *inf;

    inf = XLoadQueryFont(display, name);
    if (!inf) {
        fprintf(stderr, "Can't load this font\n");
        exit(-1);
    }

    return inf;
}

/* Get 8x16 font, character at a time, into VGA glyph format */
void get_font()
{
    Pixmap pix;
    int i, x, y, z, p;
    char str[2];
    unsigned int *mem, word, bit;
    XImage *img;

    pix = XCreatePixmap(display, win, 8, 16, depth);
    font_info = load_font("8x16");
    XSetFont(display, gc, font_info->fid);
    XSetForeground(display, gc, -1);
    XSetBackground(display, gc, 0);

    mem = s3_memory+1024;
    str[1] = 0;

    for (i=0; i<256; i++) {
        str[0] = i;
        XDrawImageString(display, pix, gc, 0, font_info->ascent, str, 1);
        img = XGetImage(display, pix, 0, 0, 8, 16, -1, ZPixmap);

        for (z=0; z<4; z++) {
            word = 0;
            bit = 0;
            for (y=0; y<4; y++) {
                for (x=0; x<8; x++) {
                    p = XGetPixel(img, x, y);
                    if (p) word |= 1<<bit;
                    bit++;
                }
            }
            *mem++ = word;
        }

        XDestroyImage(img);
    }
}


void display_screen()
{
    XImage *img;

    img = XCreateImage(display, visual, depth, ZPixmap, 0,
        (char *)(s3_memory+2048), 640, 480, 32, 0);
    XPutImage(display, win, gc, img, 0, 0, 0, 0, 640, 480);
    img->data = 0;
    XDestroyImage(img);
    XFlush(display);
}


/***************************************************************************/
/* End of X11 stuff */
/***************************************************************************/




/***************************************************************************/
/* Start of VGA conversion code */
/***************************************************************************/



/* CGA text is 2 bytes per character.  The first byte is the glyph number.
The second byte is color.  I'm doing this from memory, and this is probably
wrong, but for this code, I'm going to assume this for the color byte:
   [3:0] foreground color
   [6:4] background color
   [7]   blink

The colors are as follows (also probably wrong):
   0 - black        #000000
   1 - dk red       #AA0000
   2 - dk green     #00AA00
   3 - brown        #AAAA00 (definitely wrong, but whatever)
   4 - dk blue      #0000AA
   5 - dk magenta   #AA00AA
   6 - dk cyan      #00AAAA
   7 - lt gray      #AAAAAA
   8 - dk gray      #555555
   9 - lt red       #FF5555
  10 - lt green     #55FF55
  11 - yellow       #FFFF55
  12 - lt blue      #5555FF
  13 - lt magenta   #FF55FF
  14 - lt cyan      #55FFFF
  15 - white        #FFFFFF
*/

/* Base address of where the text is stored in graphics memory */
int text_base = 0;

/* Width and height in characters of the character display */
int text_width = 80, text_height = 25;

/* Base address of where the font is stored */
int font_base = 1024;

/* Font is assumed to be 8x16 (not always correct), where a character
   is found as:  font_addr + glyph_num*16 */
int glyph_height = 16;

/* Base address of where pixels are stored for the video framebuffer */
int pixel_base = 2048;

/* Actual size of glyph in graphics buffer.  Different from 8x16 if scaled */
int cell_width = 8, cell_height = 16;

/* Size of whole graphics screen */
int screen_width = 640, screen_height = 400;


unsigned int scratch[512];

/* This is a pointer into the scratch space where we temporarily store
   row of text */
unsigned int *text_line = scratch;


int blink_cycle = 0;



/* Poll for PCI accesses to service */
void poll_pci()
{
#if 0
    while (memory or engine reg writes) {
        /* get the write and forward it to the bridge */
    }
    if (memory or engine reg read) {
        /* forward the read addr and count to the bridge */
        /* wait for read data to arrive and forward it all back to
address_decode */
    }
    while (vga io writes) {
        /* process them, storing appropriate data in scratch space */
    }
    if (vga io read) {
        /* fetch data from scratch space and return it */
    }
#endif
}


/* Draw a glyph whose bitmap has been queued */
void draw_glyph(int pixel_addr, int fg, int bg)
{
    int px, py, i, bit, g, pixel;

    /* Outer loop for the rows of the glyph */
    for (py=0; py<glyph_height; py+=4) {
        /* Read four rows of the glyph */
        g = read_io(MEM_READQ_DATA);

        /* Process four rows of the glyph */
        for (i=0; i<4; i++) {
            /* Make sure there's room on the write queue */
            while (read_io(MEM_CMDQ_FREE) < 9);

            write_io(MEM_SEND_ADDR_MEM, pixel_addr);

            /* Write out a row of pixels */
            for (px=0; px<cell_width; px++) {
                bit = g&1;
                g >>= 1;
                pixel = bit ? fg : bg;
                write_io(MEM_SEND_DATA_1111, pixel);
                pixel_addr++;
            }

            /* Move left and down to the next row of the glyph */
            pixel_addr += screen_width - cell_width;
        }
    }
}


/* Convert the whole 80x25 screen from text to pixels */
void convert_text_to_pixels()
{
    int cx, cy, i, j, w;
    int glyph0, color0, bg0, fg0;
    int pixel_addr;
    unsigned int *buf;

    pixel_addr = pixel_base;

    for (cy=0; cy<text_height; cy++) {
        /* Read a line of text.  This is 80 character, stored in 160 bytes,
           or 40 words.  Since we don't know where a 128-word boundary
might be crossed,
           we request words in lots of 8 */


        buf = text_line;
        cx = 0;
        while (cx < text_width) {
            poll_pci();

            /* Make sure bridge is not busy and not in read mode */
            /* while (read_io(BRIDGE_BUSY)); */
            /* XXX In hardware, we need to make sure that commands are
               not dequeued while bridge is busy. */

            write_io(MEM_SEND_ADDR_MEM, text_base + cy*text_width/2);
            write_io(MEM_SEND_READ_COUNT, 8);
            i = 0;
            while (i < 8) {
                j = read_io(MEM_READQ_AVAIL);
                i += j;
                cx += j;
                switch (j) {
                    case 8: *buf++ = read_io(MEM_READQ_DATA);
                    case 7: *buf++ = read_io(MEM_READQ_DATA);
                    case 6: *buf++ = read_io(MEM_READQ_DATA);
                    case 5: *buf++ = read_io(MEM_READQ_DATA);
                    case 4: *buf++ = read_io(MEM_READQ_DATA);
                    case 3: *buf++ = read_io(MEM_READQ_DATA);
                    case 2: *buf++ = read_io(MEM_READQ_DATA);
                    case 1: *buf++ = read_io(MEM_READQ_DATA);
                }
            }
        }

        poll_pci();

        /* Now convert the line of text to pixels */
        buf = text_line;
        for (cx=0; cx<text_width; cx++) {
            poll_pci();

            /* Get a character from the buffer */
            /* If we're on the odd glyph, shift to get it */
            w = *buf;
            if (cx & 1) {
                w >>= 16;
                buf++;
            }

            /* Request font data for each character */
            glyph0 = w & 255;
            /* while (read_io(BRIDGE_BUSY)); */
            write_io(MEM_SEND_ADDR_MEM, font_base + glyph0*16);
            write_io(MEM_SEND_READ_COUNT, 4);

            /* Compute colors */
            /* If these are configurable, read them from scratch space */
            color0 = (w >> 8) & 255;
            fg0  = (color0 & 1) ? 0xAA0000 : 0;
            fg0 |= (color0 & 2) ? 0x00AA00 : 0;
            fg0 |= (color0 & 4) ? 0x0000AA : 0;
            fg0 += (color0 & 8) ? 0x555555 : 0;
            bg0  = (color0 & 16) ? 0xAA0000 : 0;
            bg0 |= (color0 & 32) ? 0x00AA00 : 0;
            bg0 |= (color0 & 64) ? 0x0000AA : 0;
            if (blink_cycle && (color0 & 128)) fg0 = bg0;

            /* Wait for all four reads to appear in queue */
            while (read_io(MEM_READQ_AVAIL) < 4);

            /* Process glyph */
            draw_glyph(pixel_addr, fg0, bg0);

            pixel_addr += cell_width;
        }

        pixel_addr += screen_width * (cell_height - 1);
    }

    poll_pci();
}


int main()
{
    int x;

    init_x11();
    get_font();

    for (x=0; x<256; x++) {
        *((char *)s3_memory + x*2) = x;
        *((char *)s3_memory + x*2 + 1) = x;
    }

    /* All I do is translate over and over and over again */
    x = 0;
    while (1) {
        convert_text_to_pixels();
        display_screen();
        sleep(1);
        blink_cycle = !blink_cycle;
    }

    return 0;
}




-- 
Timothy Normand Miller
http://www.cse.ohio-state.edu/~millerti
Open Graphics Project
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to