Improved the BusLogic incoming mailbox code; The BusLogic callback is now three-phases and outgoing mailbox interrupts are emulated correctly; Fixed the CD-ROM command READ DISC INFORMATION (0x51), fixes NetBSD crashing 86Box with segmentation fault when using the AHA-154x; Added the CD-ROM command PAUSE/RESUME ALT (0xC2).
1113 lines
28 KiB
C
1113 lines
28 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "ibm.h"
|
|
#include "device.h"
|
|
#include "io.h"
|
|
#include "mem.h"
|
|
#include "rom.h"
|
|
#include "video.h"
|
|
#include "vid_svga.h"
|
|
#include "vid_svga_render.h"
|
|
#include "vid_cl_ramdac.h"
|
|
#include "vid_cl_gd.h"
|
|
#include "vid_cl_gd_blit.h"
|
|
|
|
void cirrus_update_bank_ptr(clgd_t *clgd, uint8_t bank_index);
|
|
void clgd_recalctimings(svga_t *svga);
|
|
|
|
void svga_write_cirrus(uint32_t addr, uint8_t val, void *p);
|
|
void svga_write_cirrus_linear(uint32_t addr, uint8_t val, void *p);
|
|
void svga_write_cirrus_linear_bitblt(uint32_t addr, uint8_t val, void *p);
|
|
uint8_t svga_read_cirrus(uint32_t addr, void *p);
|
|
uint8_t svga_read_cirrus_linear(uint32_t addr, void *p);
|
|
uint8_t svga_read_cirrus_linear_bitblt(uint32_t addr, void *p);
|
|
|
|
void clgd_out(uint16_t addr, uint8_t val, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
uint8_t old;
|
|
|
|
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
|
|
addr ^= 0x60;
|
|
|
|
// pclog("clgd out %04X %02X\n", addr, val);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x3c4:
|
|
svga->seqaddr = val;
|
|
break;
|
|
case 0x3c5:
|
|
if (svga->seqaddr > 5)
|
|
{
|
|
old = svga->seqregs[svga->seqaddr & 0x1f];
|
|
switch (svga->seqaddr & 0x1f)
|
|
{
|
|
case 0x06:
|
|
val &= 0x17;
|
|
if (val == 0x12)
|
|
{
|
|
svga->seqregs[svga->seqaddr & 0x1f] = 0x12;
|
|
}
|
|
else
|
|
{
|
|
svga->seqregs[svga->seqaddr & 0x1f] = 0xf;
|
|
}
|
|
break;
|
|
|
|
case 0x10: case 0x30: case 0x50: case 0x70:
|
|
case 0x90: case 0xb0: case 0xd0: case 0xf0:
|
|
svga->seqregs[0x10] = val;
|
|
svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5);
|
|
// pclog("svga->hwcursor.x = %i\n", svga->hwcursor.x);
|
|
break;
|
|
|
|
case 0x11: case 0x31: case 0x51: case 0x71:
|
|
case 0x91: case 0xb1: case 0xd1: case 0xf1:
|
|
svga->seqregs[0x11] = val;
|
|
svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5);
|
|
// pclog("svga->hwcursor.y = %i\n", svga->hwcursor.y);
|
|
break;
|
|
|
|
case 0x07:
|
|
cirrus_update_memory_access(clgd);
|
|
clgd_recalctimings(svga);
|
|
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
|
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
|
|
case 0x14: case 0x15: case 0x16:
|
|
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
|
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
|
svga->seqregs[svga->seqaddr & 0x1f] = val;
|
|
break;
|
|
|
|
case 0x13:
|
|
svga->seqregs[svga->seqaddr & 0x1f] = val;
|
|
svga->hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256);
|
|
// pclog("svga->hwcursor.addr = %x\n", svga->hwcursor.addr);
|
|
break;
|
|
|
|
case 0x12:
|
|
svga->seqregs[svga->seqaddr & 0x1f] = val;
|
|
svga->hwcursor.ena = val & 1;
|
|
// pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena);
|
|
break;
|
|
|
|
case 0x17:
|
|
old = svga->seqregs[svga->seqaddr & 0x1f];
|
|
svga->seqregs[svga->seqaddr & 0x1f] = (svga->seqregs[svga->seqaddr & 0x1f] & 0x38) | (val & 0xc7);
|
|
cirrus_update_memory_access(clgd);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9:
|
|
// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc);
|
|
cl_ramdac_out(addr, val, &clgd->ramdac, clgd, svga);
|
|
return;
|
|
|
|
case 0x3cf:
|
|
if (svga->gdcaddr == 5)
|
|
{
|
|
svga->gdcreg[5] = val & 0x7f;
|
|
if (svga->gdcreg[0xb] & 0x04)
|
|
svga->writemode = svga->gdcreg[5] & 7;
|
|
else
|
|
svga->writemode = svga->gdcreg[5] & 3;
|
|
cirrus_update_memory_access(clgd);
|
|
svga_out(addr, val, svga);
|
|
return;
|
|
}
|
|
if (svga->gdcaddr == 6)
|
|
{
|
|
if ((svga->gdcreg[6] & 0xc) != (val & 0xc))
|
|
{
|
|
svga->gdcreg[6] = val;
|
|
cirrus_update_memory_access(clgd);
|
|
}
|
|
svga->gdcreg[6] = val;
|
|
return;
|
|
}
|
|
if (svga->gdcaddr > 8)
|
|
{
|
|
switch (svga->gdcaddr)
|
|
{
|
|
case 0x09: case 0x0A: case 0x0B:
|
|
svga->gdcreg[svga->gdcaddr & 0x3f] = val;
|
|
cirrus_update_bank_ptr(clgd, 0);
|
|
cirrus_update_bank_ptr(clgd, 1);
|
|
if (svga->gdcreg[0xb] & 0x04)
|
|
svga->writemode = svga->gdcreg[5] & 7;
|
|
else
|
|
svga->writemode = svga->gdcreg[5] & 3;
|
|
cirrus_update_memory_access(clgd);
|
|
break;
|
|
|
|
case 0x21: case 0x23: case 0x25: case 0x27:
|
|
svga->gdcreg[svga->gdcaddr & 0x3f] = val & 0x1f;
|
|
break;
|
|
|
|
case 0x2a:
|
|
svga->gdcreg[svga->gdcaddr & 0x3f] = val & 0x3f;
|
|
/* if auto start mode, starts bit blt now */
|
|
if (svga->gdcreg[0x31] & CIRRUS_BLT_AUTOSTART) cirrus_bitblt_start(clgd, svga);
|
|
break;
|
|
|
|
case 0x2e:
|
|
svga->gdcreg[svga->gdcaddr & 0x3f] = val & 0x3f;
|
|
break;
|
|
|
|
case 0x31:
|
|
cirrus_write_bitblt(clgd, svga, val);
|
|
break;
|
|
|
|
default:
|
|
svga->gdcreg[svga->gdcaddr & 0x3f] = val;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 0x3D4:
|
|
svga->crtcreg = val & 0x3f;
|
|
return;
|
|
case 0x3D5:
|
|
if (svga->crtcreg <= 0x18)
|
|
val &= mask_crtc[svga->crtcreg];
|
|
if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80))
|
|
return;
|
|
if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80))
|
|
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
|
|
old = svga->crtc[svga->crtcreg];
|
|
if ((svga->crtcreg != 0x22) && (svga->crtcreg != 0x24) && (svga->crtcreg != 0x26) && (svga->crtcreg != 0x27)) svga->crtc[svga->crtcreg] = val;
|
|
if ((svga->crtcreg == 0x22) || (svga->crtcreg == 0x24) || (svga->crtcreg == 0x26) || (svga->crtcreg == 0x27)) return;
|
|
|
|
if (old != val)
|
|
{
|
|
if (svga->crtcreg == 0x1b)
|
|
{
|
|
svga->vrammask = (val & 2) ? (clgd->vram_size - 1) : 0x3ffff;
|
|
clgd->linear_mmio_mask = (val & 2) ? (clgd->vram_size - 256) : (0x40000 - 256);
|
|
}
|
|
if (svga->crtcreg < 0xe || svga->crtcreg > 0x10)
|
|
{
|
|
svga->fullchange = changeframecount;
|
|
svga_recalctimings(svga);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
svga_out(addr, val, svga);
|
|
}
|
|
|
|
uint8_t clgd_in(uint16_t addr, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
if ((((addr & 0xfff0) == 0x3d0) || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1))
|
|
addr ^= 0x60;
|
|
|
|
// if (addr != 0x3da) pclog("IN clgd %04X\n", addr);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x3c5:
|
|
if (svga->seqaddr > 5)
|
|
{
|
|
switch (svga->seqaddr)
|
|
{
|
|
case 0x06:
|
|
return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f;
|
|
|
|
case 0x10: case 0x30: case 0x50: case 0x70:
|
|
case 0x90: case 0xb0: case 0xd0: case 0xf0:
|
|
return svga->seqregs[0x10];
|
|
|
|
case 0x11: case 0x31: case 0x51: case 0x71:
|
|
case 0x91: case 0xb1: case 0xd1: case 0xf1:
|
|
return svga->seqregs[0x11];
|
|
|
|
case 0x15:
|
|
return clgd->vram_code;
|
|
|
|
case 0x05: case 0x07: case 0x08: case 0x09:
|
|
case 0x0a: case 0x0b: case 0x0c: case 0x0d:
|
|
case 0x0e: case 0x0f: case 0x12: case 0x13:
|
|
case 0x14: case 0x16: case 0x17: case 0x18:
|
|
case 0x19: case 0x1a: case 0x1b: case 0x1c:
|
|
case 0x1d: case 0x1e: case 0x1f:
|
|
return svga->seqregs[svga->seqaddr];
|
|
}
|
|
return svga->seqregs[svga->seqaddr & 0x3f];
|
|
}
|
|
break;
|
|
|
|
case 0x3cf:
|
|
if (svga->gdcaddr >= 0x3a)
|
|
{
|
|
return 0xff;
|
|
}
|
|
if (svga->gdcaddr > 8)
|
|
{
|
|
return svga->gdcreg[svga->gdcaddr & 0x3f];
|
|
}
|
|
break;
|
|
|
|
case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9:
|
|
// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc);
|
|
return cl_ramdac_in(addr, &clgd->ramdac, clgd, svga);
|
|
|
|
case 0x3D4:
|
|
return svga->crtcreg;
|
|
case 0x3D5:
|
|
switch (svga->crtcreg)
|
|
{
|
|
case 0x24: /*Attribute controller toggle readback (R)*/
|
|
return svga->attrff << 7;
|
|
case 0x26: /*Attribute controller index readback (R)*/
|
|
return svga->attraddr & 0x3f;
|
|
}
|
|
return svga->crtc[svga->crtcreg];
|
|
}
|
|
return svga_in(addr, svga);
|
|
}
|
|
|
|
/***************************************
|
|
*
|
|
* bank memory
|
|
*
|
|
***************************************/
|
|
void cirrus_update_bank_ptr(clgd_t *clgd, uint8_t bank_index)
|
|
{
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
uint32_t offset;
|
|
uint32_t limit;
|
|
|
|
if ((svga->gdcreg[0x0b] & 0x01) != 0) /* dual bank */
|
|
offset = svga->gdcreg[0x09 + bank_index];
|
|
else /* single bank */
|
|
offset = svga->gdcreg[0x09];
|
|
|
|
if ((svga->gdcreg[0x0b] & 0x20) != 0)
|
|
offset <<= 14;
|
|
else
|
|
offset <<= 12;
|
|
|
|
if (clgd->vram_size <= offset)
|
|
limit = 0;
|
|
else
|
|
limit = clgd->vram_size - offset;
|
|
|
|
if (((svga->gdcreg[0x0b] & 0x01) == 0) && (bank_index != 0)) {
|
|
if (limit > 0x8000) {
|
|
offset += 0x8000;
|
|
limit -= 0x8000;
|
|
} else {
|
|
limit = 0;
|
|
}
|
|
}
|
|
|
|
if (limit > 0) {
|
|
clgd->bank[bank_index] = offset;
|
|
clgd->limit[bank_index] = limit;
|
|
} else {
|
|
clgd->bank[bank_index] = 0;
|
|
clgd->limit[bank_index] = 0;
|
|
}
|
|
}
|
|
|
|
void clgd_recalctimings(svga_t *svga)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)svga->p;
|
|
|
|
uint32_t iWidth, iHeight;
|
|
uint8_t iDispBpp;
|
|
|
|
svga->ma_latch = (svga->crtc[0x0c] << 8)
|
|
+ svga->crtc[0x0d]
|
|
+ ((svga->crtc[0x1b] & 0x01) << 16)
|
|
+ ((svga->crtc[0x1b] & 0x0c) << 15)
|
|
+ ((svga->crtc[0x1d] & 0x80) << 12);
|
|
svga->ma_latch <<= 2;
|
|
|
|
iHeight = 1 + svga->crtc[0x12]
|
|
+ ((svga->crtc[0x07] & 0x02) << 7)
|
|
+ ((svga->crtc[0x07] & 0x40) << 3);
|
|
|
|
if ((svga->crtc[0x1a] & 0x01) > 0) {
|
|
iHeight <<= 1;
|
|
svga->vtotal *= 2;
|
|
svga->dispend *= 2;
|
|
svga->vblankstart *= 2;
|
|
svga->vsyncstart *= 2;
|
|
svga->split *= 2;
|
|
}
|
|
|
|
iWidth = (svga->crtc[0x01] + 1) * 8;
|
|
iDispBpp = 4;
|
|
|
|
if ((svga->seqregs[0x07] & 0x1) == CIRRUS_SR7_BPP_SVGA)
|
|
{
|
|
pclog("Cirrus SVGA extended sequencer mode %x\n", svga->seqregs[0x07]);
|
|
switch (svga->seqregs[0x07] & CIRRUS_SR7_BPP_MASK)
|
|
{
|
|
case CIRRUS_SR7_BPP_8:
|
|
iDispBpp = 8;
|
|
svga->render = svga_render_8bpp_highres;
|
|
break;
|
|
|
|
case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
|
|
case CIRRUS_SR7_BPP_16:
|
|
case 0x7:
|
|
if (clgd->ramdac.ctrl & 0x1)
|
|
{
|
|
iDispBpp = 16;
|
|
svga->render = svga_render_16bpp_highres;
|
|
}
|
|
else
|
|
{
|
|
iDispBpp = 15;
|
|
svga->render = svga_render_15bpp_highres;
|
|
}
|
|
break;
|
|
|
|
case 0x3:
|
|
case CIRRUS_SR7_BPP_24:
|
|
case 0x5:
|
|
case 0xe:
|
|
iDispBpp = 24;
|
|
svga->render = svga_render_24bpp_highres;
|
|
break;
|
|
|
|
case CIRRUS_SR7_BPP_32:
|
|
iDispBpp = 32;
|
|
svga->render = svga_render_32bpp_highres;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((iWidth != svga->video_res_x) || (iHeight != svga->video_res_y)
|
|
|| (iDispBpp != svga->bpp)) {
|
|
pclog("Cirrus switched to %u x %u x %u\n", iWidth, iHeight, iDispBpp);
|
|
}
|
|
|
|
svga->video_res_x = iWidth;
|
|
svga->video_res_y = iHeight;
|
|
svga->bpp = iDispBpp;
|
|
// pclog("MA now %05X %02X\n", svga->ma_latch, svga->crtc[0x1b]);
|
|
}
|
|
|
|
void clgd_hwcursor_draw(svga_t *svga, int displine)
|
|
{
|
|
int x;
|
|
uint8_t dat[2];
|
|
int xx;
|
|
int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
|
|
int largecur = (svga->seqregs[0x12] & 4);
|
|
int cursize = (largecur) ? 64 : 32;
|
|
int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0;
|
|
int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0;
|
|
|
|
for (x = 0; x < cursize; x += 8)
|
|
{
|
|
dat[0] = svga->vram[svga->hwcursor_latch.addr];
|
|
dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80];
|
|
for (xx = 0; xx < 8; xx++)
|
|
{
|
|
if (offset >= svga->hwcursor_latch.x)
|
|
{
|
|
if (dat[1] & 0x80)
|
|
((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] = 0;
|
|
if (dat[0] & 0x80)
|
|
((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] ^= 0xffffff;
|
|
}
|
|
|
|
offset++;
|
|
dat[0] <<= 1;
|
|
dat[1] <<= 1;
|
|
}
|
|
svga->hwcursor_latch.addr++;
|
|
}
|
|
}
|
|
|
|
void cirrus_update_memory_access(clgd_t *clgd)
|
|
{
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
if ((svga->seqregs[0x17] & 0x44) == 0x44)
|
|
{
|
|
goto generic_io;
|
|
}
|
|
else if (clgd->src_ptr != clgd->src_ptr_end)
|
|
{
|
|
goto generic_io;
|
|
}
|
|
else
|
|
{
|
|
if ((svga->gdcreg[0x0B] & 0x14) == 0x14)
|
|
{
|
|
goto generic_io;
|
|
}
|
|
else if (svga->gdcreg[0x0B] & 0x02)
|
|
{
|
|
goto generic_io;
|
|
}
|
|
|
|
svga->writemode = svga->gdcreg[0x05] & 7;
|
|
if (svga->writemode < 4 || svga->writemode > 5 || ((svga->gdcreg[0x0B] & 0x4) == 0))
|
|
{
|
|
//pclog("Write mapping %02X %i\n", svga->gdcreg[6], svga->seqregs[0x17] & 0x04);
|
|
switch (svga->gdcreg[6] & 0x0C)
|
|
{
|
|
case 0x0: /*128k at A0000*/
|
|
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
|
|
mem_mapping_disable(&clgd->mmio_mapping);
|
|
svga->banked_mask = 0xffff;
|
|
break;
|
|
case 0x4: /*64k at A0000*/
|
|
mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000);
|
|
if (svga->seqregs[0x17] & 0x04)
|
|
mem_mapping_set_addr(&clgd->mmio_mapping, 0xb8000, 0x00100);
|
|
svga->banked_mask = 0xffff;
|
|
break;
|
|
case 0x8: /*32k at B0000*/
|
|
mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000);
|
|
mem_mapping_disable(&clgd->mmio_mapping);
|
|
svga->banked_mask = 0x7fff;
|
|
break;
|
|
case 0xC: /*32k at B8000*/
|
|
mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000);
|
|
mem_mapping_disable(&clgd->mmio_mapping);
|
|
svga->banked_mask = 0x7fff;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
generic_io:
|
|
mem_mapping_disable(&svga->mapping);
|
|
mem_mapping_disable(&clgd->mmio_mapping);
|
|
}
|
|
}
|
|
}
|
|
|
|
void svga_write_mode45_8bpp(clgd_t *clgd, uint8_t mode, uint32_t offset, uint8_t mem_value)
|
|
{
|
|
int x;
|
|
uint8_t val = mem_value;
|
|
uint8_t *dst;
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
dst = svga->vram + (offset &= svga->vrammask);
|
|
|
|
svga->changedvram[(offset &= svga->vrammask) >> 12] = changeframecount;
|
|
|
|
for (x = 0; x < 8; x++)
|
|
{
|
|
if (val & 0x80)
|
|
{
|
|
*dst = clgd->blt.fg_col;
|
|
}
|
|
else
|
|
{
|
|
*dst = clgd->blt.bg_col;
|
|
}
|
|
val <<= 1;
|
|
dst++;
|
|
}
|
|
}
|
|
|
|
void svga_write_mode45_16bpp(clgd_t *clgd, unsigned mode, unsigned offset, uint32_t mem_value)
|
|
{
|
|
int x;
|
|
unsigned val = mem_value;
|
|
uint8_t *dst;
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
dst = svga->vram + (offset &= svga->vrammask);
|
|
|
|
svga->changedvram[(offset &= svga->vrammask) >> 12] = changeframecount;
|
|
|
|
for (x = 0; x < 8; x++)
|
|
{
|
|
if (val & 0x80)
|
|
{
|
|
*dst = clgd->blt.fg_col;
|
|
*(dst + 1) = svga->gdcreg[0x11];
|
|
}
|
|
else
|
|
{
|
|
*dst = clgd->blt.bg_col;
|
|
*(dst + 1) = svga->gdcreg[0x10];
|
|
}
|
|
val <<= 1;
|
|
dst += 2;
|
|
}
|
|
}
|
|
|
|
uint8_t cirrus_mmio_blt_read(uint32_t address, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
uint8_t value;
|
|
|
|
switch(address & 0xff)
|
|
{
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
|
|
value = svga->gdcreg[0x00];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 1):
|
|
value = svga->gdcreg[0x10];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 2):
|
|
value = svga->gdcreg[0x12];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 3):
|
|
value = svga->gdcreg[0x14];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 0):
|
|
value = svga->gdcreg[0x01];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 1):
|
|
value = svga->gdcreg[0x11];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 2):
|
|
value = svga->gdcreg[0x13];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 3):
|
|
value = svga->gdcreg[0x15];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWIDTH + 0):
|
|
value = svga->gdcreg[0x20];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWIDTH + 1):
|
|
value = svga->gdcreg[0x21];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTHEIGHT + 0):
|
|
value = svga->gdcreg[0x22];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTHEIGHT + 1):
|
|
value = svga->gdcreg[0x23];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTPITCH + 0):
|
|
value = svga->gdcreg[0x24];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTPITCH + 1):
|
|
value = svga->gdcreg[0x25];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCPITCH + 0):
|
|
value = svga->gdcreg[0x26];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCPITCH + 1):
|
|
value = svga->gdcreg[0x27];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 0):
|
|
value = svga->gdcreg[0x28];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 1):
|
|
value = svga->gdcreg[0x29];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 2):
|
|
value = svga->gdcreg[0x2a];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 0):
|
|
value = svga->gdcreg[0x2c];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 1):
|
|
value = svga->gdcreg[0x2d];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 2):
|
|
value = svga->gdcreg[0x2e];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWRITEMASK):
|
|
value = svga->gdcreg[0x2f];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTMODE):
|
|
value = svga->gdcreg[0x30];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTROP):
|
|
value = svga->gdcreg[0x32];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTMODEEXT):
|
|
value = svga->gdcreg[0x33];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
|
|
value = svga->gdcreg[0x34];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
|
|
value = svga->gdcreg[0x35];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
|
|
value = svga->gdcreg[0x38];
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
|
|
value = svga->gdcreg[0x39];
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void cirrus_mmio_blt_write(uint32_t address, uint8_t value, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
switch(address & 0xff)
|
|
{
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
|
|
svga->gdcreg[0x00] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 1):
|
|
svga->gdcreg[0x10] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 2):
|
|
svga->gdcreg[0x12] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTBGCOLOR + 3):
|
|
svga->gdcreg[0x14] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 0):
|
|
svga->gdcreg[0x01] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 1):
|
|
svga->gdcreg[0x11] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 2):
|
|
svga->gdcreg[0x13] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTFGCOLOR + 3):
|
|
svga->gdcreg[0x15] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWIDTH + 0):
|
|
svga->gdcreg[0x20] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWIDTH + 1):
|
|
svga->gdcreg[0x21] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTHEIGHT + 0):
|
|
svga->gdcreg[0x22] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTHEIGHT + 1):
|
|
svga->gdcreg[0x23] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTPITCH + 0):
|
|
svga->gdcreg[0x24] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTPITCH + 1):
|
|
svga->gdcreg[0x25] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCPITCH + 0):
|
|
svga->gdcreg[0x26] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCPITCH + 1):
|
|
svga->gdcreg[0x27] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 0):
|
|
svga->gdcreg[0x28] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 1):
|
|
svga->gdcreg[0x29] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTDESTADDR + 2):
|
|
svga->gdcreg[0x2a] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 0):
|
|
svga->gdcreg[0x2c] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 1):
|
|
svga->gdcreg[0x2d] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTSRCADDR + 2):
|
|
svga->gdcreg[0x2e] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTWRITEMASK):
|
|
svga->gdcreg[0x2f] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTMODE):
|
|
svga->gdcreg[0x30] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTROP):
|
|
svga->gdcreg[0x32] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTMODEEXT):
|
|
svga->gdcreg[0x33] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
|
|
svga->gdcreg[0x34] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
|
|
svga->gdcreg[0x35] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
|
|
svga->gdcreg[0x38] = value;
|
|
break;
|
|
case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
|
|
svga->gdcreg[0x39] = value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void cirrus_write(uint32_t addr, uint8_t val, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
|
|
// pclog("gd5429_write : %05X %02X ", addr, val);
|
|
if (clgd->src_ptr != clgd->src_ptr_end)
|
|
{
|
|
/* bitblt */
|
|
*clgd->src_ptr++ = (uint8_t) val;
|
|
if (clgd->src_ptr >= clgd->src_ptr_end)
|
|
{
|
|
cirrus_bitblt_cputovideo_next(clgd, svga);
|
|
}
|
|
}
|
|
|
|
addr &= svga->banked_mask;
|
|
addr = (addr & 0x7fff) + clgd->bank[(addr >> 15) & 1];
|
|
// pclog("%08X\n", addr);
|
|
// svga_write_linear(addr, val, &clgd->svga);
|
|
svga->writemode = svga->gdcreg[0x05] & 0x7;
|
|
if (svga->writemode < 4 || svga->writemode > 5 || ((svga->gdcreg[0x0B] & 0x4) == 0)) {
|
|
svga_write_linear(addr, val, &clgd->svga);
|
|
} else {
|
|
if ((svga->gdcreg[0x0B] & 0x14) != 0x14) {
|
|
svga_write_mode45_8bpp(clgd, svga->writemode,
|
|
addr,
|
|
val);
|
|
} else {
|
|
svga_write_mode45_16bpp(clgd, svga->writemode,
|
|
addr,
|
|
val);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t cirrus_read(uint32_t addr, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
svga_t *svga = &clgd->svga;
|
|
uint8_t ret;
|
|
|
|
// pclog("gd5429_read : %05X ", addr);
|
|
addr &= svga->banked_mask;
|
|
addr = (addr & 0x7fff) + clgd->bank[(addr >> 15) & 1];
|
|
ret = svga_read_linear(addr, &clgd->svga);
|
|
// pclog("%08X %02X\n", addr, ret);
|
|
return ret;
|
|
}
|
|
|
|
void *clgd_common_init(char *romfn, uint8_t id)
|
|
{
|
|
clgd = malloc(sizeof(clgd_t));
|
|
svga_t *svga = &clgd->svga;
|
|
memset(clgd, 0, sizeof(clgd_t));
|
|
|
|
rom_init(&clgd->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
|
|
|
svga_init(&clgd->svga, clgd, 1 << 21, /*2mb*/
|
|
clgd_recalctimings,
|
|
clgd_in, clgd_out,
|
|
clgd_hwcursor_draw,
|
|
NULL);
|
|
|
|
mem_mapping_set_handler(&svga->mapping, cirrus_read, NULL, NULL, cirrus_write, NULL, NULL);
|
|
mem_mapping_set_p(&svga->mapping, clgd);
|
|
|
|
mem_mapping_add(&clgd->mmio_mapping, 0, 0, cirrus_mmio_blt_read, NULL, NULL, cirrus_mmio_blt_write, NULL, NULL, NULL, 0, clgd);
|
|
|
|
io_sethandler(0x03c0, 0x0020, clgd_in, NULL, NULL, clgd_out, NULL, NULL, clgd);
|
|
|
|
if (id < CIRRUS_ID_CLGD5428)
|
|
{
|
|
/* 1 MB */
|
|
clgd->vram_size = (1 << 20);
|
|
clgd->vram_code = 2;
|
|
|
|
svga->seqregs[0xf] = 0x18;
|
|
svga->seqregs[0x1f] = 0x22;
|
|
}
|
|
else if ((id >= CIRRUS_ID_CLGD5428) && (id <= CIRRUS_ID_CLGD5430))
|
|
{
|
|
/* 2 MB */
|
|
clgd->vram_size = (1 << 21);
|
|
clgd->vram_code = 3;
|
|
|
|
svga->seqregs[0xf] = 0x18;
|
|
svga->seqregs[0x1f] = 0x22;
|
|
}
|
|
else if (id >= CIRRUS_ID_CLGD5434)
|
|
{
|
|
/* 4 MB */
|
|
clgd->vram_size = (1 << 22);
|
|
clgd->vram_code = 4;
|
|
|
|
svga->seqregs[0xf] = 0x98;
|
|
svga->seqregs[0x1f] = 0x2d;
|
|
svga->seqregs[0x17] = 0x20;
|
|
svga->gdcreg[0x18] = 0xf;
|
|
}
|
|
|
|
// Seems the 5436 and 5446 BIOS'es never turn on that bit until it's actually needed,
|
|
// therefore they also don't turn it back off on 640x480x4bpp,
|
|
// therefore, we need to make sure the VRAM mask is correct at start.
|
|
svga->vrammask = (svga->crtc[0x1b] & 2) ? (clgd->vram_size - 1) : 0x3ffff;
|
|
clgd->linear_mmio_mask = (svga->crtc[0x1b] & 2) ? (clgd->vram_size - 256) : (0x40000 - 256);
|
|
|
|
svga->seqregs[0x15] = clgd->vram_code;
|
|
if ((id >= CIRRUS_ID_CLGD5422) && (id <= CIRRUS_ID_CLGD5429)) svga->seqregs[0xa] = (clgd->vram_code << 3);
|
|
|
|
svga->crtc[0x27] = id;
|
|
|
|
// clgd_recalc_mapping(clgd);
|
|
/* force refresh */
|
|
// cirrus_update_bank_ptr(s, 0);
|
|
// cirrus_update_bank_ptr(s, 1);
|
|
|
|
init_rops();
|
|
|
|
return clgd;
|
|
}
|
|
|
|
void *gd6235_init()
|
|
{
|
|
return clgd_common_init("roms/vga6235.rom", CIRRUS_ID_CLGD6235);
|
|
}
|
|
|
|
void *gd5422_init()
|
|
{
|
|
return clgd_common_init("roms/CL5422.ROM", CIRRUS_ID_CLGD5422);
|
|
}
|
|
|
|
void *gd5429_init()
|
|
{
|
|
return clgd_common_init("roms/5429.vbi", CIRRUS_ID_CLGD5429);
|
|
}
|
|
|
|
void *gd5430_init()
|
|
{
|
|
return clgd_common_init("roms/pci.BIN", CIRRUS_ID_CLGD5430);
|
|
}
|
|
|
|
void *dia5430_init()
|
|
{
|
|
return clgd_common_init("roms/diamondvlbus.BIN", CIRRUS_ID_CLGD5430);
|
|
}
|
|
|
|
void *gd5434_init()
|
|
{
|
|
return clgd_common_init("roms/japan.BIN", CIRRUS_ID_CLGD5434);
|
|
}
|
|
|
|
void *gd5436_init()
|
|
{
|
|
return clgd_common_init("roms/5436.VBI", CIRRUS_ID_CLGD5436);
|
|
}
|
|
|
|
void *gd5440_init()
|
|
{
|
|
return clgd_common_init("roms/5440BIOS.BIN", CIRRUS_ID_CLGD5440);
|
|
}
|
|
|
|
void *gd5446_init()
|
|
{
|
|
return clgd_common_init("roms/5446BV.VBI", CIRRUS_ID_CLGD5446);
|
|
}
|
|
|
|
static int gd5422_available()
|
|
{
|
|
return rom_present("roms/CL5422.ROM");
|
|
}
|
|
|
|
static int gd5429_available()
|
|
{
|
|
return rom_present("roms/5429.vbi");
|
|
}
|
|
|
|
static int gd5430_available()
|
|
{
|
|
return rom_present("roms/pci.BIN");
|
|
}
|
|
|
|
static int dia5430_available()
|
|
{
|
|
return rom_present("roms/diamondvlbus.BIN");
|
|
}
|
|
|
|
static int gd5434_available()
|
|
{
|
|
return rom_present("roms/japan.BIN");
|
|
}
|
|
|
|
static int gd5436_available()
|
|
{
|
|
return rom_present("roms/5436.VBI");
|
|
}
|
|
|
|
static int gd5440_available()
|
|
{
|
|
return rom_present("roms/5440BIOS.BIN");
|
|
}
|
|
|
|
static int gd5446_available()
|
|
{
|
|
return rom_present("roms/5446BV.VBI");
|
|
}
|
|
|
|
static int gd6235_available()
|
|
{
|
|
return rom_present("roms/vga6235.rom");
|
|
}
|
|
|
|
void clgd_close(void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
|
|
svga_close(&clgd->svga);
|
|
|
|
free(clgd);
|
|
}
|
|
|
|
void clgd_speed_changed(void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
|
|
svga_recalctimings(&clgd->svga);
|
|
}
|
|
|
|
void clgd_force_redraw(void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
|
|
clgd->svga.fullchange = changeframecount;
|
|
}
|
|
|
|
void clgd_add_status_info(char *s, int max_len, void *p)
|
|
{
|
|
clgd_t *clgd = (clgd_t *)p;
|
|
|
|
svga_add_status_info(s, max_len, &clgd->svga);
|
|
}
|
|
|
|
device_t gd5422_device =
|
|
{
|
|
"Cirrus Logic GD5422",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5422_init,
|
|
clgd_close,
|
|
gd5422_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5429_device =
|
|
{
|
|
"Cirrus Logic GD5429",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5429_init,
|
|
clgd_close,
|
|
gd5429_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5430_device =
|
|
{
|
|
"Cirrus Logic GD5430",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5430_init,
|
|
clgd_close,
|
|
gd5430_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t dia5430_device =
|
|
{
|
|
"Diamond CL-GD5430",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
dia5430_init,
|
|
clgd_close,
|
|
dia5430_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5434_device =
|
|
{
|
|
"Cirrus Logic GD5434",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5434_init,
|
|
clgd_close,
|
|
gd5434_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5436_device =
|
|
{
|
|
"Cirrus Logic GD5436",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5436_init,
|
|
clgd_close,
|
|
gd5436_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5440_device =
|
|
{
|
|
"Cirrus Logic GD5440",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5440_init,
|
|
clgd_close,
|
|
gd5440_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd5446_device =
|
|
{
|
|
"Cirrus Logic GD5446",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd5446_init,
|
|
clgd_close,
|
|
gd5446_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
};
|
|
|
|
device_t gd6235_device =
|
|
{
|
|
"Cirrus Logic GD6235",
|
|
// DEVICE_NOT_WORKING,
|
|
0,
|
|
gd6235_init,
|
|
clgd_close,
|
|
gd6235_available,
|
|
clgd_speed_changed,
|
|
clgd_force_redraw,
|
|
clgd_add_status_info
|
|
}; |