From 932378bed8181cda16b7b68eed28c23235a0583e Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 18 Dec 2016 10:44:28 +0000 Subject: [PATCH] Add missing Wyse 700 files --- src/vid_wy700.c | 994 ++++++++++++++++++++++++++++++++++++++++++++++++ src/vid_wy700.h | 1 + 2 files changed, 995 insertions(+) create mode 100644 src/vid_wy700.c create mode 100644 src/vid_wy700.h diff --git a/src/vid_wy700.c b/src/vid_wy700.c new file mode 100644 index 0000000..7f1cb27 --- /dev/null +++ b/src/vid_wy700.c @@ -0,0 +1,994 @@ +/* Wyse-700 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_wy700.h" + +#define WY700_XSIZE 1280 +#define WY700_YSIZE 800 + +void updatewindowsize(int x, int y); +void loadfont(char *s, int format); + + +/* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this + * is not exposed directly to the host PC. Instead, the CRTC is controlled by + * an MC68705P3 microcontroller. + * + * Rather than emulate the real CRTC, I'm writing this as more or less a + * fixed-frequency card with a 1280x800 display, and scaling its selection + * of modes to that window. + * + * By default, the card responds to both the CGA and MDA I/O and memory + * ranges. Either range can be disabled by means of jumpers; this allows + * the Wy700 to coexist with a CGA or MDA. + * + * wy700->wy700_mode indicates which of the supported video modes is in use: + * + * 0x00: 40x 25 text (CGA compatible) [32x32 character cell] + * 0x02: 80x 25 text (CGA / MDA compatible) [16x32 character cell] + * 0x04: 320x200x4 graphics (CGA compatible) + * 0x06: 640x200x2 graphics (CGA compatible) + * 0x80: 640x400x2 graphics + * 0x90: 320x400x4 graphics + * 0xA0: 1280x400x2 graphics + * 0xB0: 640x400x4 graphics + * 0xC0: 1280x800x2 graphics (interleaved) + * 0xD0: 640x800x4 graphics (interleaved) + * In hi-res graphics modes, bit 3 of the mode byte is the enable flag. + * + */ + +/* What works (or appears to) : + * MDA/CGA 80x25 text mode + * CGA 40x25 text mode + * CGA 640x200 graphics mode + * CGA 320x200 graphics mode + * Hi-res graphics modes + * Font selection + * Display enable / disable + * -- via Wy700 mode register (in hi-res modes) + * -- via Wy700 command register (in text & CGA modes) + * -- via CGA/MDA control register (in text & CGA modes) + * + * What doesn't work, is untested or not well understood: + * - Cursor detach (commands 4 and 5) + */ + + +/* The microcontroller sets up the real CRTC with one of five fixed mode + * definitions. As written, this is a fairly simplistic emulation that + * doesn't attempt to closely follow the actual working of the CRTC; but I've + * included the definitions here for information. */ + +static uint8_t mode_1280x800[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_1280x400[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x400[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0x03, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x200[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x37, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x32, /* Vertical displayed */ + 0x34, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x07, /* Maximum raster address */ +}; + +static uint8_t mode_80x24[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x2A, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_40x24[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x15, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + + +/* Font ROM: Two fonts, each containing 256 characters, 16x16 pixels */ +extern uint8_t fontdatw[512][32]; + +typedef struct wy700_t +{ + mem_mapping_t mapping; + + /* The microcontroller works by watching four ports: + * 0x3D8 / 0x3B8 (mode control register) + * 0x3DD (top scanline address) + * 0x3DF (Wy700 control register) + * CRTC reg 14 (cursor location high) + * + * It will do nothing until one of these registers is touched. When + * one is, it then reconfigures the internal 6845 based on what it + * sees. + */ + uint8_t last_03D8; /* Copies of values written to the listed */ + uint8_t last_03DD; /* I/O ports */ + uint8_t last_03DF; + uint8_t last_crtc_0E; + + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + uint8_t real_crtc[32]; /* The internal CRTC as the microcontroller */ + /* sees it */ + int cga_crtcreg; /* Current CRTC register */ + uint16_t wy700_base; /* Framebuffer base address (native modes) */ + uint8_t wy700_control; /* Native control / command register */ + uint8_t wy700_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated MDA/CGA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int dispontime, dispofftime; + int vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int vsynctime; + + uint8_t *vram; +} wy700_t; + +/* Mapping of attributes to colours, in CGA emulation... */ +static int cgacols[256][2][2]; +/* ... and MDA emulation. */ +static int mdacols[256][2][2]; + +void wy700_recalctimings(wy700_t *wy700); +void wy700_write(uint32_t addr, uint8_t val, void *p); +uint8_t wy700_read(uint32_t addr, void *p); +void wy700_checkchanges(wy700_t *wy700); + + +void wy700_out(uint16_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + /* These three registers are only mapped in the 3Dx range, + * not the 3Bx range. */ + case 0x3DD: /* Base address (low) */ + wy700->wy700_base &= 0xFF00; + wy700->wy700_base |= val; + wy700_checkchanges(wy700); + break; + + case 0x3DE: /* Base address (high) */ + wy700->wy700_base &= 0xFF; + wy700->wy700_base |= ((uint16_t)val) << 8; + wy700_checkchanges(wy700); + break; + + case 0x3DF: /* Command / control register */ + wy700->wy700_control = val; + wy700_checkchanges(wy700); + break; + + /* Emulated CRTC, register select */ + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + wy700->cga_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + wy700->cga_crtc[wy700->cga_crtcreg] = val; + + wy700_checkchanges(wy700); + wy700_recalctimings(wy700); + return; + + /* Emulated MDA / CGA control register */ + case 0x3b8: case 0x3D8: + wy700->cga_ctrl = val; + wy700_checkchanges(wy700); + return; + /* Emulated CGA colour register */ + case 0x3D9: + wy700->cga_colour = val; + return; + } +} + +uint8_t wy700_in(uint16_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return wy700->cga_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return wy700->cga_crtc[wy700->cga_crtcreg]; + case 0x3b8: case 0x3d8: + return wy700->cga_ctrl; + case 0x3d9: + return wy700->cga_colour; + case 0x3ba: + return wy700->mda_stat; + case 0x3da: + return wy700->cga_stat; + } + return 0xff; +} + + +/* Check if any of the four key registers has changed. If so, check for a + * mode change or cursor size change */ +void wy700_checkchanges(wy700_t *wy700) +{ + uint8_t curstart, curend; + + if (wy700->last_03D8 == wy700->cga_ctrl && + wy700->last_03DD == (wy700->wy700_base & 0xFF) && + wy700->last_03DF == wy700->wy700_control && + wy700->last_crtc_0E == wy700->cga_crtc[0x0E]) + { + return; /* Nothing changed */ + } + /* Check for control register changes */ + if (wy700->last_03DF != wy700->wy700_control) + { + wy700->last_03DF = wy700->wy700_control; + + /* Values 1-7 are commands. */ + switch (wy700->wy700_control) + { + case 1: /* Reset */ + wy700->font = 0; + wy700->enabled = 1; + wy700->detach = 0; + break; + + case 2: /* Font 1 */ + wy700->font = 0; + break; + + case 3: /* Font 2 */ + wy700->font = 1; + break; + +/* Even with the microprogram from an original card, I can't really work out + * what commands 4 and 5 (which I've called 'cursor detach' / 'cursor attach') + * do. Command 4 sets a flag in microcontroller RAM, and command 5 clears + * it. When the flag is set, the real cursor doesn't track the cursor in the + * emulated CRTC, and its blink rate increases. Possibly it's a self-test + * function of some kind. + * + * The card documentation doesn't cover these commands. + */ + + case 4: /* Detach cursor */ + wy700->detach = 1; + break; + + case 5: /* Attach cursor */ + wy700->detach = 0; + break; + + case 6: /* Disable display */ + wy700->enabled = 0; + break; + + case 7: /* Enable display */ + wy700->enabled = 1; + break; + } + /* A control write with the top bit set selects graphics mode */ + if (wy700->wy700_control & 0x80) + { + /* Select hi-res graphics mode; map framebuffer at A0000 */ + mem_mapping_set_addr(&wy700->mapping, 0xa0000, 0x20000); + wy700->wy700_mode = wy700->wy700_control; + + /* Select appropriate preset timings */ + if (wy700->wy700_mode & 0x40) + { + memcpy(wy700->real_crtc, mode_1280x800, + sizeof(mode_1280x800)); + } + else if (wy700->wy700_mode & 0x20) + { + memcpy(wy700->real_crtc, mode_1280x400, + sizeof(mode_1280x400)); + } + else + { + memcpy(wy700->real_crtc, mode_640x400, + sizeof(mode_640x400)); + } + } + } + /* An attempt to program the CGA / MDA selects low-res mode */ + else if (wy700->last_03D8 != wy700->cga_ctrl) + { + wy700->last_03D8 = wy700->cga_ctrl; + /* Set lo-res text or graphics mode. + * (Strictly speaking, when not in hi-res mode the card + * should be mapped at B0000-B3FFF and B8000-BBFFF, leaving + * a 16k hole between the two ranges) */ + mem_mapping_set_addr(&wy700->mapping, 0xb0000, 0x0C000); + if (wy700->cga_ctrl & 2) /* Graphics mode */ + { + wy700->wy700_mode = (wy700->cga_ctrl & 0x10) ? 6 : 4; + memcpy(wy700->real_crtc, mode_640x200, + sizeof(mode_640x200)); + } + else if (wy700->cga_ctrl & 1) /* Text mode 80x24 */ + { + wy700->wy700_mode = 2; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + } + else /* Text mode 40x24 */ + { + wy700->wy700_mode = 0; + memcpy(wy700->real_crtc, mode_40x24, sizeof(mode_40x24)); + } + } + /* Convert the cursor sizes from the ones used by the CGA or MDA + * to native */ + + if (wy700->cga_crtc[9] == 13) /* MDA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = ((curstart + 5) >> 3) + curstart; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = ((curend + 5) >> 3) + curend; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } + else /* CGA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = curstart << 1; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = curend << 1; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } +} + + +void wy700_write(uint32_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egawrites++; + + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 1 of the control register sets the high bit of the + * write address. */ + if ((wy700->wy700_mode & 0x42) == 0x42) + { + addr |= 0x10000; + } + wy700->vram[addr] = val; + } + else + { + wy700->vram[addr & 0x3fff] = val; + } +} + + + +uint8_t wy700_read(uint32_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egareads++; + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 0 of the control register sets the high bit of the + * read address. */ + if ((wy700->wy700_mode & 0x41) == 0x41) + { + addr |= 0x10000; + } + return wy700->vram[addr]; + } + else + { + return wy700->vram[addr & 0x3fff]; + } +} + + + +void wy700_recalctimings(wy700_t *wy700) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = wy700->real_crtc[0] + 1; + _dispontime = wy700->real_crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + wy700->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + wy700->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void wy700_textline(wy700_t *wy700) +{ + int x; + int w = (wy700->wy700_mode == 0) ? 40 : 80; + int cw = (wy700->wy700_mode == 0) ? 32 : 16; + uint8_t chr, attr, fg, bg; + uint8_t bitmap[2]; + uint8_t *fontbase = &fontdatw[0][0]; + int blink, c; + int drawcursor, cursorline; + int mda = 0; + uint16_t addr; + uint8_t sc; + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; + + +/* The fake CRTC character height register selects whether MDA or CGA + * attributes are used */ + if (wy700->cga_crtc[9] == 0 || wy700->cga_crtc[9] == 13) + { + mda = 1; + } + + if (wy700->font) + { + fontbase += 256*32; + } + addr = ((ma & ~1) + (wy700->displine >> 5) * w) * 2; + sc = (wy700->displine >> 1) & 15; + + ma += ((wy700->displine >> 5) * w); + + if ((wy700->real_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((wy700->real_crtc[10] & 0x1F) <= sc) && + ((wy700->real_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = wy700->vram[(addr + 2 * x) & 0x3FFF]; + attr = wy700->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && wy700->enabled && + (wy700->cga_ctrl & 8) && (wy700->blink & 16)); + blink = ((wy700->blink & 16) && + (wy700->cga_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (wy700->cga_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == 14 && mda && ((attr & 7) == 1)) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] = + mdacols[attr][blink][1]; + } + else /* Draw 16 pixels of character */ + { + bitmap[0] = fontbase[chr * 32 + 2 * sc]; + bitmap[1] = fontbase[chr * 32 + 2 * sc + 1]; + for (c = 0; c < 16; c++) + { + int col; + if (c < 8) + col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + else col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + col = mdacols[0][0][0]; + if (w == 40) + { + buffer->line[wy700->displine][(x * cw) + 2*c] = col; + buffer->line[wy700->displine][(x * cw) + 2*c + 1] = col; + } + else buffer->line[wy700->displine][(x * cw) + c] = col; + } + + if (drawcursor) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + } + ++ma; + } + } +} + + +/* Draw a line in either of the CGA graphics modes (320x200 or 640x200) */ +void wy700_cgaline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t bitmap, ink; + uint16_t addr; + + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + addr = ((wy700->displine >> 2) & 1) * 0x2000 + + (wy700->displine >> 3) * 80 + + ((ma & ~1) << 1); + + /* The fixed mode setting here programs the real CRTC with a screen + * width to 20, so draw in 20 fixed chunks of 4 bytes each */ + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x3FFF] << 24) | + (wy700->vram[(addr+1) & 0x3FFF] << 16) | + (wy700->vram[(addr+2) & 0x3FFF] << 8) | + (wy700->vram[(addr+3) & 0x3FFF])); + addr += 4; + + if (wy700->wy700_mode == 6) + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + else + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + } +} + +/* Draw a line in the medium-resolution graphics modes (640x400 or 320x400) */ +void wy700_medresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t bitmap, ink; + uint32_t addr; + + addr = (wy700->displine >> 1) * 80 + 4 * wy700->wy700_base; + + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + } +} + + + + +/* Draw a line in one of the high-resolution modes */ +void wy700_hiresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t bitmap, ink; + uint32_t addr; + + addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; + + if (wy700->wy700_mode & 0x40) /* 800-line interleaved modes */ + { + if (wy700->displine & 1) addr += 0x10000; + } + for (x = 0; x < 40; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + 2*c] = + buffer->line[wy700->displine][x*32 + 2*c+1] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + c] = ink; + dat = dat << 1; + } + } + } +} + + + + +void wy700_poll(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int mode; + + if (!wy700->linepos) + { + wy700->vidtime += wy700->dispofftime; + wy700->cga_stat |= 1; + wy700->mda_stat |= 1; + wy700->linepos = 1; + if (wy700->dispon) + { + if (wy700->displine == 0) + { + video_wait_for_buffer(); + } + + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + + switch (mode) + { + default: + case 0x00: + case 0x02: + wy700_textline(wy700); + break; + case 0x04: + case 0x06: + wy700_cgaline(wy700); + break; + case 0x80: + case 0x90: + wy700_medresline(wy700); + break; + case 0xA0: + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + case 0xF0: + wy700_hiresline(wy700); + break; + } + } + wy700->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (wy700->displine == 800) /* Start of VSYNC */ + { + wy700->cga_stat |= 8; + wy700->dispon = 0; + } + if (wy700->displine == 832) /* End of VSYNC */ + { + wy700->displine = 0; + wy700->cga_stat &= ~8; + wy700->dispon = 1; + } + } + else + { + if (wy700->dispon) + { + wy700->cga_stat &= ~1; + wy700->mda_stat &= ~1; + } + wy700->vidtime += wy700->dispontime; + wy700->linepos = 0; + + if (wy700->displine == 800) + { +/* Hardcode 1280x800 window size */ + if (WY700_XSIZE != xsize || WY700_YSIZE != ysize) + { + xsize = WY700_XSIZE; + ysize = WY700_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen_8(0, 0, xsize, ysize); + + frames++; + /* Fixed 1280x800 resolution */ + video_res_x = WY700_XSIZE; + video_res_y = WY700_YSIZE; + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + switch(mode) + { + case 0x00: + case 0x02: video_bpp = 0; break; + case 0x04: + case 0x90: + case 0xB0: + case 0xD0: + case 0xF0: video_bpp = 2; break; + default: video_bpp = 1; break; + } + wy700->blink++; + } + } +} + +void *wy700_init() +{ + int c; + wy700_t *wy700 = malloc(sizeof(wy700_t)); + memset(wy700, 0, sizeof(wy700_t)); + + /* 128k video RAM */ + wy700->vram = malloc(0x20000); + + timer_add(wy700_poll, &wy700->vidtime, TIMER_ALWAYS_ENABLED, wy700); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&wy700->mapping, 0xb0000, 0x10000, wy700_read, NULL, NULL, wy700_write, NULL, NULL, NULL, 0, wy700); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + + /* Set up the emulated attributes. + * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ + for (c = 0; c < 0x10; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + } + for (c = 0x10; c < 0x80; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16 + 7; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 0 + 16; + + if ((c & 0x0F) == 8) cgacols[c][0][1] = 8 + 16; + } + /* With special cases for 00, 11, 22, ... 77 */ + cgacols[0x00][0][1] = cgacols[0x00][1][1] = 16; + for (c = 0x11; c <= 0x77; c += 0x11) + { + cgacols[c][0][1] = cgacols[c][1][1] = 16 + 7; + } + for (c = 0x80; c < 0x90; c++) + { + cgacols[c][0][0] = 16 + 8; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + for (c = 0x90; c < 0x100; c++) + { + cgacols[c][0][0] = 16 + 15; + if (c & 8) cgacols[c][0][1] = 8 + 16; + else cgacols[c][0][1] = 7 + 16; + if ((c & 0x0F) == 0) cgacols[c][0][1] = 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + /* Also special cases for 99, AA, ..., FF */ + for (c = 0x99; c <= 0xFF; c += 0x11) + { + cgacols[c][0][1] = 16 + 15; + } + /* Special cases for 08, 80 and 88 */ + cgacols[0x08][0][1] = 16 + 8; + cgacols[0x80][0][1] = 16; + cgacols[0x88][0][1] = 16 + 8; + + /* MDA attributes */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + +/* Start off in 80x25 text mode */ + wy700->cga_stat = 0xF4; + wy700->wy700_mode = 2; + wy700->enabled = 1; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + return wy700; +} + +void wy700_close(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + free(wy700->vram); + free(wy700); +} + +void wy700_speed_changed(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + wy700_recalctimings(wy700); +} + +device_t wy700_device = +{ + "Wyse 700", + 0, + wy700_init, + wy700_close, + NULL, + wy700_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_wy700.h b/src/vid_wy700.h new file mode 100644 index 0000000..72c6d1a --- /dev/null +++ b/src/vid_wy700.h @@ -0,0 +1 @@ +extern device_t wy700_device;