pcem/src/vid_im1024.c

906 lines
22 KiB
C

#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_pgc.h"
#include "vid_im1024.h"
/* This implements just enough of the Vermont Microsystems IM-1024 to
* support the Windows 1.03 driver. Functions are partially implemented
* or hardwired to the behaviour expected by the Windows driver.
*
* One major difference seems to be that in hex mode, coordinates are
* passed as 2-byte integer words rather than 4-byte fixed-point fractions.
* I don't know what triggers this, so for now it's always on.
*/
extern uint8_t fontdat12x18[256][36];
typedef struct im1024_t
{
pgc_core_t pgc;
unsigned char fontx[256];
unsigned char fonty[256];
unsigned char font[256][128];
unsigned char *fifo;
unsigned fifo_len, fifo_wrptr, fifo_rdptr;
} im1024_t;
/* As well as the usual PGC ring buffer at 0xC6000, the IM1024 appears to
* have an alternate method of passing commands. This is enabled by setting
* 0xC6330 to 1, and then:
*
* CX = count to write
* SI -> bytes to write
*
* Set pending bytes to 0
* Read [C6331]. This gives number of bytes that can be written:
* 0xFF => 0, 0xFE => 1, 0xFD => 2 etc.
* Write that number of bytes to C6000.
* If there are more to come, go back to reading [C6331].
* As far as I can see, at least one byte is always written; there's no
* provision to pause if the queue is full.
*
* I am implementing this by holding a FIFO of unlimited depth in the
* IM1024 to receive the data.
*
*/
static void fifo_write(im1024_t *im1024, unsigned char val)
{
/* PGCLOG(("fifo_write: %02x [rd=%04x wr=%04x]\n", val,
im1024->fifo_rdptr, im1024->fifo_wrptr)); */
if (((im1024->fifo_wrptr + 1) % im1024->fifo_len) == im1024->fifo_rdptr)
{
/* FIFO is full. Double its size. */
unsigned char *buf;
PGCLOG(("fifo_resize: %d to %d\n",
im1024->fifo_len, 2 * im1024->fifo_len));
buf = realloc(im1024->fifo, 2 * im1024->fifo_len);
if (!buf) return;
/* Move the [0..wrptr] range to the newly-allocated area [len..len+wrptr] */
memmove(buf + im1024->fifo_len, buf, im1024->fifo_wrptr);
im1024->fifo = buf;
im1024->fifo_wrptr += im1024->fifo_len;
im1024->fifo_len *= 2;
}
/* Append to the queue */
im1024->fifo[im1024->fifo_wrptr] = val;
++im1024->fifo_wrptr;
/* Wrap if end of buffer reached */
if (im1024->fifo_wrptr >= im1024->fifo_len)
{
im1024->fifo_wrptr = 0;
}
}
static int fifo_read(im1024_t *im1024)
{
uint8_t result;
if (im1024->fifo_wrptr == im1024->fifo_rdptr)
{
return -1; /* FIFO empty */
}
result = im1024->fifo[im1024->fifo_rdptr];
++im1024->fifo_rdptr;
if (im1024->fifo_rdptr >= im1024->fifo_len)
{
im1024->fifo_rdptr = 0;
}
/*
PGCLOG(("fifo_read: %02x\n", result));
*/
return result;
}
/* Where a normal PGC would just read from the ring buffer at 0xC6300, the
* IM-1024 can read either from this or from its internal FIFO. The internal
* FIFO has priority. */
int im1024_input_byte(pgc_core_t *pgc, uint8_t *result)
{
im1024_t *im1024 = (im1024_t *)pgc;
/* If input buffer empty, wait for it to fill */
while ((im1024->fifo_wrptr == im1024->fifo_rdptr) &&
(pgc->mapram[0x300] == pgc->mapram[0x301]))
{
pgc->waiting_input_fifo = 1;
pgc_sleep(pgc);
}
if (pgc->mapram[0x3FF]) /* Reset triggered */
{
pgc_reset(pgc);
return 0;
}
if (im1024->fifo_wrptr == im1024->fifo_rdptr)
{
*result = pgc->mapram[pgc->mapram[0x301]];
++pgc->mapram[0x301];
}
else
{
*result = fifo_read(im1024);
}
return 1;
}
/* Macros to disable clipping and save clip state */
#define PUSHCLIP { \
uint16_t vp_x1, vp_x2, vp_y1, vp_y2; \
vp_x1 = pgc->vp_x1; \
vp_y1 = pgc->vp_y1; \
vp_x2 = pgc->vp_x2; \
vp_y2 = pgc->vp_y2; \
pgc->vp_x1 = 0; \
pgc->vp_y1 = 0; \
pgc->vp_x2 = pgc->maxw - 1; \
pgc->vp_y2 = pgc->maxh - 1; \
/* And to restore clip state */
#define POPCLIP \
pgc->vp_x1 = vp_x1; \
pgc->vp_y1 = vp_y1; \
pgc->vp_x2 = vp_x2; \
pgc->vp_y2 = vp_y2; \
}
/* Override memory read to return FIFO space */
uint8_t im1024_read(uint32_t addr, void *p)
{
im1024_t *im1024 = (im1024_t *)p;
if (addr == 0xC6331 && im1024->pgc.mapram[0x330] == 1)
{
return 0x80; /* Hardcode that there are 128 bytes
* free */
}
return pgc_read(addr, &im1024->pgc);
}
/* Override memory write to handle writes to the FIFO */
void im1024_write(uint32_t addr, uint8_t val, void *p)
{
im1024_t *im1024 = (im1024_t *)p;
/* If we are in 'fast' input mode, send all writes to the internal
* FIFO */
if (addr >= 0xC6000 && addr < 0xC6100 && im1024->pgc.mapram[0x330] == 1)
{
fifo_write(im1024, val);
/*
PGCLOG(("im1024_write(%02x)\n", val));
*/
if (im1024->pgc.waiting_input_fifo)
{
im1024->pgc.waiting_input_fifo = 0;
pgc_wake(&im1024->pgc);
}
return;
}
pgc_write(addr, val, &im1024->pgc);
}
/* I don't know what the IMGSIZ command does, only that the Windows driver
* issues it. So just parse and ignore it */
void hndl_imgsiz(pgc_core_t *pgc)
{
int16_t w,h;
uint8_t a,b;
// im1024_t *im1024 = (im1024_t *)pgc;
if (!pgc_param_word(pgc, &w)) return;
if (!pgc_param_word(pgc, &h)) return;
if (!pgc_param_byte(pgc, &a)) return;
if (!pgc_param_byte(pgc, &b)) return;
PGCLOG(("IMGSIZ %d,%d,%d,%d\n", w,h,a,b));
}
/* I don't know what the IPREC command does, only that the Windows driver
* issues it. So just parse and ignore it */
void hndl_iprec(pgc_core_t *pgc)
{
uint8_t param;
// im1024_t *im1024 = (im1024_t *)pgc;
if (!pgc_param_byte(pgc, &param)) return;
PGCLOG(("IPREC %d\n", param));
}
/* I think PAN controls which part of the 1024x1024 framebuffer is displayed
* in the 1024x800 visible screen. */
void hndl_pan(pgc_core_t *pgc)
{
int16_t x,y;
if (!pgc_param_word(pgc, &x)) return;
if (!pgc_param_word(pgc, &y)) return;
PGCLOG(("PAN %d,%d\n", x, y));
pgc->pan_x = x;
pgc->pan_y = y;
}
/* PLINE draws a non-filled polyline at a fixed position */
void hndl_pline(pgc_core_t *pgc)
{
int16_t x[257];
int16_t y[257];
uint8_t count;
unsigned n;
uint16_t linemask = pgc->line_pattern;
if (!pgc_param_byte(pgc, &count)) return;
PGCLOG(("PLINE<IM1024> (%d) ", count));
for (n = 0; n < count; n++)
{
if (!pgc_param_word(pgc, &x[n])) return;
if (!pgc_param_word(pgc, &y[n])) return;
PGCLOG((" (%d,%d)\n", x[n], y[n]));
}
for (n = 1; n < count; n++)
{
linemask = pgc_draw_line(pgc, x[n - 1] << 16, y[n - 1] << 16,
x[n] << 16, y[n] << 16, linemask);
}
}
/* Blit a single row of pixels from one location to another. To avoid
* difficulties if the two overlap, read both rows into memory, process them
* there, and write the result back. */
void blkmov_row(pgc_core_t *pgc, int16_t x0, int16_t x1, int16_t x2,
int16_t sy, int16_t ty)
{
int16_t x;
uint8_t src[1024];
uint8_t dst[1024];
for (x = x0; x <= x1; x++)
{
src[x - x0] = pgc_read_pixel(pgc, x, sy);
dst[x - x0] = pgc_read_pixel(pgc, x - x0 + x2, ty);
}
for (x = x0; x <= x1; x++)
{
switch (pgc->draw_mode)
{
default:
case 0: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0]); break;
case 1: pgc_write_pixel(pgc, (x - x0 + x2), ty, dst[x - x0] ^ 0xFF); break;
case 2: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] ^ dst[x - x0]); break;
case 3: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] & dst[x - x0]); break;
}
}
}
/* BLKMOV blits a rectangular area from one location to another, with no
* clipping. */
void hndl_blkmov(pgc_core_t *pgc)
{
int16_t x0,y0;
int16_t x1,y1;
int16_t x2,y2;
int16_t y;
// im1024_t *im1024 = (im1024_t *)pgc;
if (!pgc_param_word(pgc, &x0)) return;
if (!pgc_param_word(pgc, &y0)) return;
if (!pgc_param_word(pgc, &x1)) return;
if (!pgc_param_word(pgc, &y1)) return;
if (!pgc_param_word(pgc, &x2)) return;
if (!pgc_param_word(pgc, &y2)) return;
PGCLOG(("BLKMOV %d,%d,%d,%d,%d,%d\n", x0,y0,x1,y1,x2,y2));
/* Disable clipping */
PUSHCLIP
/* Either go down from the top, or up from the bottom, depending
* whether areas might overlap */
if (y2 <= y0)
{
for (y = y0; y <= y1; y++)
{
blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2);
}
}
else
{
for (y = y1; y >= y0; y--)
{
blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2);
}
}
/* Restore clipping */
POPCLIP
}
/* This overrides the PGC ELIPSE command to parse its parameters as words
* rather than coordinates */
static void hndl_ellipse(pgc_core_t *pgc)
{
int16_t x, y;
if (!pgc_param_word(pgc, &x)) return;
if (!pgc_param_word(pgc, &y)) return;
PGCLOG(("ELLIPSE<IM1024> %d,%d @ %d,%d\n", x,y,
pgc->x >> 16, pgc->y >> 16));
pgc_draw_ellipse(pgc, x << 16, y << 16);
}
/* This overrides the PGC MOVE command to parse its parameters as words
* rather than coordinates */
static void hndl_move(pgc_core_t *pgc)
{
int16_t x, y;
if (!pgc_param_word(pgc, &x)) return;
if (!pgc_param_word(pgc, &y)) return;
pgc->x = x << 16;
pgc->y = y << 16;
PGCLOG(("MOVE<IM1024> %d,%d\n", x,y));
}
/* This overrides the PGC DRAW command to parse its parameters as words
* rather than coordinates */
static void hndl_draw(pgc_core_t *pgc)
{
int16_t x, y;
if (!pgc_param_word(pgc, &x)) return;
if (!pgc_param_word(pgc, &y)) return;
PGCLOG(("DRAW<IM1024> %d,%d to %d,%d\n",
pgc->x >> 16, pgc->y >> 16, x, y));
pgc_draw_line(pgc, pgc->x, pgc->y, x << 16, y << 16, pgc->line_pattern);
pgc->x = x << 16;
pgc->y = y << 16;
}
/* This overrides the PGC POLY command to parse its parameters as words
* rather than coordinates */
static void hndl_poly(pgc_core_t *pgc)
{
int32_t *x, *y;
int32_t n;
int16_t xw, yw, mask;
unsigned realcount = 0;
int parsing = 1;
int as = 256;
x = malloc(as * sizeof(int32_t));
y = malloc(as * sizeof(int32_t));
if (!x || !y)
{
PGCLOG(("hndl_poly: malloc failed\n"));
return;
}
while (parsing)
{
uint8_t count;
if (!pgc_param_byte(pgc, &count)) return;
if (count + realcount >= as)
{
int32_t *nx, *ny;
nx = realloc(x, 2 * as * sizeof(int32_t));
ny = realloc(y, 2 * as * sizeof(int32_t));
if (!x || !y)
{
PGCLOG(("hndl_poly: realloc failed\n"));
break;
}
x = nx;
y = ny;
as *= 2;
}
for (n = 0; n < count; n++)
{
if (!pgc_param_word(pgc, &xw)) return;
if (!pgc_param_word(pgc, &yw)) return;
/* Skip degenerate line segments */
if (realcount > 0 &&
(xw << 16) == x[realcount - 1] &&
(yw << 16) == y[realcount - 1])
{
continue;
}
x[realcount] = xw << 16;
y[realcount] = yw << 16;
++realcount;
}
/* If we're in a command list, peek ahead to see if the next command is
* also POLY. If so, that's a continuation of this polygon! */
parsing = 0;
if (pgc->clcur && (pgc->clcur->rdptr+1) < pgc->clcur->wrptr &&
pgc->clcur->list[pgc->clcur->rdptr] == 0x30)
{
PGCLOG(("hndl_poly: POLY continues!\n"));
parsing = 1;
/* Swallow the POLY */
++pgc->clcur->rdptr;
}
}
PGCLOG(("POLY<IM1024> (%d) fill_mode=%d\n", realcount, pgc->fill_mode));
for (n = 0; n < realcount; n++)
{
PGCLOG((" (%d,%d)\n", x[n] >> 16, y[n] >> 16));
}
if (pgc->fill_mode)
{
pgc_fill_polygon(pgc, realcount, x, y);
}
/* Now draw borders */
mask = pgc->line_pattern;
for (n = 1; n < realcount; n++)
{
mask = pgc_draw_line(pgc, x[n - 1], y[n - 1], x[n], y[n], mask);
}
pgc_draw_line(pgc, x[realcount - 1], y[realcount - 1], x[0], y[0], mask);
free(y);
free(x);
}
static int parse_poly(pgc_core_t *pgc, pgc_commandlist_t *cl, int c)
{
uint8_t count;
PGCLOG(("parse_poly<IM1024>\n"));
if (!pgc_param_byte(pgc, &count)) return 0;
PGCLOG(("parse_poly<IM1024>: count=%02x\n", count));
if (!pgc_commandlist_append(cl, count))
{
pgc_error(pgc, PGC_ERROR_OVERFLOW);
return 0;
}
PGCLOG(("parse_poly<IM1024>: parse %d words\n", 2 * count));
return pgc_parse_words(pgc, cl, count * 2);
}
/* This overrides the PGC RECT command to parse its parameters as words
* rather than coordinates */
static void hndl_rect(pgc_core_t *pgc)
{
int16_t x0, y0, x1, y1, p, q;
x0 = pgc->x >> 16;
y0 = pgc->y >> 16;
if (!pgc_param_word(pgc, &x1)) return;
if (!pgc_param_word(pgc, &y1)) return;
/* Convert to raster coords */
pgc_sto_raster(pgc, &x0, &y0);
pgc_sto_raster(pgc, &x1, &y1);
if (x0 > x1) { p = x0; x0 = x1; x1 = p; }
if (y0 > y1) { q = y0; y0 = y1; y1 = q; }
PGCLOG(("RECT<IM1024> (%d,%d) -> (%d,%d)\n", x0, y0, x1, y1));
if (pgc->fill_mode)
{
for (p = y0; p <= y1; p++)
{
pgc_fill_line_r(pgc, x0, x1, p);
}
}
else /* Outline: 4 lines */
{
p = pgc->line_pattern;
p = pgc_draw_line_r(pgc, x0, y0, x1, y0, p);
p = pgc_draw_line_r(pgc, x1, y0, x1, y1, p);
p = pgc_draw_line_r(pgc, x1, y1, x0, y1, p);
p = pgc_draw_line_r(pgc, x0, y1, x0, y0, p);
}
}
/* TODO: Text drawing should probably be implemented in vid_pgc.c rather
* than vid_im1024.c */
static void hndl_tdefin(pgc_core_t *pgc)
{
unsigned char ch, bt;
unsigned char rows, cols;
unsigned len, n;
// unsigned x = 0;
im1024_t * im1024 = (im1024_t *)pgc;
if (!pgc_param_byte(pgc, &ch)) return;
if (!pgc_param_byte(pgc, &cols)) return;
if (!pgc_param_byte(pgc, &rows)) return;
PGCLOG(("TDEFIN<IM1024> (%d,%d,%d) 0x%02x 0x%02x\n", ch, rows, cols,
pgc->mapram[0x300], pgc->mapram[0x301]));
len = ((cols + 7) / 8) * rows;
for (n = 0; n < len; n++)
{
// char buf[10];
// unsigned char mask;
if (!pgc_param_byte(pgc, &bt)) return;
// buf[0] = 0;
// for (mask = 0x80; mask != 0; mask >>= 1)
// {
// if (bt & mask) strcat(buf, "#");
// else strcat(buf, "-");
// ++x;
// if (x == cols) { strcat(buf, "\n"); x = 0; }
// }
// PGCLOG((buf));
if (n < sizeof(im1024->font[ch])) im1024->font[ch][n] = bt;
}
im1024->fontx[ch] = cols;
im1024->fonty[ch] = rows;
}
static void hndl_tsize(pgc_core_t *pgc)
{
int16_t size;
if (!pgc_param_word(pgc, &size)) return;
PGCLOG(("TSIZE<IM1024>(%d)\n", size));
pgc->tsize = size << 16;
}
static void hndl_twrite(pgc_core_t *pgc)
{
unsigned char count;
unsigned char mask;
unsigned char *row;
int x, y, wb, n;
im1024_t * im1024 = (im1024_t *)pgc;
int16_t x0 = pgc->x >> 16;
int16_t y0 = pgc->y >> 16;
unsigned char buf[256];
/* unsigned char rbuf[256];*/
if (!pgc_param_byte(pgc, &count)) return;
for (n = 0; n < count; n++)
{
if (!pgc_param_byte(pgc, &buf[n])) return;
}
buf[count] = 0;
/* for (n = 0; n <= count; n++)
{
if (isprint(buf[n]) || 0 == buf[n])
{
rbuf[n] = buf[n];
}
else rbuf[n] = '?';
}*/
pgc_sto_raster(pgc, &x0, &y0);
PGCLOG(("TWRITE<IM1024> (%d,%-*.*s) x0=%d y0=%d\n", count, count, count, rbuf, x0, y0));
for (n = 0; n < count; n++)
{
wb = (im1024->fontx[buf[n]] + 7) / 8;
PGCLOG(("ch=0x%02x w=%d h=%d wb=%d\n",
buf[n], im1024->fontx[buf[n]],
im1024->fonty[buf[n]], wb));
for (y = 0; y < im1024->fonty[buf[n]]; y++)
{
mask = 0x80;
row = &im1024->font[buf[n]][y * wb];
for (x = 0; x < im1024->fontx[buf[n]]; x++)
{
/* rbuf[x] = (row[0] & mask) ? '#' : '-';*/
if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y);
mask = mask >> 1;
if (mask == 0) { mask = 0x80; ++row; }
}
/* rbuf[x++] = '\n';
rbuf[x++] = 0;*/
// PGCLOG((rbuf);
}
x0 += im1024->fontx[buf[n]];
}
}
static void hndl_txt88(pgc_core_t *pgc)
{
unsigned char count;
unsigned char mask;
unsigned char *row;
int x, y, /*wb, */n;
int16_t x0 = pgc->x >> 16;
int16_t y0 = pgc->y >> 16;
unsigned char buf[256];
/* unsigned char rbuf[256];*/
if (!pgc_param_byte(pgc, &count)) return;
for (n = 0; n < count; n++)
{
if (!pgc_param_byte(pgc, &buf[n])) return;
}
buf[count] = 0;
/* for (n = 0; n <= count; n++)
{
if (isprint(buf[n]) || 0 == buf[n])
{
rbuf[n] = buf[n];
}
else rbuf[n] = '?';
}*/
pgc_sto_raster(pgc, &x0, &y0);
PGCLOG(("TXT88<IM1024> (%d,%-*.*s) x0=%d y0=%d\n", count, count, count, rbuf, x0, y0));
for (n = 0; n < count; n++)
{
/* wb = 2;*/
PGCLOG(("ch=0x%02x w=%d h=%d wb=%d\n", buf[n], 12, 18, wb));
for (y = 0; y < 18; y++)
{
mask = 0x80;
row = &fontdat12x18[buf[n]][y * 2];
for (x = 0; x < 12; x++)
{
/* rbuf[x] = (row[0] & mask) ? '#' : '-';*/
if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y);
mask = mask >> 1;
if (mask == 0) { mask = 0x80; ++row; }
}
/* rbuf[x++] = '\n';
rbuf[x++] = 0;*/
// PGCLOG((rbuf);
}
x0 += 12;
}
}
static void hndl_imagew(pgc_core_t *pgc)
{
int16_t row1, col1, col2;
uint8_t v1, v2;
int16_t vp_x1, vp_y1, vp_x2, vp_y2;
if (!pgc_param_word(pgc, &row1)) return;
if (!pgc_param_word(pgc, &col1)) return;
if (!pgc_param_word(pgc, &col2)) return;
/* IMAGEW already uses raster coordinates so there is no need to
* convert it */
PGCLOG(("IMAGEW<IM1024> (row=%d,col1=%d,col2=%d)\n", row1, col1, col2));
vp_x1 = pgc->vp_x1;
vp_y1 = pgc->vp_y1;
vp_x2 = pgc->vp_x2;
vp_y2 = pgc->vp_y2;
/* Disable clipping */
pgc->vp_x1 = 0;
pgc->vp_y1 = 0;
pgc->vp_x2 = pgc->maxw - 1;
pgc->vp_y2 = pgc->maxh - 1;
/* In ASCII mode, what is written is a stream of bytes */
if (pgc->ascii_mode)
{
while (col1 <= col2)
{
if (!pgc_param_byte(pgc, &v1)) return;
pgc_write_pixel(pgc, col1, row1, v1);
++col1;
}
return;
}
else /* In hex mode, it's RLE compressed */
{
while (col1 <= col2)
{
if (!pgc_param_byte(pgc, &v1)) return;
if (v1 & 0x80) /* Literal run */
{
v1 -= 0x7F;
while (col1 <= col2 && v1 != 0)
{
if (!pgc_param_byte(pgc, &v2)) return;
pgc_write_pixel(pgc, col1, row1, v2);
++col1;
--v1;
}
}
else /* Repeated run */
{
if (!pgc_param_byte(pgc, &v2)) return;
++v1;
while (col1 <= col2 && v1 != 0)
{
pgc_write_pixel(pgc, col1, row1, v2);
++col1;
--v1;
}
}
}
}
/* Restore clipping */
pgc->vp_x1 = vp_x1;
pgc->vp_y1 = vp_y1;
pgc->vp_x2 = vp_x2;
pgc->vp_y2 = vp_y2;
}
/* I have called this command DOT - I don't know its proper name. Draws a
* single pixel at the current location */
static void hndl_dot(pgc_core_t *pgc)
{
int16_t x = pgc->x >> 16, y = pgc->y >> 16;
pgc_sto_raster(pgc, &x, &y);
PGCLOG(("Dot @ %d,%d ink=%d mode=%d\n", x, y, pgc->colour, pgc->draw_mode));
pgc_plot(pgc, x, y);
}
/* This command (which I have called IMAGEX, since I don't know its real
* name) is a screen-to-memory blit. It reads a rectangle of bytes, rather
* than the single row read by IMAGER, and does not attempt to compress
* the result */
static void hndl_imagex(pgc_core_t *pgc)
{
int16_t x0, x1, y0, y1;
int16_t p,q;
if (!pgc_param_word(pgc, &x0)) return;
if (!pgc_param_word(pgc, &y0)) return;
if (!pgc_param_word(pgc, &x1)) return;
if (!pgc_param_word(pgc, &y1)) return;
/* IMAGEX already uses raster coordinates so don't convert */
PGCLOG(("IMAGEX<IM1024> (%d,%d,%d,%d)\n", x0,y0,x1,y1));
for (p = y0; p <= y1; p++)
{
for (q = x0; q <= x1; q++)
{
if (!pgc_result_byte(pgc, pgc_read_pixel(pgc, q, p)))
return;
}
}
}
/* Commands implemented by the IM-1024.
*
* TODO: A lot of commands need commandlist parsers.
* TODO: The IM-1024 has a lot more commands that are not included here
* (BLINK, BUTRD, COPROC, RBAND etc) because the Windows 1.03 driver
* does not use them.
*/
static const pgc_command_t im1024_commands[] =
{
{ "BLKMOV", 0xDF, hndl_blkmov, pgc_parse_words, 6 },
{ "DRAW", 0x28, hndl_draw, pgc_parse_words, 2 },
{ "D", 0x28, hndl_draw, pgc_parse_words, 2 },
{ "DOT", 0x08, hndl_dot },
{ "ELIPSE", 0x39, hndl_ellipse, pgc_parse_words, 2 },
{ "EL", 0x39, hndl_ellipse, pgc_parse_words, 2 },
{ "IMAGEW", 0xD9, hndl_imagew },
{ "IW", 0xD9, hndl_imagew },
{ "IMAGEX", 0xDA, hndl_imagex },
{ "TXT88", 0x88, hndl_txt88 },
{ "TWRITE", 0x8B, hndl_twrite },
{ "TDEFIN", 0x84, hndl_tdefin },
{ "TD", 0x84, hndl_tdefin },
{ "TSIZE", 0x81, hndl_tsize },
{ "TS", 0x81, hndl_tsize },
{ "IPREC", 0xE4, hndl_iprec },
{ "IMGSIZ", 0x4E, hndl_imgsiz },
{ "LUT8", 0xE6, pgc_hndl_lut8 },
{ "L8", 0xE6, pgc_hndl_lut8 },
{ "LUT8RD", 0x53, pgc_hndl_lut8rd },
{ "L8RD", 0x53, pgc_hndl_lut8rd },
{ "PAN", 0xB7, hndl_pan },
{ "POLY", 0x30, hndl_poly, parse_poly },
{ "P", 0x30, hndl_poly, parse_poly },
{ "PLINE", 0x36, hndl_pline },
{ "PL", 0x37, hndl_pline },
{ "MOVE", 0x10, hndl_move, pgc_parse_words, 2 },
{ "M", 0x10, hndl_move, pgc_parse_words, 2 },
{ "RECT", 0x34, hndl_rect },
{ "R", 0x34, hndl_rect },
{ "******", 0x00, NULL }
};
void *im1024_init()
{
im1024_t *im1024 = malloc(sizeof(im1024_t));
memset(im1024, 0, sizeof(im1024_t));
im1024->fifo = malloc(4096);
im1024->fifo_len = 4096;
im1024->fifo_wrptr = 0;
im1024->fifo_rdptr = 0;
/* 1024x1024 framebuffer with 1024x800 visible
Pixel clock is a guess */
pgc_core_init(&im1024->pgc, 1024, 1024, 1024, 800, im1024_input_byte, 65000000.0);
mem_mapping_set_handler(&im1024->pgc.mapping,
im1024_read, NULL, NULL,
im1024_write, NULL, NULL);
im1024->pgc.pgc_commands = im1024_commands;
return im1024;
}
void im1024_close(void *p)
{
im1024_t *im1024 = (im1024_t *)p;
pgc_close(&im1024->pgc);
}
void im1024_speed_changed(void *p)
{
im1024_t *im1024 = (im1024_t *)p;
pgc_speed_changed(&im1024->pgc);
}
device_t im1024_device =
{
"Image Manager 1024",
0,
im1024_init,
im1024_close,
NULL,
im1024_speed_changed,
NULL,
NULL,
NULL
};