More Hercules fixes.

This commit is contained in:
OBattler
2021-08-02 04:24:23 +02:00
parent 4af2177c66
commit 07e7c1dd9e

View File

@@ -36,7 +36,7 @@
typedef struct { typedef struct {
mem_mapping_t mapping; mem_mapping_t mapping;
uint8_t crtc[32]; uint8_t crtc[32], charbuffer[4096];
int crtcreg; int crtcreg;
uint8_t ctrl, uint8_t ctrl,
@@ -125,27 +125,31 @@ hercules_out(uint16_t addr, uint8_t val, void *priv)
dev->crtc[10] = 0xb; dev->crtc[10] = 0xb;
dev->crtc[11] = 0xc; dev->crtc[11] = 0xc;
} }
#if 0
if (old ^ val)
recalc_timings(dev);
#else
if (old != val) { if (old != val) {
if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) {
fullchange = changeframecount; fullchange = changeframecount;
recalc_timings(dev); recalc_timings(dev);
} }
} }
#endif
break; break;
case 0x03b8: case 0x03b8:
old = dev->ctrl; old = dev->ctrl;
/* Prevent settings of bits if they are disabled in CTRL2. */
if (!(dev->ctrl2 & 0x01) && (val & 0x02)) /* Prevent setting of bits if they are disabled in CTRL2. */
val &= 0xfd; if ((old & 0x02) && !(val & 0x02))
if (!(dev->ctrl2 & 0x02) && (val & 0x80)) dev->ctrl &= 0xfd;
val &= 0x7f; else if ((val & 0x02) && (dev->ctrl2 & 0x01))
dev->ctrl = val; dev->ctrl |= 0x02;
if ((old & 0x80) && !(val & 0x80))
dev->ctrl &= 0x7f;
else if ((val & 0x80) && (dev->ctrl2 & 0x02))
dev->ctrl |= 0x80;
dev->ctrl = (dev->ctrl & 0x82) | (val & 0x7d);
if (old ^ val) if (old ^ val)
recalc_timings(dev); recalc_timings(dev);
break; break;
@@ -158,6 +162,19 @@ hercules_out(uint16_t addr, uint8_t val, void *priv)
case 0x03bf: case 0x03bf:
old = dev->ctrl2; old = dev->ctrl2;
dev->ctrl2 = val; dev->ctrl2 = val;
/* According to the Programmer's guide to the Hercules graphics cars
by David B. Doty from 1988, the CTRL2 modes (bits 1,0) are as follow:
- 00: DIAG: Text mode only, only page 0 accessible;
- 01: HALF: Graphics mode allowed, only page 0 accessible;
- 11: FULL: Graphics mode allowed, both pages accessible. */
if (val & 0x01)
mem_mapping_set_exec(&dev->mapping, dev->vram);
else
mem_mapping_set_exec(&dev->mapping, NULL);
if (val & 0x02)
mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000);
else
mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000);
if (old ^ val) if (old ^ val)
recalc_timings(dev); recalc_timings(dev);
break; break;
@@ -187,21 +204,18 @@ hercules_in(uint16_t addr, void *priv)
case 0x03b5: case 0x03b5:
case 0x03b7: case 0x03b7:
ret = dev->crtc[dev->crtcreg]; ret = dev->crtc[dev->crtcreg];
if (dev->crtcreg == 12)
ret = (dev->ma >> 8) & 0x3f;
else
ret = dev->ma & 0xff;
break; break;
case 0x03ba: case 0x03ba:
// ret = 0x72; /* Hercules ident */
ret = 0x70; /* Hercules ident */ ret = 0x70; /* Hercules ident */
ret |= (dev->lp_ff ? 2 : 0); ret |= (dev->lp_ff ? 2 : 0);
#if 0 ret |= (dev->stat & 0x01);
if (dev->stat & 0x08)
ret |= 0x88;
#else
if (dev->stat & 0x08) if (dev->stat & 0x08)
ret |= 0x80; ret |= 0x80;
#endif
if ((dev->stat & 0x09) == 0x01)
ret |= (dev->stat & 0x01);
if ((ret & 0x81) == 0x80) if ((ret & 0x81) == 0x80)
ret |= 0x08; ret |= 0x08;
break; break;
@@ -230,15 +244,12 @@ hercules_write(uint32_t addr, uint8_t val, void *priv)
{ {
hercules_t *dev = (hercules_t *)priv; hercules_t *dev = (hercules_t *)priv;
/* According to the Programmer's guide to the Hercules graphics cars if (dev->ctrl2 & 0x01)
by David B. Doty from 1988, the CTRL2 modes (bits 1,0) are as follow: addr &= 0xffff;
- 00: DIAG: Text mode only, only page 0 accessible; else
- 01: HALF: Graphics mode allowed, only page 0 accessible; addr &= 0x0fff;
- 11: FULL: Graphics mode allowed, both pages accessible. */
if ((addr >= 0xb8000) && ((dev->ctrl2 & 0x03) != 0x03))
return;
dev->vram[addr & 0xffff] = val; dev->vram[addr] = val;
hercules_waitstates(dev); hercules_waitstates(dev);
} }
@@ -248,13 +259,18 @@ static uint8_t
hercules_read(uint32_t addr, void *priv) hercules_read(uint32_t addr, void *priv)
{ {
hercules_t *dev = (hercules_t *)priv; hercules_t *dev = (hercules_t *)priv;
uint8_t ret = 0xff;
if ((addr >= 0xb8000) && ((dev->ctrl2 & 0x03) != 0x03)) if (dev->ctrl2 & 0x01)
return 0xff; addr &= 0xffff;
else
return(dev->vram[addr & 0xffff]); addr &= 0x0fff;
hercules_waitstates(dev); hercules_waitstates(dev);
ret = dev->vram[addr];
return ret;
} }
@@ -282,14 +298,14 @@ hercules_poll(void *priv)
if (dev->dispon) { if (dev->dispon) {
if (dev->displine < dev->firstline) { if (dev->displine < dev->firstline) {
dev->firstline = dev->displine; dev->firstline = dev->displine;
video_wait_for_buffer(); video_wait_for_buffer();
} }
dev->lastline = dev->displine; dev->lastline = dev->displine;
if ((dev->ctrl & 0x02) && (dev->ctrl2 & 0x01)) { if (dev->ctrl & 0x02) {
ca = (dev->sc & 3) * 0x2000; ca = (dev->sc & 3) * 0x2000;
if ((dev->ctrl & 0x80) && (dev->ctrl2 & 0x02)) if (dev->ctrl & 0x80)
ca += 0x8000; ca += 0x8000;
for (x = 0; x < dev->crtc[1]; x++) { for (x = 0; x < dev->crtc[1]; x++) {
@@ -304,13 +320,12 @@ hercules_poll(void *priv)
video_blend((x << 4) + c, dev->displine); video_blend((x << 4) + c, dev->displine);
} }
} else { } else {
pa = ((dev->ctrl & 0x80) && (dev->ctrl2 & 0x02)) ? 0x8000 : 0x0000;
for (x = 0; x < dev->crtc[1]; x++) { for (x = 0; x < dev->crtc[1]; x++) {
if (dev->ctrl & 8) { if (dev->ctrl & 8) {
/* Undocumented behavior: page 1 in text mode means characters are read /* Undocumented behavior: page 1 in text mode means characters are read
from page 1 and attributes from page 0. */ from page 1 and attributes from page 0. */
chr = dev->vram[((dev->ma << 1) & 0xfff) + pa]; chr = dev->charbuffer[x << 1];
attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; attr = dev->charbuffer[(x << 1) + 1];
} else } else
chr = attr = 0; chr = attr = 0;
drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron);
@@ -328,7 +343,10 @@ hercules_poll(void *priv)
else else
buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0]; buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0];
} }
dev->ma++; if (dev->ctrl2 & 0x01)
dev->ma = (dev->ma + 1) & 0x3fff;
else
dev->ma = (dev->ma + 1) & 0x7ff;
if (drawcursor) { if (drawcursor) {
for (c = 0; c < 9; c++) for (c = 0; c < 9; c++)
@@ -347,6 +365,9 @@ hercules_poll(void *priv)
} else { } else {
timer_advance_u64(&dev->timer, dev->dispontime); timer_advance_u64(&dev->timer, dev->dispontime);
if (dev->dispon)
dev->stat &= ~1;
dev->linepos = 0; dev->linepos = 0;
if (dev->vsynctime) { if (dev->vsynctime) {
dev->vsynctime--; dev->vsynctime--;
@@ -364,42 +385,51 @@ hercules_poll(void *priv)
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->dispon = 1; dev->dispon = 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;
} }
} else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { } else if (((dev->crtc[8] & 3) != 3 && dev->sc == dev->crtc[9]) || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) {
dev->maback = dev->ma; dev->maback = dev->ma;
dev->sc = 0; dev->sc = 0;
oldvc = dev->vc; oldvc = dev->vc;
dev->vc++; dev->vc++;
dev->vc &= 127; dev->vc &= 127;
if (dev->vc == dev->crtc[6]) if (dev->vc == dev->crtc[6])
dev->dispon = 0; dev->dispon = 0;
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) if (! dev->vadj) {
dev->dispon = 1; dev->dispon = 1;
if (! dev->vadj)
dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff;
if ((dev->crtc[10] & 0x60) == 0x20) }
dev->cursoron = 0; switch (dev->crtc[10] & 0x60) {
else case 0x20:
dev->cursoron = dev->blink & 16; dev->cursoron = 0;
break;
case 0x60:
dev->cursoron = dev->blink & 0x10;
break;
default:
dev->cursoron = dev->blink & 0x08;
break;
}
} }
if (dev->vc == dev->crtc[7]) { if (dev->vc == dev->crtc[7]) {
dev->dispon = 0; dev->dispon = 0;
dev->displine = 0; dev->displine = 0;
dev->vsynctime = 16;//(crtcm[3]>>4)+1; if ((dev->crtc[8] & 3) == 3)
dev->vsynctime = ((int32_t)dev->crtc[4] * ((dev->crtc[9] >> 1) + 1)) + dev->crtc[5] - dev->crtc[7] + 1;
else
dev->vsynctime = ((int32_t)dev->crtc[4] * (dev->crtc[9] + 1)) + dev->crtc[5] - dev->crtc[7] + 1;
if (dev->crtc[7]) { if (dev->crtc[7]) {
// if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) if (dev->ctrl & 0x02)
if (dev->ctrl & 2)
x = dev->crtc[1] << 4; x = dev->crtc[1] << 4;
else else
x = dev->crtc[1] * 9; x = dev->crtc[1] * 9;
@@ -419,7 +449,8 @@ hercules_poll(void *priv)
video_blit_memtoscreen_8(0, dev->firstline, 0, ysize, xsize, ysize); video_blit_memtoscreen_8(0, dev->firstline, 0, ysize, xsize, ysize);
frames++; frames++;
if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) {
if (dev->ctrl & 0x02) {
video_res_x = dev->crtc[1] * 16; video_res_x = dev->crtc[1] * 16;
video_res_y = dev->crtc[6] * 4; video_res_y = dev->crtc[6] * 4;
video_bpp = 1; video_bpp = 1;
@@ -439,12 +470,15 @@ hercules_poll(void *priv)
dev->ma = dev->maback; dev->ma = dev->maback;
} }
if (dev->dispon)
dev->stat &= ~1;
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;
if (dev->dispon && !(dev->ctrl & 0x02)) {
for (x = 0; x < (dev->crtc[1] << 1); x++) {
pa = (dev->ctrl & 0x80) ? ((x & 1) ? 0x0000 : 0x8000) : 0x0000;
dev->charbuffer[x] = dev->vram[(((dev->ma << 1) + x) & 0x3fff) + pa];
}
}
} }
} }
@@ -462,9 +496,9 @@ hercules_init(const device_t *info)
timer_add(&dev->timer, hercules_poll, dev, 1); timer_add(&dev->timer, hercules_poll, dev, 1);
mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, mem_mapping_add(&dev->mapping, 0xb0000, 0x08000,
hercules_read,NULL,NULL, hercules_write,NULL,NULL, hercules_read,NULL,NULL, hercules_write,NULL,NULL,
dev->vram, MEM_MAPPING_EXTERNAL, dev); NULL /*dev->vram*/, MEM_MAPPING_EXTERNAL, dev);
io_sethandler(0x03b0, 16, io_sethandler(0x03b0, 16,
hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev); hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev);