pcem/src/vid_olivetti_m24.c
TomW 2ca4ead570 Implemented preliminary S3 ViRGE 2D blitter emulation.
Misc ViRGE fixes.
Changes to memory mapping.
Changes to PCI handling.
Disabled 'AMI WinBIOS 486 PCI' due to incomplete chipset emulation.
Invalid GUS register reads no longer kill the emulator.
2014-03-20 14:03:55 +00:00

492 lines
23 KiB
C

/*Olivetti M24 video emulation
Essentially double-res CGA*/
#include <stdlib.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "mem.h"
#include "timer.h"
#include "video.h"
#include "vid_olivetti_m24.h"
typedef struct m24_t
{
mem_mapping_t mapping;
uint8_t crtc[32];
int crtcreg;
uint8_t *vram;
uint8_t charbuffer[256];
uint8_t ctrl;
uint32_t base;
uint8_t cgamode, cgacol;
uint8_t stat;
int linepos, displine;
int sc, vc;
int con, coff, cursoron, blink;
int vsynctime, vadj;
int lineff;
uint16_t ma, maback;
int dispon;
int dispontime, dispofftime, vidtime;
int firstline, lastline;
} m24_t;
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 m24_recalctimings(m24_t *m24);
void m24_out(uint16_t addr, uint8_t val, void *p)
{
m24_t *m24 = (m24_t *)p;
uint8_t old;
// pclog("m24_out %04X %02X\n", addr, val);
switch (addr)
{
case 0x3d4:
m24->crtcreg = val & 31;
return;
case 0x3d5:
old = m24->crtc[m24->crtcreg];
m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg];
if (old != val)
{
if (m24->crtcreg < 0xe || m24->crtcreg > 0x10)
{
fullchange = changeframecount;
m24_recalctimings(m24);
}
}
return;
case 0x3d8:
m24->cgamode = val;
return;
case 0x3d9:
m24->cgacol = val;
return;
case 0x3de:
m24->ctrl = val;
m24->base = (val & 0x08) ? 0x4000 : 0;
return;
}
}
uint8_t m24_in(uint16_t addr, void *p)
{
m24_t *m24 = (m24_t *)p;
switch (addr)
{
case 0x3d4:
return m24->crtcreg;
case 0x3d5:
return m24->crtc[m24->crtcreg];
case 0x3da:
return m24->stat;
}
return 0xff;
}
void m24_write(uint32_t addr, uint8_t val, void *p)
{
m24_t *m24 = (m24_t *)p;
m24->vram[addr & 0x7FFF]=val;
m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val;
m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val;
}
uint8_t m24_read(uint32_t addr, void *p)
{
m24_t *m24 = (m24_t *)p;
return m24->vram[addr & 0x7FFF];
}
void m24_recalctimings(m24_t *m24)
{
double _dispontime, _dispofftime, disptime;
if (m24->cgamode & 1)
{
disptime = m24->crtc[0] + 1;
_dispontime = m24->crtc[1];
}
else
{
disptime = (m24->crtc[0] + 1) << 1;
_dispontime = m24->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 / 2;
_dispofftime *= CGACONST / 2;
// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92);
m24->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
m24->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
}
void m24_poll(void *p)
{
m24_t *m24 = (m24_t *)p;
uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff;
int drawcursor;
int x, c;
int oldvc;
uint8_t chr, attr;
uint16_t dat, dat2;
int cols[4];
int col;
int oldsc;
if (!m24->linepos)
{
// pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine);
m24->vidtime += m24->dispofftime;
m24->stat |= 1;
m24->linepos = 1;
oldsc = m24->sc;
if ((m24->crtc[8] & 3) == 3)
m24->sc = (m24->sc << 1) & 7;
if (m24->dispon)
{
pclog("dispon %i\n", m24->linepos);
if (m24->displine < m24->firstline)
{
m24->firstline = m24->displine;
// printf("Firstline %i\n",firstline);
}
m24->lastline = m24->displine;
for (c = 0; c < 8; c++)
{
if ((m24->cgamode & 0x12) == 0x12)
{
buffer->line[m24->displine][c] = 0;
if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0;
else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0;
}
else
{
buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16;
if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16;
else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16;
}
}
if (m24->cgamode & 1)
{
for (x = 0; x < m24->crtc[1]; x++)
{
chr = m24->charbuffer[ x << 1];
attr = m24->charbuffer[(x << 1) + 1];
drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron);
if (m24->cgamode & 0x20)
{
cols[1] = (attr & 15) + 16;
cols[0] = ((attr >> 4) & 7) + 16;
if ((m24->blink & 16) && (attr & 0x80) && !drawcursor)
cols[1] = cols[0];
}
else
{
cols[1] = (attr & 15) + 16;
cols[0] = (attr >> 4) + 16;
}
if (drawcursor)
{
for (c = 0; c < 8; c++)
buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
}
else
{
for (c = 0; c < 8; c++)
buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0];
}
m24->ma++;
}
}
else if (!(m24->cgamode & 2))
{
for (x = 0; x < m24->crtc[1]; x++)
{
chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base];
attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base];
drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron);
if (m24->cgamode & 0x20)
{
cols[1] = (attr & 15) + 16;
cols[0] = ((attr >> 4) & 7) + 16;
if ((m24->blink & 16) && (attr & 0x80))
cols[1] = cols[0];
}
else
{
cols[1] = (attr & 15) + 16;
cols[0] = (attr >> 4) + 16;
}
m24->ma++;
if (drawcursor)
{
for (c = 0; c < 8; c++)
buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
}
else
{
for (c = 0; c < 8; c++)
buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0];
}
}
}
else if (!(m24->cgamode & 16))
{
cols[0] = (m24->cgacol & 15) | 16;
col = (m24->cgacol & 16) ? 24 : 16;
if (m24->cgamode & 4)
{
cols[1] = col | 3;
cols[2] = col | 4;
cols[3] = col | 7;
}
else if (m24->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 < m24->crtc[1]; x++)
{
dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) |
m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base];
m24->ma++;
for (c = 0; c < 8; c++)
{
buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14];
dat <<= 2;
}
}
}
else
{
if (m24->ctrl & 1)
{
dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000);
cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16;
}
else
{
dat2 = (m24->sc & 1) * 0x2000;
cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16;
}
for (x = 0; x < m24->crtc[1]; x++)
{
dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1];
m24->ma++;
for (c = 0; c < 16; c++)
{
buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15];
dat <<= 1;
}
}
}
}
else
{
cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16;
if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]);
else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]);
}
if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
else x = (m24->crtc[1] << 4) + 16;
m24->sc = oldsc;
if (m24->vc == m24->crtc[7] && !m24->sc)
m24->stat |= 8;
m24->displine++;
if (m24->displine >= 720) m24->displine = 0;
}
else
{
// pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj);
m24->vidtime += m24->dispontime;
if (m24->dispon) m24->stat &= ~1;
m24->linepos = 0;
m24->lineff ^= 1;
if (m24->lineff)
{
m24->ma = m24->maback;
}
else
{
if (m24->vsynctime)
{
m24->vsynctime--;
if (!m24->vsynctime)
m24->stat &= ~8;
}
if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1)))
{
m24->con = 0;
m24->coff = 1;
}
if (m24->vadj)
{
m24->sc++;
m24->sc &= 31;
m24->ma = m24->maback;
m24->vadj--;
if (!m24->vadj)
{
m24->dispon = 1;
m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
m24->sc = 0;
}
}
else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1)))
{
m24->maback = m24->ma;
m24->sc = 0;
oldvc = m24->vc;
m24->vc++;
m24->vc &= 127;
if (m24->vc == m24->crtc[6])
m24->dispon=0;
if (oldvc == m24->crtc[4])
{
m24->vc = 0;
m24->vadj = m24->crtc[5];
if (!m24->vadj) m24->dispon = 1;
if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
if ((m24->crtc[10] & 0x60) == 0x20) m24->cursoron = 0;
else m24->cursoron = m24->blink & 16;
}
if (m24->vc == m24->crtc[7])
{
m24->dispon = 0;
m24->displine = 0;
m24->vsynctime = (m24->crtc[3] >> 4) + 1;
if (m24->crtc[7])
{
if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
else x = (m24->crtc[1] << 4) + 16;
m24->lastline++;
if (x != xsize || (m24->lastline - m24->firstline) != ysize)
{
xsize = x;
ysize = m24->lastline - m24->firstline;
if (xsize < 64) xsize = 656;
if (ysize < 32) ysize = 200;
updatewindowsize(xsize, ysize + 16);
}
startblit();
pclog("m24 blit %i %i\n", m24->firstline, m24->lastline);
video_blit_memtoscreen_8(0, m24->firstline - 8, xsize, (m24->lastline - m24->firstline) + 16);
if (readflash) rectfill(screen, winsizex - 40, 8, winsizex - 8, 14, 0xFFFFFFFF);
readflash = 0;
frames++;
endblit();
video_res_x = xsize - 16;
video_res_y = ysize;
if (m24->cgamode & 1)
{
video_res_x /= 8;
video_res_y /= (m24->crtc[9] + 1) * 2;
video_bpp = 0;
}
else if (!(m24->cgamode & 2))
{
video_res_x /= 16;
video_res_y /= (m24->crtc[9] + 1) * 2;
video_bpp = 0;
}
else if (!(m24->cgamode & 16))
{
video_res_x /= 2;
video_res_y /= 2;
video_bpp = 2;
}
else if (!(m24->ctrl & 1))
{
video_res_y /= 2;
video_bpp = 1;
}
}
m24->firstline = 1000;
m24->lastline = 0;
m24->blink++;
}
}
else
{
m24->sc++;
m24->sc &= 31;
m24->ma = m24->maback;
}
if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1))))
m24->con = 1;
}
if (m24->dispon && (m24->cgamode & 1))
{
for (x = 0; x < (m24->crtc[1] << 1); x++)
m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base];
}
}
}
void *m24_init()
{
int c;
m24_t *m24 = malloc(sizeof(m24_t));
memset(m24, 0, sizeof(m24_t));
m24->vram = malloc(0x8000);
timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24);
mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL, NULL, 0, m24);
io_sethandler(0x03d0, 0x0010, m24_in, NULL, NULL, m24_out, NULL, NULL, m24);
return m24;
}
void m24_close(void *p)
{
m24_t *m24 = (m24_t *)p;
free(m24->vram);
free(m24);
}
void m24_speed_changed(void *p)
{
m24_t *m24 = (m24_t *)p;
m24_recalctimings(m24);
}
device_t m24_device =
{
"Olivetti M24 (video)",
0,
m24_init,
m24_close,
NULL,
m24_speed_changed,
NULL,
NULL
};