New graphics card(s): Quadram Quadcolor I / I+II (#281)

This commit is contained in:
Benedikt Freisen
2025-06-19 21:08:27 +02:00
committed by GitHub
parent a3fb803078
commit 2d75892db3
6 changed files with 578 additions and 5 deletions

View File

@@ -25,6 +25,7 @@
## Added the following Video Cards to v18
- Matrox Millennium
- Quadram Quadcolor I / I+II
## Developer Changes to v18
- First release to switch from autotools/make to CMake/Ninja

View File

@@ -321,6 +321,7 @@ enum {
GFX_VOODOO_3_2000, /*Voodoo 3 2000*/
GFX_VOODOO_3_3000, /*Voodoo 3 3000*/
GFX_MILLENNIUM, /*Matrox Millennium*/
GFX_QUADCOLOR, /*Quadram Quadcolor I/II*/
GFX_BUILTIN_MAX,
};

View File

@@ -0,0 +1,57 @@
#ifndef _VID_QUADCOLOR_H_
#define _VID_QUADCOLOR_H_
typedef struct quadcolor_t {
mem_mapping_t mapping;
mem_mapping_t mapping_2;
int crtcreg;
uint8_t crtc[32];
uint8_t cgastat;
uint8_t cgamode, cgacol;
uint8_t quadcolor_ctrl;
uint8_t quadcolor_2_oe;
uint16_t page_offset;
int fontbase;
int linepos, displine;
int sc, vc;
int cgadispon;
int con, coff, cursoron, cgablink;
int vsynctime, vadj;
uint16_t ma, maback;
int oddeven;
int qc2idx;
uint8_t qc2mask;
uint64_t dispontime, dispofftime;
pc_timer_t timer;
int firstline, lastline;
int drawcursor;
uint8_t *vram;
uint8_t *vram_2;
uint8_t charbuffer[256];
int revision;
int composite;
int has_2nd_charset;
int has_quadcolor_2;
} quadcolor_t;
void quadcolor_init(quadcolor_t *quadcolor);
void quadcolor_out(uint16_t addr, uint8_t val, void *p);
uint8_t quadcolor_in(uint16_t addr, void *p);
void quadcolor_write(uint32_t addr, uint8_t val, void *p);
uint8_t quadcolor_read(uint32_t addr, void *p);
void quadcolor_recalctimings(quadcolor_t *quadcolor);
void quadcolor_poll(void *p);
extern device_t quadcolor_device;
#endif /* _VID_QUADCOLOR_H_ */

503
src/video/vid_quadcolor.c Normal file
View File

@@ -0,0 +1,503 @@
/* Quadram Quadcolor I / I+II emulation */
/* This has been derived from CGA emulation */
/* omissions: simulated snow (Quadcolor has dual-ported RAM), single and dual 8x16 font configuration */
/* additions: ports 0x3dd and 0x3de, 2nd char set, 2nd VRAM bank, hi-res bg color, Quadcolor II memory and mode */
/* assumptions: MA line 12 XORed with Bank Select, hi-res bg is also border color, QC2 mode has simple address counter */
#include <stdlib.h>
#include <math.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "mem.h"
#include "timer.h"
#include "video.h"
#include "vid_quadcolor.h"
#include "dosbox/vid_cga_comp.h"
#define COMPOSITE_OLD 0
#define COMPOSITE_NEW 1
static uint8_t crtcmask[32] = {0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void quadcolor_recalctimings(quadcolor_t *quadcolor);
void quadcolor_out(uint16_t addr, uint8_t val, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
uint8_t old;
// pclog("CGA_OUT %04X %02X\n", addr, val);
switch (addr) {
case 0x3d0:
case 0x3d2:
case 0x3d4:
case 0x3d6:
quadcolor->crtcreg = val & 31;
return;
case 0x3d1:
case 0x3d3:
case 0x3d5:
case 0x3d7:
old = quadcolor->crtc[quadcolor->crtcreg];
quadcolor->crtc[quadcolor->crtcreg] = val & crtcmask[quadcolor->crtcreg];
if (old != val) {
if (quadcolor->crtcreg < 0xe || quadcolor->crtcreg > 0x10) {
fullchange = changeframecount;
quadcolor_recalctimings(quadcolor);
}
}
return;
case 0x3d8:
if (((quadcolor->cgamode ^ val) & 5) != 0) {
quadcolor->cgamode = val;
update_cga16_color(quadcolor->cgamode);
}
quadcolor->cgamode = val;
return;
case 0x3d9:
quadcolor->cgacol = val;
return;
case 0x3dd:
quadcolor->quadcolor_ctrl = val & 0x3f;
/* helper variable that can be XORed onto the VRAM address to select the page to display */
quadcolor->page_offset = (val & 0x10) << 8;
/* in dual 8x8 font configuration, use fontbase 256 if "Character Set Select" bit is set */
if (quadcolor->has_2nd_charset)
quadcolor->fontbase = (val & 0x20) << 3;
return;
case 0x3de:
/* NOTE: the polarity of this register is the opposite of what the manual says */
if (quadcolor->has_quadcolor_2)
quadcolor->quadcolor_2_oe = !(val & 0x10);
return;
}
}
uint8_t quadcolor_in(uint16_t addr, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
// pclog("CGA_IN %04X\n", addr);
switch (addr) {
case 0x3D4:
return quadcolor->crtcreg;
case 0x3D5:
return quadcolor->crtc[quadcolor->crtcreg];
case 0x3DA:
return quadcolor->cgastat;
}
return 0xFF;
}
void quadcolor_write(uint32_t addr, uint8_t val, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
// pclog("CGA_WRITE %04X %02X\n", addr, val);
quadcolor->vram[addr & 0x7fff] = val;
egawrites++;
cycles -= 4;
}
uint8_t quadcolor_read(uint32_t addr, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
cycles -= 4;
egareads++;
// pclog("CGA_READ %04X\n", addr);
return quadcolor->vram[addr & 0x7fff];
}
void quadcolor_2_write(uint32_t addr, uint8_t val, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
quadcolor->vram_2[addr & 0xffff] = val;
}
uint8_t quadcolor_2_read(uint32_t addr, void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
return quadcolor->vram_2[addr & 0xffff];
}
void quadcolor_recalctimings(quadcolor_t *quadcolor) {
double disptime;
double _dispontime, _dispofftime;
pclog("Recalc - %i %i %i\n", quadcolor->crtc[0], quadcolor->crtc[1], quadcolor->cgamode & 1);
if (quadcolor->cgamode & 1) {
disptime = quadcolor->crtc[0] + 1;
_dispontime = quadcolor->crtc[1];
} else {
disptime = (quadcolor->crtc[0] + 1) << 1;
_dispontime = quadcolor->crtc[1] << 1;
}
_dispofftime = disptime - _dispontime;
// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]);
_dispontime *= CGACONST;
_dispofftime *= CGACONST;
// printf("Timings - on %f off %f frame %f second
// %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92);
quadcolor->dispontime = (uint64_t)_dispontime;
quadcolor->dispofftime = (uint64_t)_dispofftime;
}
static inline uint8_t get_next_qc2_pixel(quadcolor_t *quadcolor) {
uint8_t pixel = (quadcolor->vram_2[quadcolor->qc2idx] & quadcolor->qc2mask) >> ((quadcolor->qc2mask = ~quadcolor->qc2mask) & 4);
quadcolor->qc2idx += quadcolor->qc2mask >> 7;
return quadcolor->quadcolor_2_oe ? pixel : 0;
}
void quadcolor_poll(void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
uint16_t ca = (quadcolor->crtc[15] | (quadcolor->crtc[14] << 8)) & 0x7fff;
int drawcursor;
int x, c;
int oldvc;
uint8_t chr, attr;
uint16_t dat;
uint32_t cols[4];
int col;
int oldsc;
if (!quadcolor->linepos) {
timer_advance_u64(&quadcolor->timer, quadcolor->dispofftime);
quadcolor->cgastat |= 1;
quadcolor->linepos = 1;
oldsc = quadcolor->sc;
if ((quadcolor->crtc[8] & 3) == 3)
quadcolor->sc = ((quadcolor->sc << 1) + quadcolor->oddeven) & 7;
if (quadcolor->cgadispon) {
if (quadcolor->displine < quadcolor->firstline) {
quadcolor->firstline = quadcolor->displine;
video_wait_for_buffer();
// printf("Firstline %i\n",firstline);
}
quadcolor->lastline = quadcolor->displine;
cols[0] = ((quadcolor->cgamode & 0x12) == 0x12) ? (quadcolor->quadcolor_ctrl & 15) : (quadcolor->cgacol & 15); /* TODO: Is Quadcolor bg color actually relevant, here? */
for (c = 0; c < 8; c++) {
((uint32_t *)buffer32->line[quadcolor->displine])[c] = cols[0];
if (quadcolor->cgamode & 1)
((uint32_t *)buffer32->line[quadcolor->displine])[c + (quadcolor->crtc[1] << 3) + 8] = cols[0];
else
((uint32_t *)buffer32->line[quadcolor->displine])[c + (quadcolor->crtc[1] << 4) + 8] = cols[0];
}
if (quadcolor->cgamode & 1) { /* 80-column text */
for (x = 0; x < quadcolor->crtc[1]; x++) {
if (quadcolor->cgamode & 8) {
chr = quadcolor->charbuffer[x << 1];
attr = quadcolor->charbuffer[(x << 1) + 1];
} else
chr = attr = 0;
drawcursor = ((quadcolor->ma == ca) && quadcolor->con && quadcolor->cursoron);
if (quadcolor->cgamode & 0x20) {
cols[1] = attr & 15;
cols[0] = (attr >> 4) & 7;
if ((quadcolor->cgablink & 8) && (attr & 0x80) && !quadcolor->drawcursor)
cols[1] = cols[0];
} else {
cols[1] = attr & 15;
cols[0] = attr >> 4;
}
if (drawcursor) {
for (c = 0; c < 8; c++)
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 3) + c + 8] =
(cols[(fontdat[chr + quadcolor->fontbase][quadcolor->sc & 7] & (1 << (c ^ 7)))
? 1
: 0] ^
0xffffff) | get_next_qc2_pixel(quadcolor);
} else {
for (c = 0; c < 8; c++)
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 3) + c + 8] =
cols[(fontdat[chr + quadcolor->fontbase][quadcolor->sc & 7] & (1 << (c ^ 7)))
? 1
: 0] | get_next_qc2_pixel(quadcolor);
}
quadcolor->ma++;
}
} else if (!(quadcolor->cgamode & 2)) { /* not graphics (nor 80-column text) => 40-column text */
for (x = 0; x < quadcolor->crtc[1]; x++) {
if (quadcolor->cgamode & 8) {
chr = quadcolor->vram[quadcolor->page_offset ^ ((quadcolor->ma << 1) & 0x7fff)];
attr = quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) + 1) & 0x7fff)];
} else
chr = attr = 0;
drawcursor = ((quadcolor->ma == ca) && quadcolor->con && quadcolor->cursoron);
if (quadcolor->cgamode & 0x20) {
cols[1] = attr & 15;
cols[0] = (attr >> 4) & 7;
if ((quadcolor->cgablink & 8) && (attr & 0x80) && !quadcolor->drawcursor)
cols[1] = cols[0];
} else {
cols[1] = attr & 15;
cols[0] = attr >> 4;
}
quadcolor->ma++;
if (drawcursor) {
for (c = 0; c < 8; c++) {
dat = (cols[(fontdat[chr + quadcolor->fontbase][quadcolor->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff);
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 8] = dat | get_next_qc2_pixel(quadcolor);
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 1 + 8] = dat | get_next_qc2_pixel(quadcolor);
}
} else {
for (c = 0; c < 8; c++) {
dat = cols[(fontdat[chr + quadcolor->fontbase][quadcolor->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 8] = dat | get_next_qc2_pixel(quadcolor);
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 1 + 8] = dat | get_next_qc2_pixel(quadcolor);
}
}
}
} else if (!(quadcolor->cgamode & 16)) { /* not hi-res (but graphics) => 4-color mode */
cols[0] = quadcolor->cgacol & 15;
col = (quadcolor->cgacol & 16) ? 8 : 0;
if (quadcolor->cgamode & 4) {
cols[1] = col | 3;
cols[2] = col | 4;
cols[3] = col | 7;
} else if (quadcolor->cgacol & 32) {
cols[1] = col | 3;
cols[2] = col | 5;
cols[3] = col | 7;
} else {
cols[1] = col | 2;
cols[2] = col | 4;
cols[3] = col | 6;
}
for (x = 0; x < quadcolor->crtc[1]; x++) {
if (quadcolor->cgamode & 8)
dat = (quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) & 0x1fff) + ((quadcolor->sc & 1) * 0x2000))] << 8) |
quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) & 0x1fff) + ((quadcolor->sc & 1) * 0x2000) + 1)];
else
dat = 0;
quadcolor->ma++;
for (c = 0; c < 8; c++) {
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 8] = cols[dat >> 14] | get_next_qc2_pixel(quadcolor);
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14] | get_next_qc2_pixel(quadcolor);
dat <<= 2;
}
}
} else { /* 2-color hi-res graphics mode */
cols[0] = quadcolor->quadcolor_ctrl & 15; /* background color (Quadcolor-specific) */
cols[1] = quadcolor->cgacol & 15;
for (x = 0; x < quadcolor->crtc[1]; x++) {
if (quadcolor->cgamode & 8) /* video enabled */
dat = (quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) & 0x1fff) + ((quadcolor->sc & 1) * 0x2000))] << 8) |
quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) & 0x1fff) + ((quadcolor->sc & 1) * 0x2000) + 1)];
else
dat = quadcolor->quadcolor_ctrl & 15; /* TODO: Is Quadcolor bg color actually relevant, here? Probably. See QC2 manual p.46 1. */
quadcolor->ma++;
for (c = 0; c < 16; c++) {
((uint32_t *)buffer32->line[quadcolor->displine])[(x << 4) + c + 8] = cols[dat >> 15] | get_next_qc2_pixel(quadcolor);
dat <<= 1;
}
}
}
} else {
cols[0] = ((quadcolor->cgamode & 0x12) == 0x12) ? (quadcolor->quadcolor_ctrl & 15) : (quadcolor->cgacol & 15); /* TODO: Is Quadcolor bg color actually relevant, here? */
if (quadcolor->cgamode & 1)
hline(buffer32, 0, quadcolor->displine, (quadcolor->crtc[1] << 3) + 16, cols[0]);
else
hline(buffer32, 0, quadcolor->displine, (quadcolor->crtc[1] << 4) + 16, cols[0]);
}
if (quadcolor->cgamode & 1)
x = (quadcolor->crtc[1] << 3) + 16;
else
x = (quadcolor->crtc[1] << 4) + 16;
if (quadcolor->composite) {
for (c = 0; c < x; c++)
buffer32->line[quadcolor->displine][c] = ((uint32_t *)buffer32->line[quadcolor->displine])[c] & 0xf;
Composite_Process(quadcolor->cgamode, 0, x >> 2, buffer32->line[quadcolor->displine]);
} else {
for (c = 0; c < x; c++)
((uint32_t *)buffer32->line[quadcolor->displine])[c] =
cgapal[((uint32_t *)buffer32->line[quadcolor->displine])[c] & 0xf];
}
quadcolor->sc = oldsc;
if (quadcolor->vc == quadcolor->crtc[7] && !quadcolor->sc)
quadcolor->cgastat |= 8;
quadcolor->displine++;
if (quadcolor->displine >= 360)
quadcolor->displine = 0;
} else {
timer_advance_u64(&quadcolor->timer, quadcolor->dispontime);
quadcolor->linepos = 0;
if (quadcolor->vsynctime) {
quadcolor->vsynctime--;
if (!quadcolor->vsynctime)
quadcolor->cgastat &= ~8;
quadcolor->qc2idx = 0;
quadcolor->qc2mask = 0xf0;
}
if (quadcolor->sc == (quadcolor->crtc[11] & 31) || ((quadcolor->crtc[8] & 3) == 3 && quadcolor->sc == ((quadcolor->crtc[11] & 31) >> 1))) {
quadcolor->con = 0;
quadcolor->coff = 1;
}
if ((quadcolor->crtc[8] & 3) == 3 && quadcolor->sc == (quadcolor->crtc[9] >> 1))
quadcolor->maback = quadcolor->ma;
if (quadcolor->vadj) {
quadcolor->sc++;
quadcolor->sc &= 31;
quadcolor->ma = quadcolor->maback;
quadcolor->vadj--;
if (!quadcolor->vadj) {
quadcolor->cgadispon = 1;
quadcolor->ma = quadcolor->maback = (quadcolor->crtc[13] | (quadcolor->crtc[12] << 8)) & 0x7fff;
quadcolor->sc = 0;
}
} else if (quadcolor->sc == quadcolor->crtc[9]) {
quadcolor->maback = quadcolor->ma;
quadcolor->sc = 0;
oldvc = quadcolor->vc;
quadcolor->vc++;
quadcolor->vc &= 127;
if (quadcolor->vc == quadcolor->crtc[6])
quadcolor->cgadispon = 0;
if (oldvc == quadcolor->crtc[4]) {
quadcolor->vc = 0;
quadcolor->vadj = quadcolor->crtc[5];
if (!quadcolor->vadj)
quadcolor->cgadispon = 1;
if (!quadcolor->vadj)
quadcolor->ma = quadcolor->maback = (quadcolor->crtc[13] | (quadcolor->crtc[12] << 8)) & 0x7fff;
if ((quadcolor->crtc[10] & 0x60) == 0x20)
quadcolor->cursoron = 0;
else
quadcolor->cursoron = quadcolor->cgablink & 8;
}
if (quadcolor->vc == quadcolor->crtc[7]) {
quadcolor->cgadispon = 0;
quadcolor->displine = 0;
quadcolor->vsynctime = 16;
if (quadcolor->crtc[7]) {
if (quadcolor->cgamode & 1)
x = (quadcolor->crtc[1] << 3) + 16;
else
x = (quadcolor->crtc[1] << 4) + 16;
quadcolor->lastline++;
if (x != xsize || (quadcolor->lastline - quadcolor->firstline) != ysize) {
xsize = x;
ysize = quadcolor->lastline - quadcolor->firstline;
if (xsize < 64)
xsize = 656;
if (ysize < 32)
ysize = 200;
updatewindowsize(xsize, (ysize << 1) + 16);
}
video_blit_memtoscreen(0, quadcolor->firstline - 4, 0, (quadcolor->lastline - quadcolor->firstline) + 8,
xsize, (quadcolor->lastline - quadcolor->firstline) + 8);
frames++;
video_res_x = xsize - 16;
video_res_y = ysize;
if (quadcolor->cgamode & 1) {
video_res_x /= 8;
video_res_y /= quadcolor->crtc[9] + 1;
video_bpp = 0;
} else if (!(quadcolor->cgamode & 2)) {
video_res_x /= 16;
video_res_y /= quadcolor->crtc[9] + 1;
video_bpp = 0;
} else if (!(quadcolor->cgamode & 16)) {
video_res_x /= 2;
video_bpp = 2;
} else {
video_bpp = 1;
}
}
quadcolor->firstline = 1000;
quadcolor->lastline = 0;
quadcolor->cgablink++;
quadcolor->oddeven ^= 1;
}
} else {
quadcolor->sc++;
quadcolor->sc &= 31;
quadcolor->ma = quadcolor->maback;
}
if (quadcolor->cgadispon)
quadcolor->cgastat &= ~1;
if ((quadcolor->sc == (quadcolor->crtc[10] & 31) || ((quadcolor->crtc[8] & 3) == 3 && quadcolor->sc == ((quadcolor->crtc[10] & 31) >> 1))))
quadcolor->con = 1;
if (quadcolor->cgadispon && (quadcolor->cgamode & 1)) {
for (x = 0; x < (quadcolor->crtc[1] << 1); x++)
quadcolor->charbuffer[x] = quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->ma << 1) + x) & 0x7fff)];
}
}
}
void quadcolor_init(quadcolor_t *quadcolor) {
timer_add(&quadcolor->timer, quadcolor_poll, quadcolor, 1);
quadcolor->composite = 0;
}
void *quadcolor_standalone_init() {
int display_type, contrast;
quadcolor_t *quadcolor = malloc(sizeof(quadcolor_t));
memset(quadcolor, 0, sizeof(quadcolor_t));
display_type = device_get_config_int("display_type");
quadcolor->composite = (display_type == DISPLAY_COMPOSITE);
quadcolor->revision = device_get_config_int("composite_type");
quadcolor->has_2nd_charset = device_get_config_int("has_2nd_charset");
quadcolor->has_quadcolor_2 = device_get_config_int("has_quadcolor_2");
contrast = device_get_config_int("contrast");
quadcolor->vram = malloc(0x8000);
quadcolor->vram_2 = malloc(0x10000);
cga_comp_init(quadcolor->revision);
timer_add(&quadcolor->timer, quadcolor_poll, quadcolor, 1);
mem_mapping_add(&quadcolor->mapping, 0xb8000, 0x08000, quadcolor_read, NULL, NULL, quadcolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL,
quadcolor);
/* add mapping for vram_2 at 0xd0000, mirrored at 0xe0000 */
if (quadcolor->has_quadcolor_2)
mem_mapping_add(&quadcolor->mapping_2, 0xd0000, 0x20000, quadcolor_2_read, NULL, NULL, quadcolor_2_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL,
quadcolor);
io_sethandler(0x03d0, 0x0010, quadcolor_in, NULL, NULL, quadcolor_out, NULL, NULL, quadcolor);
cgapal_rebuild(display_type, contrast);
return quadcolor;
}
void quadcolor_close(void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
free(quadcolor->vram);
free(quadcolor->vram_2);
free(quadcolor);
}
void quadcolor_speed_changed(void *p) {
quadcolor_t *quadcolor = (quadcolor_t *)p;
quadcolor_recalctimings(quadcolor);
}
device_config_t quadcolor_config[] = {
{.name = "display_type",
.description = "Display type",
.type = CONFIG_SELECTION,
.selection = {{.description = "RGB", .value = DISPLAY_RGB},
{.description = "RGB (no brown)", .value = DISPLAY_RGB_NO_BROWN},
{.description = "Green Monochrome", .value = DISPLAY_GREEN},
{.description = "Amber Monochrome", .value = DISPLAY_AMBER},
{.description = "White Monochrome", .value = DISPLAY_WHITE},
{.description = "Composite", .value = DISPLAY_COMPOSITE},
{.description = ""}},
.default_int = DISPLAY_RGB},
{.name = "composite_type",
.description = "Composite type",
.type = CONFIG_SELECTION,
.selection = {{.description = "Old", .value = COMPOSITE_OLD},
{.description = "New", .value = COMPOSITE_NEW},
{.description = ""}},
.default_int = COMPOSITE_OLD},
{.name = "has_2nd_charset", .description = "Has secondary 8x8 character set", .type = CONFIG_BINARY, .default_int = 0},
{.name = "has_quadcolor_2", .description = "Has Quadcolor II daughter board", .type = CONFIG_BINARY, .default_int = 1},
{.name = "contrast", .description = "Alternate monochrome contrast", .type = CONFIG_BINARY, .default_int = 0},
{.type = -1}};
device_t quadcolor_device = {"Quadram Quadcolor I / I+II", 0, quadcolor_standalone_init, quadcolor_close, NULL, quadcolor_speed_changed, NULL, NULL, quadcolor_config};

