diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 49a860835..5ff73287a 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -36,7 +36,7 @@ typedef struct { mem_mapping_t mapping; - uint8_t crtc[32]; + uint8_t crtc[32], charbuffer[4096]; int crtcreg; uint8_t ctrl, @@ -125,27 +125,31 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) dev->crtc[10] = 0xb; dev->crtc[11] = 0xc; } -#if 0 - if (old ^ val) - recalc_timings(dev); -#else + if (old != val) { if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { fullchange = changeframecount; recalc_timings(dev); } } -#endif break; case 0x03b8: old = dev->ctrl; - /* Prevent settings of bits if they are disabled in CTRL2. */ - if (!(dev->ctrl2 & 0x01) && (val & 0x02)) - val &= 0xfd; - if (!(dev->ctrl2 & 0x02) && (val & 0x80)) - val &= 0x7f; - dev->ctrl = val; + + /* Prevent setting of bits if they are disabled in CTRL2. */ + if ((old & 0x02) && !(val & 0x02)) + dev->ctrl &= 0xfd; + else if ((val & 0x02) && (dev->ctrl2 & 0x01)) + 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) recalc_timings(dev); break; @@ -158,6 +162,19 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) case 0x03bf: old = dev->ctrl2; 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) recalc_timings(dev); break; @@ -187,21 +204,18 @@ hercules_in(uint16_t addr, void *priv) case 0x03b5: case 0x03b7: ret = dev->crtc[dev->crtcreg]; + if (dev->crtcreg == 12) + ret = (dev->ma >> 8) & 0x3f; + else + ret = dev->ma & 0xff; break; case 0x03ba: - // ret = 0x72; /* Hercules ident */ ret = 0x70; /* Hercules ident */ ret |= (dev->lp_ff ? 2 : 0); -#if 0 - if (dev->stat & 0x08) - ret |= 0x88; -#else + ret |= (dev->stat & 0x01); if (dev->stat & 0x08) ret |= 0x80; -#endif - if ((dev->stat & 0x09) == 0x01) - ret |= (dev->stat & 0x01); if ((ret & 0x81) == 0x80) ret |= 0x08; break; @@ -230,15 +244,12 @@ hercules_write(uint32_t addr, uint8_t val, void *priv) { hercules_t *dev = (hercules_t *)priv; - /* 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 ((addr >= 0xb8000) && ((dev->ctrl2 & 0x03) != 0x03)) - return; + if (dev->ctrl2 & 0x01) + addr &= 0xffff; + else + addr &= 0x0fff; - dev->vram[addr & 0xffff] = val; + dev->vram[addr] = val; hercules_waitstates(dev); } @@ -248,13 +259,18 @@ static uint8_t hercules_read(uint32_t addr, void *priv) { hercules_t *dev = (hercules_t *)priv; + uint8_t ret = 0xff; - if ((addr >= 0xb8000) && ((dev->ctrl2 & 0x03) != 0x03)) - return 0xff; - - return(dev->vram[addr & 0xffff]); + if (dev->ctrl2 & 0x01) + addr &= 0xffff; + else + addr &= 0x0fff; hercules_waitstates(dev); + + ret = dev->vram[addr]; + + return ret; } @@ -282,14 +298,14 @@ hercules_poll(void *priv) if (dev->dispon) { if (dev->displine < dev->firstline) { - dev->firstline = dev->displine; - video_wait_for_buffer(); + dev->firstline = dev->displine; + video_wait_for_buffer(); } dev->lastline = dev->displine; - if ((dev->ctrl & 0x02) && (dev->ctrl2 & 0x01)) { + if (dev->ctrl & 0x02) { ca = (dev->sc & 3) * 0x2000; - if ((dev->ctrl & 0x80) && (dev->ctrl2 & 0x02)) + if (dev->ctrl & 0x80) ca += 0x8000; for (x = 0; x < dev->crtc[1]; x++) { @@ -304,13 +320,12 @@ hercules_poll(void *priv) video_blend((x << 4) + c, dev->displine); } } else { - pa = ((dev->ctrl & 0x80) && (dev->ctrl2 & 0x02)) ? 0x8000 : 0x0000; for (x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) { /* Undocumented behavior: page 1 in text mode means characters are read from page 1 and attributes from page 0. */ - chr = dev->vram[((dev->ma << 1) & 0xfff) + pa]; - attr = dev->vram[((dev->ma << 1) + 1) & 0xfff]; + chr = dev->charbuffer[x << 1]; + attr = dev->charbuffer[(x << 1) + 1]; } else chr = attr = 0; drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); @@ -328,7 +343,10 @@ hercules_poll(void *priv) else 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) { for (c = 0; c < 9; c++) @@ -347,6 +365,9 @@ hercules_poll(void *priv) } else { timer_advance_u64(&dev->timer, dev->dispontime); + if (dev->dispon) + dev->stat &= ~1; + dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; @@ -364,42 +385,51 @@ hercules_poll(void *priv) dev->sc++; dev->sc &= 31; dev->ma = dev->maback; - dev->vadj--; if (! dev->vadj) { dev->dispon = 1; dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; 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->sc = 0; oldvc = dev->vc; dev->vc++; dev->vc &= 127; + if (dev->vc == dev->crtc[6]) dev->dispon = 0; if (oldvc == dev->crtc[4]) { dev->vc = 0; dev->vadj = dev->crtc[5]; - if (! dev->vadj) + if (! dev->vadj) { dev->dispon = 1; - if (! dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - if ((dev->crtc[10] & 0x60) == 0x20) - dev->cursoron = 0; - else - dev->cursoron = dev->blink & 16; + } + switch (dev->crtc[10] & 0x60) { + case 0x20: + 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]) { dev->dispon = 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->ctrl & 2) && (dev->ctrl2 & 1)) - if (dev->ctrl & 2) + if (dev->ctrl & 0x02) x = dev->crtc[1] << 4; else x = dev->crtc[1] * 9; @@ -419,7 +449,8 @@ hercules_poll(void *priv) video_blit_memtoscreen_8(0, dev->firstline, 0, ysize, xsize, ysize); 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_y = dev->crtc[6] * 4; video_bpp = 1; @@ -439,12 +470,15 @@ hercules_poll(void *priv) dev->ma = dev->maback; } - if (dev->dispon) - dev->stat &= ~1; - if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3)==3 && dev->sc == ((dev->crtc[10] & 31) >> 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); - mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, 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, hercules_in,NULL,NULL, hercules_out,NULL,NULL, dev);