diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h index 5ef509830..99fce8a4d 100644 --- a/src/include/86box/m_tandy.h +++ b/src/include/86box/m_tandy.h @@ -36,6 +36,15 @@ typedef struct t1kvid_t { uint8_t planar_ctrl; uint8_t lp_strobe; + uint8_t baseline_hsyncpos; + uint8_t baseline_vsyncpos; + uint8_t last_hdisp; + uint8_t last_vdisp; + int calib_countdown; + int baseline_ready; + int hsync_offset; + int vsync_offset; + int linepos; int displine; int scanline; diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 439ee36fc..d6e391afb 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -125,6 +125,7 @@ extern void cga_recalctimings(cga_t *cga); extern void cga_interpolate_init(void); extern void cga_blit_memtoscreen(int x, int y, int w, int h, int double_type); extern void cga_do_blit(int vid_xsize, int firstline, int lastline, int double_type); +extern void cga_do_blit_tandy(int vid_xsize, int firstline, int lastline, int double_type, int hsync_offset, int vsync_offset); extern void cga_poll(void *priv); //#ifdef EMU_DEVICE_H diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 3bedf53a4..7791d664d 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -545,6 +545,34 @@ cga_do_blit(int vid_xsize, int firstline, int lastline, int double_type) } } +void +cga_do_blit_tandy(int vid_xsize, int firstline, int lastline, int double_type, int hsync_offset, int vsync_offset) +{ + if (double_type > DOUBLE_NONE) { + if (enable_overscan) { + cga_blit_memtoscreen(0 + hsync_offset, ((firstline - 8) << 1) + (vsync_offset << 1), + vid_xsize, ((lastline - firstline) + 16) << 1, + double_type + ); + } else { + cga_blit_memtoscreen(16 + hsync_offset, (firstline << 1) + (vsync_offset << 1), + vid_xsize, (lastline - firstline) << 1, + double_type + ); + } + } else { + if (enable_overscan) { + video_blit_memtoscreen(0 + hsync_offset, (firstline - 8) + vsync_offset, + vid_xsize, (lastline - firstline) + 8 + ); + } else { + video_blit_memtoscreen(16 + hsync_offset, firstline + vsync_offset, + vid_xsize, lastline - firstline + ); + } + } +} + void cga_poll(void *priv) { diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index f11b687ef..0d4daa6fc 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -164,6 +164,47 @@ vid_update_latch(t1kvid_t *vid) vid->crtc[0x11] = lp_latch & 0xff; } +static void +vid_update_display_offset(t1kvid_t *vid) +{ + const int calib_frames = 12; + const int hsync_scale = 16; + const int vsync_scale = 4; + + if (vid->crtc[1] != vid->last_hdisp || vid->crtc[6] != vid->last_vdisp) { + vid->last_hdisp = vid->crtc[1]; + vid->last_vdisp = vid->crtc[6]; + vid->calib_countdown = calib_frames; + vid->baseline_ready = 0; + vid->hsync_offset = 0; + vid->vsync_offset = 0; + return; + } + + if (vid->calib_countdown > 0) { + vid->calib_countdown--; + vid->baseline_hsyncpos = vid->crtc[2]; + vid->baseline_vsyncpos = vid->crtc[7]; + vid->hsync_offset = 0; + vid->vsync_offset = 0; + if (vid->calib_countdown == 0) + vid->baseline_ready = 1; + return; + } + + if (!vid->baseline_ready) { + vid->hsync_offset = 0; + vid->vsync_offset = 0; + return; + } + + int hsync_deviation = (int)vid->baseline_hsyncpos - (int)vid->crtc[2]; + int vsync_deviation = (int)vid->baseline_vsyncpos - (int)vid->crtc[7]; + + vid->hsync_offset = hsync_deviation * hsync_scale; + vid->vsync_offset = vsync_deviation * vsync_scale; +} + void tandy_vid_out(uint16_t addr, uint8_t val, void *priv) { @@ -190,6 +231,7 @@ tandy_vid_out(uint16_t addr, uint8_t val, void *priv) vid->fullchange = changeframecount; recalc_timings(dev); } + vid_update_display_offset(vid); } break; @@ -354,25 +396,25 @@ vid_render(tandy_t *dev, int line) cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < 8; c++) { + for (c = 0; c < 16; c++) { if (vid->array[3] & 4) { buffer32->line[line][c] = cols[0]; if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + 8] = cols[0]; + buffer32->line[line][c + (vid->crtc[1] << 3) + 16] = cols[0]; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 8] = cols[0]; + buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = cols[0]; } else if ((vid->mode & 0x12) == 0x12) { buffer32->line[line][c] = 0; if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + 8] = 0; + buffer32->line[line][c + (vid->crtc[1] << 3) + 16] = 0; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 8] = 0; + buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = 0; } else { buffer32->line[line][c] = buffer32->line[(line) + 1][c] = (vid->col & 15) + 16; if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + buffer32->line[line][c + (vid->crtc[1] << 3) + 16] = (vid->col & 15) + 16; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = (vid->col & 15) + 16; } } @@ -380,23 +422,23 @@ vid_render(tandy_t *dev, int line) for (x = 0; x < vid->crtc[1] * 2; x++) { dat = (vid->vram[(vid->memaddr << 1) & 0xffff] << 8) | vid->vram[((vid->memaddr << 1) + 1) & 0xffff]; vid->memaddr++; - buffer32->line[line][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + 11] = vid->array[(dat & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + 16] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + 17] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + 18] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + 19] = vid->array[(dat & 0xf) + 16] + 16; } } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; vid->memaddr++; - buffer32->line[line][(x << 3) + 8] = buffer32->line[line][(x << 3) + 9] = + buffer32->line[line][(x << 3) + 16] = buffer32->line[line][(x << 3) + 17] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 10] = buffer32->line[line][(x << 3) + 11] = + buffer32->line[line][(x << 3) + 18] = buffer32->line[line][(x << 3) + 19] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 12] = buffer32->line[line][(x << 3) + 13] = + buffer32->line[line][(x << 3) + 20] = buffer32->line[line][(x << 3) + 21] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 14] = buffer32->line[line][(x << 3) + 15] = + buffer32->line[line][(x << 3) + 22] = buffer32->line[line][(x << 3) + 23] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; } } else if (vid->array[3] & 0x10) { /*160x200x16*/ @@ -408,17 +450,17 @@ vid_render(tandy_t *dev, int line) dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; vid->memaddr++; - buffer32->line[line][(x << 4) + 8] = buffer32->line[line][(x << 4) + 9] = - buffer32->line[line][(x << 4) + 10] = buffer32->line[line][(x << 4) + 11] = - vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 4) + 12] = buffer32->line[line][(x << 4) + 13] = - buffer32->line[line][(x << 4) + 14] = buffer32->line[line][(x << 4) + 15] = - vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; buffer32->line[line][(x << 4) + 16] = buffer32->line[line][(x << 4) + 17] = buffer32->line[line][(x << 4) + 18] = buffer32->line[line][(x << 4) + 19] = - vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; buffer32->line[line][(x << 4) + 20] = buffer32->line[line][(x << 4) + 21] = buffer32->line[line][(x << 4) + 22] = buffer32->line[line][(x << 4) + 23] = + vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[line][(x << 4) + 24] = buffer32->line[line][(x << 4) + 25] = + buffer32->line[line][(x << 4) + 26] = buffer32->line[line][(x << 4) + 27] = + vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[line][(x << 4) + 28] = buffer32->line[line][(x << 4) + 29] = + buffer32->line[line][(x << 4) + 30] = buffer32->line[line][(x << 4) + 31] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ @@ -429,7 +471,7 @@ vid_render(tandy_t *dev, int line) for (c = 0; c < 8; c++) { chr = (dat >> 6) & 2; chr |= ((dat >> 15) & 1); - buffer32->line[line][(x << 3) + 8 + c] = + buffer32->line[line][(x << 3) + 16 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } @@ -449,16 +491,16 @@ vid_render(tandy_t *dev, int line) cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; } if (vid->scanline & 8) for (c = 0; c < 8; c++) - buffer32->line[line][(x << 3) + c + 8] = + buffer32->line[line][(x << 3) + c + 16] = ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; else for (c = 0; c < 8; c++) { if (vid->scanline == 8) - buffer32->line[line][(x << 3) + c + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[line][(x << 3) + c + 16] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer32->line[line][(x << 3) + c + 8] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[line][(x << 3) + c + 16] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) for (c = 0; c < 8; c++) - buffer32->line[line][(x << 3) + c + 8] ^= 15; + buffer32->line[line][(x << 3) + c + 16] ^= 15; vid->memaddr++; } } else if (!(vid->mode & 2)) { @@ -477,21 +519,21 @@ vid_render(tandy_t *dev, int line) } vid->memaddr++; if (vid->scanline & 8) for (c = 0; c < 8; c++) - buffer32->line[line][(x << 4) + (c << 1) + 8] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[line][(x << 4) + (c << 1) + 16] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; else for (c = 0; c < 8; c++) { if (vid->scanline == 8) - buffer32->line[line][(x << 4) + (c << 1) + 8] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[line][(x << 4) + (c << 1) + 16] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer32->line[line][(x << 4) + (c << 1) + 8] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[line][(x << 4) + (c << 1) + 16] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) for (c = 0; c < 16; c++) - buffer32->line[line][(x << 4) + c + 8] ^= 15; + buffer32->line[line][(x << 4) + c + 16] ^= 15; } } else if (!(vid->mode & 16)) { cols[0] = (vid->col & 15); @@ -518,8 +560,8 @@ vid_render(tandy_t *dev, int line) vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; vid->memaddr++; for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 4) + (c << 1) + 8] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + buffer32->line[line][(x << 4) + (c << 1) + 16] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = cols[dat >> 14]; dat <<= 2; } } @@ -531,7 +573,7 @@ vid_render(tandy_t *dev, int line) vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; vid->memaddr++; for (c = 0; c < 16; c++) { - buffer32->line[line][(x << 4) + c + 8] = buffer32->line[(line) + 1][(x << 4) + c + 8] = cols[dat >> 15]; + buffer32->line[line][(x << 4) + c + 16] = buffer32->line[(line) + 1][(x << 4) + c + 16] = cols[dat >> 15]; dat <<= 1; } } @@ -545,16 +587,16 @@ vid_render_blank(tandy_t *dev, int line) if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 32, (vid->array[2] & 0xf) + 16); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 32, (vid->array[2] & 0xf) + 16); } else { int cols = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 32, cols); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 32, cols); } } @@ -565,9 +607,9 @@ vid_render_process(tandy_t *dev, int line) int x; if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; + x = (vid->crtc[1] << 3) + 32; else - x = (vid->crtc[1] << 4) + 16; + x = (vid->crtc[1] << 4) + 32; if (!dev->is_sl2 && vid->composite) Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); @@ -704,9 +746,9 @@ vid_poll(void *priv) picint(1 << 5); if (vid->crtc[7]) { if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; + x = (vid->crtc[1] << 3) + 32; else - x = (vid->crtc[1] << 4) + 16; + x = (vid->crtc[1] << 4) + 32; vid->lastline++; xs_temp = x; @@ -718,18 +760,18 @@ vid_poll(void *priv) if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xs_temp -= 16; + xs_temp -= 32; if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { xsize = xs_temp; ysize = ys_temp; - set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + set_screen_size(xsize, ysize + (enable_overscan ? 32 : 0)); if (video_force_resize_get()) video_force_resize_set(0); } - cga_do_blit(xsize, vid->firstline, vid->lastline, vid->double_type); + cga_do_blit_tandy(xsize, vid->firstline, vid->lastline, vid->double_type, vid->hsync_offset, vid->vsync_offset); } frames++; @@ -797,6 +839,14 @@ tandy_vid_init(tandy_t *dev) t1kvid_t *vid; vid = calloc(1, sizeof(t1kvid_t)); + vid->baseline_hsyncpos = 0; + vid->baseline_vsyncpos = 0; + vid->last_hdisp = 0xFF; + vid->last_vdisp = 0xFF; + vid->calib_countdown = 0; + vid->baseline_ready = 0; + vid->hsync_offset = 0; + vid->vsync_offset = 0; vid->memctrl = -1; video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram);