Fixed a few things in the Sigma Color 400 driver.

This commit is contained in:
waltje
2019-05-08 19:41:57 -05:00
parent bffc6bf7fb
commit 3baba710bf

View File

@@ -17,6 +17,10 @@
* *
* <http://arvutimuuseum.ee/th99/v/S-T/52579.htm> * <http://arvutimuuseum.ee/th99/v/S-T/52579.htm>
* *
* The full-length card is the Color 400; the half-length card
* has a label saying 'Color 400S'. John has the 400S, Fred has
* the 400 (with the AT Enhancer daughterboard.)
*
* The card is CGA-compatible at BIOS level, but to improve * The card is CGA-compatible at BIOS level, but to improve
* compatibility attempts to write to the CGA I/O ports at * compatibility attempts to write to the CGA I/O ports at
* 0x3D0-0x3DF trigger an NMI. The card's BIOS handles the NMI * 0x3D0-0x3DF trigger an NMI. The card's BIOS handles the NMI
@@ -33,7 +37,9 @@
* configures itself to work or not as required. I've therefore * configures itself to work or not as required. I've therefore
* added a configuration option to handle this. * added a configuration option to handle this.
* *
* The card's real CRTC at 0x2D0/0x2D1 appears to be a 6845. * The card's CRTC at 0x2D0/0x2D1 is a real HD6845 on the long
* card, and integrated into the ASICs on the short card.
*
* One oddity is that all its horizontal counts are halved * One oddity is that all its horizontal counts are halved
* compared to what a real CGA uses; 40-column modes have a width * compared to what a real CGA uses; 40-column modes have a width
* of 20, and 80-column modes have a width of 40. This means that * of 20, and 80-column modes have a width of 40. This means that
@@ -41,7 +47,14 @@
* even-numbered columns, so the top bit of the control register * even-numbered columns, so the top bit of the control register
* at 0x2D9 is used to adjust the position. * at 0x2D9 is used to adjust the position.
* *
* Version: @(#)vid_sigma.c 1.0.9 2019/05/05 * **NOTE** This driver doesn't seem to play very nice on the DTK-XT
* machine. It works, but will beep a lot. This only happens if
* it is used in CGA emulation mode, so there might be something
* going on with the NMI stuff. If native mode is selected, all
* is well, but some strange mishaps with cursor positioning
* occur.
*
* Version: @(#)vid_sigma.c 1.0.10 2019/05/08
* *
* Authors: Fred N. van Kempen, <decwiz@yahoo.com> * Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com> * Miran Grca, <mgrca8@gmail.com>
@@ -88,8 +101,19 @@
#include "vid_cga.h" #include "vid_cga.h"
#define FONT_ROM_PATH L"video/sigma/sigma400_font.rom" #define ENABLE_CGA 1 /* set to 1 to enable CGA mode */
#define BIOS_ROM_PATH L"video/sigma/sigma400_bios.rom" #define SHORT_CARD 0 /* set to 1 to use the new ROMs */
#if SHORT_CARD
/* ROMs from the short card. */
# define FONT_ROM_PATH L"video/sigma/sigma400_font_2.52l.rom"
# define BIOS_ROM_PATH L"video/sigma/sigma400_bios_2.52l.rom"
#else
/* ROMs from the long card. */
# define FONT_ROM_PATH L"video/sigma/sigma400_font_2.49h.rom"
# define BIOS_ROM_PATH L"video/sigma/sigma400_bios_2.49h.rom"
#endif
/* 0x2D8: Mode register. Values written by the card BIOS are: /* 0x2D8: Mode register. Values written by the card BIOS are:
@@ -172,30 +196,29 @@ typedef struct {
rom_t bios_rom; rom_t bios_rom;
uint8_t crtc[32]; /* CRTC: Real values */ uint8_t crtc[32]; /* CRTC: real values */
int crtcreg; /* CRTC: Real selected register */
uint8_t lastport; /* Last I/O port written */ int8_t enable_nmi; /* enable NMI mechanism for CGA emulation */
uint8_t lastwrite; /* Value written to that port */ int8_t rom_paged; /* is ROM paged in at 0x0c1800? */
uint8_t sigma_ctl; /* Controls register:
* Bit 7 is low bit of cursor position uint8_t lastport; /* last I/O port written */
* Bit 5 set if writes to CGA ports trigger NMI uint8_t lastwrite; /* value written to that port */
* Bit 3 clears lightpen latch uint8_t sigma_ctl; /* controls register:
* Bit 2 sets lightpen latch * bit 7 is low bit of cursor position
* Bit 1 controls meaning of port 2DE * bit 5 set if writes to CGA ports trigger NMI
* bit 3 clears lightpen latch
* bit 2 sets lightpen latch
* bit 1 controls meaning of port 0x02de
*/ */
uint8_t enable_nmi; /* Enable the NMI mechanism for CGA emulation?*/ uint8_t crtc_value; /* value to return from a CRTC register read */
uint8_t rom_paged; /* Is ROM paged in at 0xC1800? */
uint8_t crtc_value; /* Value to return from a CRTC register read */ uint8_t sigma_stat; /* status register [0x02da] */
uint8_t sigmastat; /* Status register [0x2DA] */ uint8_t sigma_mode; /* mode control register [0x02d8] */
uint8_t sigmamode; /* Mode control register [0x2D8] */
uint16_t ma, maback; uint16_t ma, maback;
int crtcreg; /* CRTC: Real selected register */
int linepos, displine; int linepos, displine;
int sc, vc; int sc, vc;
int cgadispon; int cgadispon;
@@ -207,10 +230,7 @@ typedef struct {
int firstline, lastline; int firstline, lastline;
int drawcursor;
int plane; int plane;
int revision;
int64_t vidtime; int64_t vidtime;
@@ -238,7 +258,7 @@ recalc_timings(sigma_t *dev)
double disptime; double disptime;
double _dispontime, _dispofftime; double _dispontime, _dispofftime;
if (dev->sigmamode & MODE_80COLS) { if (dev->sigma_mode & MODE_80COLS) {
disptime = (dev->crtc[0] + 1) << 1; disptime = (dev->crtc[0] + 1) << 1;
_dispontime = (dev->crtc[1]) << 1; _dispontime = (dev->crtc[1]) << 1;
} else { } else {
@@ -261,70 +281,74 @@ sigma_out(uint16_t port, uint8_t val, void *priv)
sigma_t *dev = (sigma_t *)priv; sigma_t *dev = (sigma_t *)priv;
uint8_t old; uint8_t old;
if (port >= 0x3d0 && port < 0x3e0) { DBGLOG(1, "SIGMA: out(%04x, %02x)\n", port, val);
if (port >= 0x03d0 && port < 0x03e0) {
dev->lastport = port & 0x0f; dev->lastport = port & 0x0f;
dev->lastwrite = val; dev->lastwrite = val;
/* If set to NMI on video I/O... */ /* If set to NMI on video I/O... */
if (dev->enable_nmi && (dev->sigma_ctl & CTL_NMI)) { if (dev->enable_nmi && (dev->sigma_ctl & CTL_NMI)) {
dev->lastport |= 0x80; /* Card raised NMI */ dev->lastport |= 0x80; /* card raised NMI */
nmi = 1; nmi = 1;
} }
/* For CRTC emulation, the card BIOS sets the value to be /*
* read from port 0x3D1 like this */ * For CRTC emulation, the card BIOS sets the
if (port == 0x3d1) * value to be read from port 0x03d1 like this.
*/
if (port == 0x03d1)
dev->crtc_value = val; dev->crtc_value = val;
return; return;
} }
switch (port) { switch (port) {
case 0x2d0: case 0x02d0:
case 0x2d2: case 0x02d2:
case 0x2d4: case 0x02d4:
case 0x2d6: case 0x02d6:
dev->crtcreg = val & 31; dev->crtcreg = val & 0x1f;
break; break;
case 0x2d1: case 0x02d1:
case 0x2d3: case 0x02d3:
case 0x2d5: case 0x02d5:
case 0x2d7: case 0x02d7:
old = dev->crtc[dev->crtcreg]; old = dev->crtc[dev->crtcreg];
dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg];
if (old != val) { if (old != val) {
if (dev->crtcreg < 0xe || dev->crtcreg > 0x10) { if (dev->crtcreg < 0x0e || dev->crtcreg > 0x10) {
fullchange = changeframecount; fullchange = changeframecount;
recalc_timings(dev); recalc_timings(dev);
} }
} }
break; break;
case 0x2d8: case 0x02d8:
dev->sigmamode = val; dev->sigma_mode = val;
break; break;
case 0x2d9: case 0x02d9:
dev->sigma_ctl = val; dev->sigma_ctl = val;
break; break;
case 0x2db: case 0x02db:
dev->lastport &= 0x7F; dev->lastport &= 0x7f;
break; break;
case 0x2dc: /* Reset NMI */ case 0x02dc: /* reset NMI */
nmi = 0; nmi = 0;
dev->lastport &= 0x7F; dev->lastport &= 0x7f;
break; break;
case 0x2dd: /* Page in RAM at 0xC1800 */ case 0x02dd: /* page in RAM at 0x0c1800 */
if (dev->rom_paged != 0) if (dev->rom_paged)
mmu_invalidate(0xc0000); mmu_invalidate(0x0c0000);
dev->rom_paged = 0; dev->rom_paged = 0;
break; break;
case 0x2de: case 0x02de:
if (dev->sigma_ctl & CTL_PALETTE) if (dev->sigma_ctl & CTL_PALETTE)
dev->palette[val >> 4] = (val & 0x0f) ^ 0x0f; dev->palette[val >> 4] = (val & 0x0f) ^ 0x0f;
else else
@@ -341,43 +365,43 @@ sigma_in(uint16_t port, void *priv)
uint8_t ret = 0xff; uint8_t ret = 0xff;
switch (port) { switch (port) {
case 0x2d0: case 0x02d0:
case 0x2d2: case 0x02d2:
case 0x2d4: case 0x02d4:
case 0x2d6: case 0x02d6:
ret = dev->crtcreg; ret = dev->crtcreg;
break; break;
case 0x2d1: case 0x02d1:
case 0x2d3: case 0x02d3:
case 0x2d5: case 0x02d5:
case 0x2d7: case 0x02d7:
ret = dev->crtc[dev->crtcreg & 0x1f]; ret = dev->crtc[dev->crtcreg & 0x1f];
break; break;
case 0x2da: case 0x2da:
ret = (dev->sigma_ctl & 0xe0) | (dev->sigmastat & 0x1f); ret = (dev->sigma_ctl & 0xe0) | (dev->sigma_stat & 0x1f);
break; break;
case 0x2db: case 0x2db: /* return value that triggered NMI */
ret = dev->lastwrite; /* Value that triggered NMI */ ret = dev->lastwrite;
break; break;
case 0x2dc: case 0x2dc: /* port that triggered NMI */
ret = dev->lastport; /* Port that triggered NMI */ ret = dev->lastport;
break; break;
case 0x2dd: /* Page in ROM at 0xC1800 */ case 0x2dd: /* page in ROM at 0x0c1800 */
ret = (dev->rom_paged ? 0x80 : 0); ret = (dev->rom_paged ? 0x80 : 0);
if (dev->rom_paged != 0x80) if (dev->rom_paged)
mmu_invalidate(0xc0000); mmu_invalidate(0x0c0000);
dev->rom_paged = 0x80; dev->rom_paged = 1;
break; break;
case 0x3d1: case 0x03d1:
case 0x3d3: case 0x03d3:
case 0x3d5: case 0x03d5:
case 0x3d7: case 0x03d7:
ret = dev->crtc_value; ret = dev->crtc_value;
break; break;
@@ -386,13 +410,16 @@ sigma_in(uint16_t port, void *priv)
* on this port. On a real card this functionality can be turned * on this port. On a real card this functionality can be turned
* on or off with SW1/6. * on or off with SW1/6.
*/ */
case 0x3da: case 0x03da:
ret = dev->sigmastat & 7; ret = dev->sigma_stat & 0x07;
if (dev->sigmastat & STATUS_RETR_V) ret |= 8; if (dev->sigma_stat & STATUS_RETR_V)
ret |= 0x08;
break; break;
} }
return ret; DBGLOG(1, "SIGMA: in(%04x) = %02x\n", port, ret);
return(ret);
} }
@@ -414,46 +441,46 @@ sigma_read(uint32_t addr, void *priv)
cycles -= 4; cycles -= 4;
return dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)]; return(dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)]);
} }
/* Write to the RAM part of the 8K ROM/RAM area. */
static void static void
sigma_bwrite(uint32_t addr, uint8_t val, void *priv) sigma_bwrite(uint32_t addr, uint8_t val, void *priv)
{ {
sigma_t *dev = (sigma_t *)priv; sigma_t *dev = (sigma_t *)priv;
addr &= 0x3fff; addr &= 0x3fff;
#if 0 if ((addr >= 0x1800) && (addr < 0x2000) && !dev->rom_paged)
if ((addr >= 0x1800) && !dev->rom_paged && (addr < 0x2000)) dev->bram[addr & 0x07ff] = val;
#endif
if ((addr < 0x1800) || dev->rom_paged || (addr >= 0x2000))
;
else
dev->bram[addr & 0x7ff] = val;
} }
/* Read from the 8K ROM/RAM area. */
static uint8_t static uint8_t
sigma_bread(uint32_t addr, void *priv) sigma_bread(uint32_t addr, void *priv)
{ {
sigma_t *dev = (sigma_t *)priv; sigma_t *dev = (sigma_t *)priv;
uint8_t ret; uint8_t ret = 0xff;
/* If address higher than 8K, no go. */
addr &= 0x3fff; addr &= 0x3fff;
if (addr >= 0x2000) if (addr < 0x2000) {
return 0xff; if (addr < 0x1800 || dev->rom_paged) {
/* Read from the ROM. */
ret = dev->bios_rom.rom[addr];
} else {
/* Read from the RAM. */
ret = dev->bram[addr & 0x07ff];
}
}
if (addr < 0x1800 || dev->rom_paged) return(ret);
ret = dev->bios_rom.rom[addr & 0x1fff];
else
ret = dev->bram[addr & 0x7ff];
return ret;
} }
/* Render a line in 80-column text mode */ /* Render a line in 80-column text mode. */
static void static void
sigma_text80(sigma_t *dev) sigma_text80(sigma_t *dev)
{ {
@@ -469,52 +496,56 @@ sigma_text80(sigma_t *dev)
ca++; ca++;
ca &= 0x3fff; ca &= 0x3fff;
/* The Sigma 400 seems to use screen widths stated in words /*
(40 for 80-column, 20 for 40-column) */ * The Sigma 400 seems to use screen widths stated
* in words (40 for 80-column, 20 for 40-column.)
*/
for (x = 0; x < (dev->crtc[1] << 1); x++) { for (x = 0; x < (dev->crtc[1] << 1); x++) {
chr = vram[x << 1]; chr = vram[x << 1];
attr = vram[(x << 1) + 1]; attr = vram[(x << 1) + 1];
drawcursor = ((ma == ca) && dev->con && dev->cursoron); drawcursor = ((ma == ca) && dev->con && dev->cursoron);
if (! (dev->sigmamode & MODE_NOBLINK)) { if (! (dev->sigma_mode & MODE_NOBLINK)) {
cols[1] = (attr & 15) | 16; cols[1] = (attr & 15) | 16;
cols[0] = ((attr >> 4) & 7) | 16; cols[0] = ((attr >> 4) & 7) | 16;
if ((dev->cgablink & 8) && (attr & 0x80) && !dev->drawcursor) if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor)
cols[1] = cols[0]; cols[1] = cols[0];
} else { /* No blink */ } else {
/* No blink. */
cols[1] = (attr & 15) | 16; cols[1] = (attr & 15) | 16;
cols[0] = (attr >> 4) | 16; cols[0] = (attr >> 4) | 16;
} }
if (drawcursor) { if (drawcursor) {
for (c = 0; c < 8; c++) { for (c = 0; c < 8; c++) {
if (dev->sigmamode & MODE_FONT16) if (dev->sigma_mode & MODE_FONT16)
screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f;
else else
screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat[chr][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat[chr][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f;
} }
} else { } else {
for (c = 0; c < 8; c++) { for (c = 0; c < 8; c++) {
if (dev->sigmamode & MODE_FONT16) if (dev->sigma_mode & MODE_FONT16)
screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
else else
screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat[chr][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; screen->line[dev->displine][(x << 3) + c + 8].pal = cols[(dev->fontdat[chr][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0];
} }
} }
++ma;
ma++;
} }
dev->ma += dev->crtc[1]; dev->ma += dev->crtc[1];
} }
/* Render a line in 40-column text mode */ /* Render a line in 40-column text mode. */
static void static void
sigma_text40(sigma_t *dev) sigma_text40(sigma_t *dev)
{ {
uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)); uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8));
uint16_t ma = ((dev->ma & 0x3FFF) << 1); uint16_t ma = ((dev->ma & 0x3fff) << 1);
uint8_t *vram = dev->vram + ((ma << 1) & 0x3FFF); uint8_t *vram = dev->vram + ((ma << 1) & 0x3fff);
int drawcursor, x, c; int drawcursor, x, c;
uint8_t chr, attr; uint8_t chr, attr;
uint8_t cols[4]; uint8_t cols[4];
@@ -524,19 +555,22 @@ sigma_text40(sigma_t *dev)
++ca; ++ca;
ca &= 0x3fff; ca &= 0x3fff;
/* The Sigma 400 seems to use screen widths stated in words /*
(40 for 80-column, 20 for 40-column) */ * The Sigma 400 seems to use screen widths stated
* in words (40 for 80-column, 20 for 40-column.)
*/
for (x = 0; x < (dev->crtc[1] << 1); x++) { for (x = 0; x < (dev->crtc[1] << 1); x++) {
chr = vram[x << 1]; chr = vram[x << 1];
attr = vram[(x << 1) + 1]; attr = vram[(x << 1) + 1];
drawcursor = ((ma == ca) && dev->con && dev->cursoron); drawcursor = ((ma == ca) && dev->con && dev->cursoron);
if (!(dev->sigmamode & MODE_NOBLINK)) { if (!(dev->sigma_mode & MODE_NOBLINK)) {
cols[1] = (attr & 15) | 16; cols[1] = (attr & 15) | 16;
cols[0] = ((attr >> 4) & 7) | 16; cols[0] = ((attr >> 4) & 7) | 16;
if ((dev->cgablink & 8) && (attr & 0x80) && !dev->drawcursor) if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor)
cols[1] = cols[0]; cols[1] = cols[0];
} else { /* No blink */ } else {
/* No blink. */
cols[1] = (attr & 15) | 16; cols[1] = (attr & 15) | 16;
cols[0] = (attr >> 4) | 16; cols[0] = (attr >> 4) | 16;
} }
@@ -550,6 +584,7 @@ sigma_text40(sigma_t *dev)
screen->line[dev->displine][(x << 4) + 2*c + 8].pal = screen->line[dev->displine][(x << 4) + 2*c + 9].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; screen->line[dev->displine][(x << 4) + 2*c + 8].pal = screen->line[dev->displine][(x << 4) + 2*c + 9].pal = cols[(dev->fontdat16[chr][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0];
} }
} }
ma++; ma++;
} }
@@ -557,15 +592,17 @@ sigma_text40(sigma_t *dev)
} }
/* Draw a line in the 640x400 graphics mode */ /* Draw a line in the 640x400 graphics mode. */
static void static void
sigma_gfx400(sigma_t *dev) sigma_gfx400(sigma_t *dev)
{ {
uint8_t *vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 3) * 0x2000];
uint8_t mask, col, c; uint8_t mask, col, c;
uint8_t plane[4]; uint8_t plane[4];
uint8_t *vram;
int x; int x;
vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 3) * 0x2000];
for (x = 0; x < (dev->crtc[1] << 1); x++) { for (x = 0; x < (dev->crtc[1] << 1); x++) {
plane[0] = vram[x]; plane[0] = vram[x];
plane[1] = vram[0x8000 + x]; plane[1] = vram[0x8000 + x];
@@ -578,27 +615,35 @@ sigma_gfx400(sigma_t *dev)
((plane[1] & mask) ? 2 : 0) | ((plane[1] & mask) ? 2 : 0) |
((plane[0] & mask) ? 1 : 0); ((plane[0] & mask) ? 1 : 0);
col |= 16; col |= 16;
screen->line[dev->displine][(x << 3) + c + 8].pal = col; screen->line[dev->displine][(x << 3) + c + 8].pal = col;
} }
if (x & 1) dev->ma++; if (x & 1)
dev->ma++;
} }
} }
/* Draw a line in the 640x200 graphics mode. /*
* This is actually a 640x200x16 mode; on startup, the BIOS selects plane 2, * Draw a line in the 640x200 graphics mode.
* blanks the other planes, and sets palette ink 4 to white. Pixels plotted *
* in plane 2 come out in white, others black; but by programming the palette * This is actually a 640x200x16 mode; on startup, the BIOS
* and plane registers manually you can get the full resolution. */ * selects plane 2, blanks the other planes, and sets palette
* ink 4 to white. Pixels plotted in plane 2 come out in white,
* others black; but by programming the palette and plane
* registers manually you can get the full resolution.
*/
static void static void
sigma_gfx200(sigma_t *dev) sigma_gfx200(sigma_t *dev)
{ {
uint8_t *vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 2) * 0x1000];
uint8_t mask, col, c; uint8_t mask, col, c;
uint8_t plane[4]; uint8_t plane[4];
uint8_t *vram;
int x; int x;
vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 2) * 0x1000];
for (x = 0; x < (dev->crtc[1] << 1); x++) { for (x = 0; x < (dev->crtc[1] << 1); x++) {
plane[0] = vram[x]; plane[0] = vram[x];
plane[1] = vram[0x8000 + x]; plane[1] = vram[0x8000 + x];
@@ -611,23 +656,27 @@ sigma_gfx200(sigma_t *dev)
((plane[1] & mask) ? 2 : 0) | ((plane[1] & mask) ? 2 : 0) |
((plane[0] & mask) ? 1 : 0); ((plane[0] & mask) ? 1 : 0);
col |= 16; col |= 16;
screen->line[dev->displine][(x << 3) + c + 8].pal = col; screen->line[dev->displine][(x << 3) + c + 8].pal = col;
} }
if (x & 1) dev->ma++; if (x & 1)
dev->ma++;
} }
} }
/* Draw a line in the 320x200 graphics mode */ /* Draw a line in the 320x200 graphics mode. */
static void static void
sigma_gfx4col(sigma_t *dev) sigma_gfx4col(sigma_t *dev)
{ {
uint8_t *vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 2) * 0x1000];
uint8_t mask, col, c; uint8_t mask, col, c;
uint8_t plane[4]; uint8_t plane[4];
uint8_t *vram;
int x; int x;
vram = &dev->vram[((dev->ma << 1) & 0x1fff) + (dev->sc & 2) * 0x1000];
for (x = 0; x < (dev->crtc[1] << 1); x++) { for (x = 0; x < (dev->crtc[1] << 1); x++) {
plane[0] = vram[x]; plane[0] = vram[x];
plane[1] = vram[0x8000 + x]; plane[1] = vram[0x8000 + x];
@@ -647,7 +696,8 @@ sigma_gfx4col(sigma_t *dev)
screen->line[dev->displine][(x << 3) + (c << 1) + 8].pal = screen->line[dev->displine][(x << 3) + (c << 1) + 9].pal = col; screen->line[dev->displine][(x << 3) + (c << 1) + 8].pal = screen->line[dev->displine][(x << 3) + (c << 1) + 9].pal = col;
} }
if (x & 1) dev->ma++; if (x & 1)
dev->ma++;
} }
} }
@@ -662,11 +712,13 @@ sigma_poll(void *priv)
if (! dev->linepos) { if (! dev->linepos) {
dev->vidtime += dev->dispofftime; dev->vidtime += dev->dispofftime;
dev->sigmastat |= STATUS_RETR_H; dev->sigma_stat |= STATUS_RETR_H;
dev->linepos = 1; dev->linepos = 1;
oldsc = dev->sc; oldsc = dev->sc;
if ((dev->crtc[8] & 3) == 3) if ((dev->crtc[8] & 3) == 3)
dev->sc = ((dev->sc << 1) + dev->oddeven) & 7; dev->sc = ((dev->sc << 1) + dev->oddeven) & 7;
if (dev->cgadispon) { if (dev->cgadispon) {
if (dev->displine < dev->firstline) { if (dev->displine < dev->firstline) {
dev->firstline = dev->displine; dev->firstline = dev->displine;
@@ -676,37 +728,38 @@ sigma_poll(void *priv)
cols[0] = 16; cols[0] = 16;
/* Left overscan */ /* Left overscan. */
for (c = 0; c < 8; c++) { for (c = 0; c < 8; c++) {
screen->line[dev->displine][c].pal = cols[0]; screen->line[dev->displine][c].pal = cols[0];
if (dev->sigmamode & MODE_80COLS) if (dev->sigma_mode & MODE_80COLS)
screen->line[dev->displine][c + (dev->crtc[1] << 4) + 8].pal = cols[0]; screen->line[dev->displine][c + (dev->crtc[1] << 4) + 8].pal = cols[0];
else else
screen->line[dev->displine][c + (dev->crtc[1] << 5) + 8].pal = cols[0]; screen->line[dev->displine][c + (dev->crtc[1] << 5) + 8].pal = cols[0];
} }
if (dev->sigmamode & MODE_GRAPHICS) { if (dev->sigma_mode & MODE_GRAPHICS) {
if (dev->sigmamode & MODE_640x400) if (dev->sigma_mode & MODE_640x400)
sigma_gfx400(dev); sigma_gfx400(dev);
else if (dev->sigmamode & MODE_HRGFX) else if (dev->sigma_mode & MODE_HRGFX)
sigma_gfx200(dev); sigma_gfx200(dev);
else else
sigma_gfx4col(dev); sigma_gfx4col(dev);
} else { /* Text modes */ } else {
if (dev->sigmamode & MODE_80COLS) /* Text modes. */
if (dev->sigma_mode & MODE_80COLS)
sigma_text80(dev); sigma_text80(dev);
else else
sigma_text40(dev); sigma_text40(dev);
} }
} else { } else {
cols[0] = 16; cols[0] = 16;
if (dev->sigmamode & MODE_80COLS) if (dev->sigma_mode & MODE_80COLS)
cga_hline(screen, 0, dev->displine, (dev->crtc[1] << 4) + 16, cols[0]); cga_hline(screen, 0, dev->displine, (dev->crtc[1] << 4) + 16, cols[0]);
else else
cga_hline(screen, 0, dev->displine, (dev->crtc[1] << 5) + 16, cols[0]); cga_hline(screen, 0, dev->displine, (dev->crtc[1] << 5) + 16, cols[0]);
} }
if (dev->sigmamode & MODE_80COLS) if (dev->sigma_mode & MODE_80COLS)
x = (dev->crtc[1] << 4) + 16; x = (dev->crtc[1] << 4) + 16;
else else
x = (dev->crtc[1] << 5) + 16; x = (dev->crtc[1] << 5) + 16;
@@ -716,31 +769,36 @@ sigma_poll(void *priv)
dev->sc = oldsc; dev->sc = oldsc;
if (dev->vc == dev->crtc[7] && !dev->sc) if (dev->vc == dev->crtc[7] && !dev->sc)
dev->sigmastat |= STATUS_RETR_V; dev->sigma_stat |= STATUS_RETR_V;
dev->displine++; dev->displine++;
if (dev->displine >= 560) if (dev->displine >= 560)
dev->displine = 0; dev->displine = 0;
} else { } else {
dev->vidtime += dev->dispontime; dev->vidtime += dev->dispontime;
dev->linepos = 0; dev->linepos = 0;
if (dev->vsynctime) { if (dev->vsynctime) {
dev->vsynctime--; dev->vsynctime--;
if (!dev->vsynctime) if (! dev->vsynctime)
dev->sigmastat &= ~STATUS_RETR_V; dev->sigma_stat &= ~STATUS_RETR_V;
} }
if (dev->sc == (dev->crtc[11] & 31) || if (dev->sc == (dev->crtc[11] & 31) ||
((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) {
dev->con = 0; dev->con = 0;
dev->coff = 1; dev->coff = 1;
} }
if ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1)) if ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))
dev->maback = dev->ma; dev->maback = dev->ma;
if (dev->vadj) { if (dev->vadj) {
dev->sc++; dev->sc++;
dev->sc &= 31; dev->sc &= 31;
dev->ma = dev->maback; dev->ma = dev->maback;
dev->vadj--; dev->vadj--;
if (!dev->vadj) { if (! dev->vadj) {
dev->cgadispon = 1; dev->cgadispon = 1;
dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff;
dev->sc = 0; dev->sc = 0;
@@ -758,8 +816,11 @@ sigma_poll(void *priv)
if (oldvc == dev->crtc[4]) { if (oldvc == dev->crtc[4]) {
dev->vc = 0; dev->vc = 0;
dev->vadj = dev->crtc[5]; dev->vadj = dev->crtc[5];
if (!dev->vadj) dev->cgadispon = 1; if (! dev->vadj)
if (!dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; dev->cgadispon = 1;
if (! dev->vadj)
dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff;
if ((dev->crtc[10] & 0x60) == 0x20) if ((dev->crtc[10] & 0x60) == 0x20)
dev->cursoron = 0; dev->cursoron = 0;
else else
@@ -770,8 +831,9 @@ sigma_poll(void *priv)
dev->cgadispon = 0; dev->cgadispon = 0;
dev->displine = 0; dev->displine = 0;
dev->vsynctime = 16; dev->vsynctime = 16;
if (dev->crtc[7]) { if (dev->crtc[7]) {
if (dev->sigmamode & MODE_80COLS) if (dev->sigma_mode & MODE_80COLS)
x = (dev->crtc[1] << 4) + 16; x = (dev->crtc[1] << 4) + 16;
else else
x = (dev->crtc[1] << 5) + 16; x = (dev->crtc[1] << 5) + 16;
@@ -799,20 +861,20 @@ sigma_poll(void *priv)
video_res_x = xsize - 16; video_res_x = xsize - 16;
video_res_y = ysize; video_res_y = ysize;
if (dev->sigmamode & MODE_GRAPHICS) { if (dev->sigma_mode & MODE_GRAPHICS) {
if (dev->sigmamode & (MODE_HRGFX | MODE_640x400)) if (dev->sigma_mode & (MODE_HRGFX | MODE_640x400))
video_bpp = 1; video_bpp = 1;
else { else {
video_res_x /= 2; video_res_x /= 2;
video_bpp = 2; video_bpp = 2;
} }
} else if (dev->sigmamode & MODE_80COLS) { } else if (dev->sigma_mode & MODE_80COLS) {
/* 80-column text */ /* 80-column text. */
video_res_x /= 8; video_res_x /= 8;
video_res_y /= dev->crtc[9] + 1; video_res_y /= dev->crtc[9] + 1;
video_bpp = 0; video_bpp = 0;
} else { } else {
/* 40-column text */ /* 40-column text. */
video_res_x /= 16; video_res_x /= 16;
video_res_y /= dev->crtc[9] + 1; video_res_y /= dev->crtc[9] + 1;
video_bpp = 0; video_bpp = 0;
@@ -828,8 +890,10 @@ sigma_poll(void *priv)
dev->sc &= 31; dev->sc &= 31;
dev->ma = dev->maback; dev->ma = dev->maback;
} }
if (dev->cgadispon) if (dev->cgadispon)
dev->sigmastat &= ~STATUS_RETR_H; dev->sigma_stat &= ~STATUS_RETR_H;
if ((dev->sc == (dev->crtc[10] & 31) || if ((dev->sc == (dev->crtc[10] & 31) ||
((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))))
dev->con = 1; dev->con = 1;
@@ -838,14 +902,14 @@ sigma_poll(void *priv)
static int static int
load_font(sigma_t *dev, const wchar_t *s) load_font(sigma_t *dev, const wchar_t *fn)
{ {
FILE *fp; FILE *fp;
int c; int c;
fp = rom_fopen(s, L"rb"); fp = rom_fopen(fn, L"rb");
if (fp == NULL) { if (fp == NULL) {
ERRLOG("%s: cannot load font '%ls'\n", dev->name, s); ERRLOG("%s: cannot load font '%ls'\n", dev->name, fn);
return(0); return(0);
} }
@@ -865,6 +929,26 @@ load_font(sigma_t *dev, const wchar_t *s)
} }
static void
sigma_close(void *priv)
{
sigma_t *dev = (sigma_t *)priv;
free(dev->vram);
free(dev);
}
static void
speed_changed(void *priv)
{
sigma_t *dev = (sigma_t *)priv;
recalc_timings(dev);
}
static void * static void *
sigma_init(const device_t *info, UNUSED(void *parent)) sigma_init(const device_t *info, UNUSED(void *parent))
{ {
@@ -886,7 +970,8 @@ sigma_init(const device_t *info, UNUSED(void *parent))
cga_palette = 0; cga_palette = 0;
video_palette_rebuild(); video_palette_rebuild();
dev->vram = malloc(0x8000 * 4); /* Allocate 128KB video memory. */
dev->vram = (uint8_t *)mem_alloc(131072);
mem_map_add(&dev->mapping, 0xb8000, 0x08000, mem_map_add(&dev->mapping, 0xb8000, 0x08000,
sigma_read,NULL,NULL, sigma_write,NULL,NULL, sigma_read,NULL,NULL, sigma_write,NULL,NULL,
@@ -902,7 +987,7 @@ sigma_init(const device_t *info, UNUSED(void *parent))
mem_map_disable(&dev->bios_rom.mapping); mem_map_disable(&dev->bios_rom.mapping);
memcpy(dev->bram, &dev->bios_rom.rom[0x1800], 0x0800); memcpy(dev->bram, &dev->bios_rom.rom[0x1800], 0x0800);
mem_map_add(&dev->bios_ram, 0xc1800, 0x0800, mem_map_add(&dev->bios_ram, 0xc0000, 0x2000,
sigma_bread,NULL,NULL, sigma_bwrite,NULL,NULL, sigma_bread,NULL,NULL, sigma_bwrite,NULL,NULL,
dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, dev); dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, dev);
@@ -914,38 +999,17 @@ sigma_init(const device_t *info, UNUSED(void *parent))
timer_add(sigma_poll, dev, &dev->vidtime, TIMER_ALWAYS_ENABLED); timer_add(sigma_poll, dev, &dev->vidtime, TIMER_ALWAYS_ENABLED);
/* Start with ROM paged in, BIOS RAM paged out */ /* Start with ROM paged in, BIOS RAM paged out */
dev->rom_paged = 0x80; dev->rom_paged = 1;
if (dev->enable_nmi) if (dev->enable_nmi)
dev->sigmastat = STATUS_LPEN_T; dev->sigma_stat = STATUS_LPEN_T;
video_inform(DEVICE_VIDEO_GET(info->flags), video_inform(DEVICE_VIDEO_GET(info->flags), &sigma_timing);
(const video_timings_t *)&sigma_timing);
return(dev); return(dev);
} }
static void
sigma_close(void *priv)
{
sigma_t *dev = (sigma_t *)priv;
free(dev->vram);
free(dev);
}
void
speed_changed(void *priv)
{
sigma_t *dev = (sigma_t *)priv;
recalc_timings(dev);
}
static int static int
sigma_available(void) sigma_available(void)
{ {
@@ -988,7 +1052,11 @@ static const device_config_t sigma_config[] = {
const device_t sigma_device = { const device_t sigma_device = {
"Sigma Color 400", "Sigma Color 400",
#if ENABLE_CGA
DEVICE_VIDEO(VID_TYPE_CGA) | DEVICE_ISA, DEVICE_VIDEO(VID_TYPE_CGA) | DEVICE_ISA,
#else
DEVICE_VIDEO(VID_TYPE_SPEC) | DEVICE_ISA,
#endif
0, 0,
BIOS_ROM_PATH, BIOS_ROM_PATH,
sigma_init, sigma_close, NULL, sigma_init, sigma_close, NULL,