View File

@@ -39,6 +39,7 @@
#include "vid_pcjr.h"
#include "vid_pgc.h"
#include "vid_ps1_svga.h"
#include "vid_quadcolor.h"
#include "vid_s3.h"
#include "vid_s3_virge.h"
#include "vid_sigma.h"
@@ -164,6 +165,9 @@ VIDEO_CARD v_px_trio64 = {"Phoenix S3 Trio64", "px_trio64",
VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}};
VIDEO_CARD v_plantronics = {"Plantronics ColorPlus", "plantronics", &colorplus_device,
GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}};
VIDEO_CARD v_quadcolor = {
"Quadram Quadcolor I / I+II", "quadcolor", &quadcolor_device, GFX_QUADCOLOR, VIDEO_FLAG_TYPE_CGA,
{VIDEO_ISA, 8, 16, 32, 8, 16, 32}};
VIDEO_CARD v_virge375 = {
"S3 ViRGE/DX", "virge375", &s3_virge_375_device, GFX_VIRGEDX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}};
VIDEO_CARD v_sigma400 = {"Sigma Color 400", "sigma400", &sigma_device,
@@ -929,18 +933,22 @@ void loadfont(char *s, fontformat_t format) {
}
switch (format) {
case FONT_MDA: /* MDA */
for (c = 0; c < 256; c++) {
for (c = 0; c < 256; c++) { /* 8x14 MDA in 8x8 cell (lines 0-7) */
for (d = 0; d < 8; d++) {
fontdatm[c][d] = getc(f);
}
}
for (c = 0; c < 256; c++) {
for (c = 0; c < 256; c++) { /* 8x14 MDA in 8x8 cell (lines 8-13 + padding lines) */
for (d = 0; d < 8; d++) {
fontdatm[c][d + 8] = getc(f);
}
}
fseek(f, 4096 + 2048, SEEK_SET);
for (c = 0; c < 256; c++) {
for (c = 0; c < 256; c++) { /* 8x8 CGA (thin, secondary, normally unused) */
for (d = 0; d < 8; d++) {
fontdat[c + 256][d] = getc(f);
}
}
for (c = 0; c < 256; c++) { /* 8x8 CGA (thick, primary) */
for (d = 0; d < 8; d++) {
fontdat[c][d] = getc(f);
}
@@ -1327,6 +1335,7 @@ void video_init_builtin() {
pcem_add_video(&v_px_trio32);
pcem_add_video(&v_px_trio64);
pcem_add_video(&v_plantronics);
pcem_add_video(&v_quadcolor);
pcem_add_video(&v_virge375);
pcem_add_video(&v_sigma400);
pcem_add_video(&v_tvga8900d);

View File

@@ -21,6 +21,7 @@ set(PCEM_PRIVATE_API ${PCEM_PRIVATE_API}
${CMAKE_SOURCE_DIR}/includes/private/video/vid_pcjr.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_pgc.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_ps1_svga.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_quadcolor.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_s3.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_s3_virge.h
${CMAKE_SOURCE_DIR}/includes/private/video/vid_sdac_ramdac.h
@@ -106,6 +107,7 @@ set(PCEM_SRC ${PCEM_SRC}
video/vid_pcjr.c
video/vid_pgc.c
video/vid_ps1_svga.c
video/vid_quadcolor.c
video/vid_s3.c
video/vid_s3_virge.c
video/vid_sdac_ramdac.c
@@ -136,4 +138,4 @@ set(PCEM_SRC ${PCEM_SRC}
video/vid_voodoo_texture.c
video/vid_wy700.c
video/video.c
)
)