From aa5a7e4079c1be5d3b1936f3811f9b5cf35cf70a Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Tue, 2 Sep 2025 02:02:01 +0300 Subject: [PATCH 01/13] Update tandy shake code for latest master changes --- src/include/86box/m_tandy.h | 9 +++ src/include/86box/vid_cga.h | 1 + src/video/vid_cga.c | 28 +++++++ src/video/vid_tandy.c | 146 ++++++++++++++++++++++++------------ 4 files changed, 136 insertions(+), 48 deletions(-) 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); From 3bd879bf3c24fca1b62433b8c027591a3f90569b Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:05:17 +0300 Subject: [PATCH 02/13] Refactor calibration system - Replace frame-based calibration system with timer-based approach - Replace fixed scaling constants with dynamic video mode-aware calculations - Reduce unnecessary vid_update_display_offset() calls by filtering registers - Introduce dynamic horizontal/vertical scaling calculations - Update rendering pipeline to use dynamic display parameters --- src/include/86box/m_tandy.h | 4 +- src/video/vid_cga.c | 28 ---- src/video/vid_tandy.c | 253 ++++++++++++++++++++++-------------- 3 files changed, 157 insertions(+), 128 deletions(-) diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h index 99fce8a4d..75d917beb 100644 --- a/src/include/86box/m_tandy.h +++ b/src/include/86box/m_tandy.h @@ -38,9 +38,6 @@ typedef struct t1kvid_t { 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; @@ -63,6 +60,7 @@ typedef struct t1kvid_t { uint64_t dispontime; uint64_t dispofftime; pc_timer_t timer; + pc_timer_t calib_timer; int firstline; int lastline; diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 7791d664d..3bedf53a4 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -545,34 +545,6 @@ 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 0d4daa6fc..4b8ee82ad 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -164,31 +164,50 @@ vid_update_latch(t1kvid_t *vid) vid->crtc[0x11] = lp_latch & 0xff; } -static void -vid_update_display_offset(t1kvid_t *vid) +static int +vid_h_scale(t1kvid_t *vid) { - const int calib_frames = 12; - const int hsync_scale = 16; - const int vsync_scale = 4; + int cwidth; - 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->mode & 2) && !(vid->mode & 1) && (vid->array[3] & 0x10)) { /* 160x200 */ + cwidth = 32; + } else if (!(vid->mode & 16) && ((vid->mode & 2) || (vid->mode & 4))) { /* 320x200 + 40 column text */ + cwidth = 16; + } else { /* 640x200 + 80 column text */ + cwidth = 8; } - 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 cwidth; +} + +static void +baseline_calib_start(t1kvid_t *vid) +{ + vid->baseline_ready = 0; + vid->hsync_offset = 0; + vid->vsync_offset = 0; + timer_on_auto(&vid->calib_timer, 100000.0); +} + +static void +baseline_calib_finish(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + + vid->baseline_hsyncpos = vid->crtc[2]; + vid->baseline_vsyncpos = vid->crtc[7]; + vid->baseline_ready = 1; +} + +static void +vid_update_display_offset(t1kvid_t *vid, uint8_t reg) +{ + int hsync_scale = vid_h_scale(vid); + int vsync_scale = vid->crtc[9] + 1; + + if (reg == 1 || reg == 6) { + baseline_calib_start(vid); return; } @@ -196,13 +215,16 @@ vid_update_display_offset(t1kvid_t *vid) vid->hsync_offset = 0; vid->vsync_offset = 0; return; + } else { + switch (reg) { + case 2: + vid->hsync_offset = ((int)vid->baseline_hsyncpos - (int)vid->crtc[2]) * hsync_scale; + break; + case 7: + vid->vsync_offset = ((int)vid->baseline_vsyncpos - (int)vid->crtc[7]) * vsync_scale; + break; + } } - - 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 @@ -231,7 +253,10 @@ tandy_vid_out(uint16_t addr, uint8_t val, void *priv) vid->fullchange = changeframecount; recalc_timings(dev); } - vid_update_display_offset(vid); + if ((vid->crtcreg >= 0x01 && vid->crtcreg <= 0x02) || + (vid->crtcreg >= 0x06 && vid->crtcreg <= 0x07)) { + vid_update_display_offset(vid, vid->crtcreg); + } } break; @@ -381,7 +406,7 @@ vid_read(uint32_t addr, void *priv) } static void -vid_render(tandy_t *dev, int line) +vid_render(tandy_t *dev, int line, int hos_offs) { t1kvid_t *vid = dev->vid; uint16_t cursoraddr = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; @@ -396,25 +421,25 @@ vid_render(tandy_t *dev, int line) cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < 16; c++) { + for (c = 0; c < hos_offs; c++) { if (vid->array[3] & 4) { buffer32->line[line][c] = cols[0]; if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + 16] = cols[0]; + buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = cols[0]; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = cols[0]; + buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = 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) + 16] = 0; + buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = 0; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = 0; + buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = 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) + 16] = (vid->col & 15) + 16; + buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = (vid->col & 15) + 16; else - buffer32->line[line][c + (vid->crtc[1] << 4) + 16] = (vid->col & 15) + 16; + buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = (vid->col & 15) + 16; } } @@ -422,23 +447,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) + 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; + buffer32->line[line][(x << 2) + hos_offs] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + hos_offs + 1] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + hos_offs + 2] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[line][(x << 2) + hos_offs + 3] = 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) + 16] = buffer32->line[line][(x << 3) + 17] = + buffer32->line[line][(x << 3) + hos_offs] = buffer32->line[line][(x << 3) + hos_offs + 1] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 18] = buffer32->line[line][(x << 3) + 19] = + buffer32->line[line][(x << 3) + hos_offs + 2] = buffer32->line[line][(x << 3) + hos_offs + 3] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 20] = buffer32->line[line][(x << 3) + 21] = + buffer32->line[line][(x << 3) + hos_offs + 4] = buffer32->line[line][(x << 3) + hos_offs + 5] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + 22] = buffer32->line[line][(x << 3) + 23] = + buffer32->line[line][(x << 3) + hos_offs + 6] = buffer32->line[line][(x << 3) + hos_offs + 7] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; } } else if (vid->array[3] & 0x10) { /*160x200x16*/ @@ -450,17 +475,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) + 16] = buffer32->line[line][(x << 4) + 17] = - buffer32->line[line][(x << 4) + 18] = buffer32->line[line][(x << 4) + 19] = + buffer32->line[line][(x << 4) + hos_offs] = buffer32->line[line][(x << 4) + hos_offs + 1] = + buffer32->line[line][(x << 4) + hos_offs + 2] = buffer32->line[line][(x << 4) + hos_offs + 3] = 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] = + buffer32->line[line][(x << 4) + hos_offs + 4] = buffer32->line[line][(x << 4) + hos_offs + 5] = + buffer32->line[line][(x << 4) + hos_offs + 6] = buffer32->line[line][(x << 4) + hos_offs + 7] = 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] = + buffer32->line[line][(x << 4) + hos_offs + 8] = buffer32->line[line][(x << 4) + hos_offs + 9] = + buffer32->line[line][(x << 4) + hos_offs + 10] = buffer32->line[line][(x << 4) + hos_offs + 11] = 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] = + buffer32->line[line][(x << 4) + hos_offs + 12] = buffer32->line[line][(x << 4) + hos_offs + 13] = + buffer32->line[line][(x << 4) + hos_offs + 14] = buffer32->line[line][(x << 4) + hos_offs + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ @@ -471,7 +496,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) + 16 + c] = + buffer32->line[line][(x << 3) + hos_offs + c] = vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } @@ -491,16 +516,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 + 16] = + buffer32->line[line][(x << 3) + c + hos_offs] = ((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 + 16] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[line][(x << 3) + c + hos_offs] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer32->line[line][(x << 3) + c + 16] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[line][(x << 3) + c + hos_offs] = 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 + 16] ^= 15; + buffer32->line[line][(x << 3) + c + hos_offs] ^= 15; vid->memaddr++; } } else if (!(vid->mode & 2)) { @@ -519,21 +544,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) + 16] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = + buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = ((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) + 16] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = + buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer32->line[line][(x << 4) + (c << 1) + 16] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = + buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = 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 + 16] ^= 15; + buffer32->line[line][(x << 4) + c + hos_offs] ^= 15; } } else if (!(vid->mode & 16)) { cols[0] = (vid->col & 15); @@ -560,8 +585,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) + 16] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + 16] = cols[dat >> 14]; + buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = + buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = cols[dat >> 14]; dat <<= 2; } } @@ -573,7 +598,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 + 16] = buffer32->line[(line) + 1][(x << 4) + c + 16] = cols[dat >> 15]; + buffer32->line[line][(x << 4) + c + hos_offs] = buffer32->line[(line) + 1][(x << 4) + c + hos_offs] = cols[dat >> 15]; dat <<= 1; } } @@ -581,35 +606,35 @@ vid_render(tandy_t *dev, int line) } static void -vid_render_blank(tandy_t *dev, int line) +vid_render_blank(tandy_t *dev, int line, int hos_offs_tot) { t1kvid_t *vid = dev->vid; if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 32, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_offs_tot, (vid->array[2] & 0xf) + 16); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 32, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_offs_tot, (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) + 32, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_offs_tot, cols); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 32, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_offs_tot, cols); } } static void -vid_render_process(tandy_t *dev, int line) +vid_render_process(tandy_t *dev, int line, int hos_offs_tot) { t1kvid_t *vid = dev->vid; int x; if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 32; + x = (vid->crtc[1] << 3) + hos_offs_tot; else - x = (vid->crtc[1] << 4) + 32; + x = (vid->crtc[1] << 4) + hos_offs_tot; if (!dev->is_sl2 && vid->composite) Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); @@ -628,6 +653,10 @@ vid_poll(void *priv) int oldvc; int scanline_old; int old_ma; + int hscale = vid_h_scale(vid); + int hscale_tot = hscale << 1; + int hos_offs = hscale + vid->hsync_offset; + int hos_offs_tot = hscale_tot + vid->hsync_offset; if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); @@ -636,6 +665,20 @@ vid_poll(void *priv) scanline_old = vid->scanline; if ((vid->crtc[8] & 3) == 3) vid->scanline = (vid->scanline << 1) & 7; + + int border_col; + if (vid->array[3] & 4) { + border_col = (vid->array[2] & 0xf) + 16; + } else { + border_col = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + } + if (vid->double_type > DOUBLE_NONE) { + hline(buffer32, 0, vid->displine << 1, xsize, border_col); + hline(buffer32, 0, (vid->displine << 1) + 1, xsize, border_col); + } else { + hline(buffer32, 0, vid->displine, xsize, border_col); + } + if (vid->dispon) { if (vid->displine < vid->firstline) { vid->firstline = vid->displine; @@ -644,39 +687,39 @@ vid_poll(void *priv) vid->lastline = vid->displine; switch (vid->double_type) { default: - vid_render(dev, vid->displine << 1); - vid_render_blank(dev, (vid->displine << 1) + 1); + vid_render(dev, vid->displine << 1, hos_offs); + vid_render_blank(dev, (vid->displine << 1) + 1, hos_offs_tot); break; case DOUBLE_NONE: - vid_render(dev, vid->displine); + vid_render(dev, vid->displine, hos_offs); break; case DOUBLE_SIMPLE: old_ma = vid->memaddr; - vid_render(dev, vid->displine << 1); + vid_render(dev, vid->displine << 1, hos_offs); vid->memaddr = old_ma; - vid_render(dev, (vid->displine << 1) + 1); + vid_render(dev, (vid->displine << 1) + 1, hos_offs); break; } } else switch (vid->double_type) { default: - vid_render_blank(dev, vid->displine << 1); + vid_render_blank(dev, vid->displine << 1, hos_offs_tot); break; case DOUBLE_NONE: - vid_render_blank(dev, vid->displine); + vid_render_blank(dev, vid->displine, hos_offs_tot); break; case DOUBLE_SIMPLE: - vid_render_blank(dev, vid->displine << 1); - vid_render_blank(dev, (vid->displine << 1) + 1); + vid_render_blank(dev, vid->displine << 1, hos_offs_tot); + vid_render_blank(dev, (vid->displine << 1) + 1, hos_offs_tot); break; } switch (vid->double_type) { default: - vid_render_process(dev, vid->displine << 1); - vid_render_process(dev, (vid->displine << 1) + 1); + vid_render_process(dev, vid->displine << 1, hos_offs_tot); + vid_render_process(dev, (vid->displine << 1) + 1, hos_offs_tot); break; case DOUBLE_NONE: - vid_render_process(dev, vid->displine); + vid_render_process(dev, vid->displine, hos_offs_tot); break; } @@ -746,9 +789,9 @@ vid_poll(void *priv) picint(1 << 5); if (vid->crtc[7]) { if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 32; + x = (vid->crtc[1] << 3) + hscale_tot; else - x = (vid->crtc[1] << 4) + 32; + x = (vid->crtc[1] << 4) + hscale_tot; vid->lastline++; xs_temp = x; @@ -760,20 +803,35 @@ vid_poll(void *priv) if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xs_temp -= 32; + xs_temp -= hscale_tot; if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { xsize = xs_temp; ysize = ys_temp; - set_screen_size(xsize, ysize + (enable_overscan ? 32 : 0)); + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); if (video_force_resize_get()) video_force_resize_set(0); } - cga_do_blit_tandy(xsize, vid->firstline, vid->lastline, vid->double_type, vid->hsync_offset, vid->vsync_offset); + if (vid->double_type > DOUBLE_NONE) { + if (enable_overscan) + cga_blit_memtoscreen(0, ((vid->firstline - 4) << 1) - (vid->vsync_offset << 1), + xsize, ((vid->lastline - vid->firstline) << 1) + 16, + vid->double_type); + else + cga_blit_memtoscreen(hscale, (vid->firstline << 1) - (vid->vsync_offset << 1), + xsize, (vid->lastline - vid->firstline) << 1, + vid->double_type); + } else { + if (enable_overscan) + video_blit_memtoscreen(0, (vid->firstline - 4) - vid->vsync_offset, + xsize, (vid->lastline - vid->firstline) + 8); + else + video_blit_memtoscreen(hscale, vid->firstline - vid->vsync_offset, + xsize, vid->lastline - vid->firstline); + } } - frames++; video_res_x = xsize; @@ -828,6 +886,8 @@ tandy_vid_close(void *priv) { tandy_t *dev = (tandy_t *) priv; + timer_on_auto(&dev->vid->calib_timer, 0.0); + free(dev->vid); dev->vid = NULL; } @@ -841,9 +901,6 @@ tandy_vid_init(tandy_t *dev) 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; @@ -859,13 +916,15 @@ tandy_vid_init(tandy_t *dev) if (dev->is_sl2) { vid->b8000_limit = 0x8000; vid->planar_ctrl = 4; - overscan_x = overscan_y = 16; + overscan_x = vid_h_scale(vid) << 1; + overscan_y = 16; io_sethandler(0x0065, 1, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); } else vid->b8000_mask = 0x3fff; timer_add(&vid->timer, vid_poll, dev, 1); + timer_add(&vid->calib_timer, baseline_calib_finish, dev, 0); mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); io_sethandler(0x03d0, 16, From bea5a6ff1b9979ecba3058888c78a5dac5399b56 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Wed, 17 Sep 2025 10:16:56 +0300 Subject: [PATCH 03/13] Fix border rendering issues, add boolean type support, and improve variable/function naming --- src/include/86box/m_tandy.h | 2 +- src/include/86box/vid_cga.h | 1 - src/video/vid_tandy.c | 113 ++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h index 75d917beb..e8cfbae15 100644 --- a/src/include/86box/m_tandy.h +++ b/src/include/86box/m_tandy.h @@ -38,7 +38,7 @@ typedef struct t1kvid_t { uint8_t baseline_hsyncpos; uint8_t baseline_vsyncpos; - int baseline_ready; + bool baseline_ready; int hsync_offset; int vsync_offset; diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index d6e391afb..439ee36fc 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -125,7 +125,6 @@ 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_tandy.c b/src/video/vid_tandy.c index 4b8ee82ad..a26c1c38a 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -18,6 +18,7 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2025 starfrost */ +#include #include #include #include @@ -165,25 +166,21 @@ vid_update_latch(t1kvid_t *vid) } static int -vid_h_scale(t1kvid_t *vid) +vid_get_char_width(t1kvid_t *vid) { - int cwidth; - - if ((vid->mode & 2) && !(vid->mode & 1) && (vid->array[3] & 0x10)) { /* 160x200 */ - cwidth = 32; - } else if (!(vid->mode & 16) && ((vid->mode & 2) || (vid->mode & 4))) { /* 320x200 + 40 column text */ - cwidth = 16; - } else { /* 640x200 + 80 column text */ - cwidth = 8; + if ((vid->mode & 2) && !(vid->mode & 1) && (vid->array[3] & 0x10)) { /*160x200*/ + return 32; + } else if (!(vid->mode & 16) && ((vid->mode & 2) || (vid->mode & 4))) { /*320x200 + 40-column text*/ + return 16; + } else { /*640x200 + 80-column text*/ + return 8; } - - return cwidth; } static void baseline_calib_start(t1kvid_t *vid) { - vid->baseline_ready = 0; + vid->baseline_ready = false; vid->hsync_offset = 0; vid->vsync_offset = 0; timer_on_auto(&vid->calib_timer, 100000.0); @@ -197,13 +194,13 @@ baseline_calib_finish(void *priv) vid->baseline_hsyncpos = vid->crtc[2]; vid->baseline_vsyncpos = vid->crtc[7]; - vid->baseline_ready = 1; + vid->baseline_ready = true; } static void vid_update_display_offset(t1kvid_t *vid, uint8_t reg) { - int hsync_scale = vid_h_scale(vid); + int hsync_scale = vid_get_char_width(vid); int vsync_scale = vid->crtc[9] + 1; if (reg == 1 || reg == 6) { @@ -406,7 +403,7 @@ vid_read(uint32_t addr, void *priv) } static void -vid_render(tandy_t *dev, int line, int hos_offs) +vid_render(tandy_t *dev, int line, int hos, int hos_offs) { t1kvid_t *vid = dev->vid; uint16_t cursoraddr = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; @@ -424,18 +421,25 @@ vid_render(tandy_t *dev, int line, int hos_offs) for (c = 0; c < hos_offs; c++) { if (vid->array[3] & 4) { buffer32->line[line][c] = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + buffer32->line[line][c] = 0; + } else { + buffer32->line[line][c] = buffer32->line[(line) + 1][c] = (vid->col & 15) + 16; + } + } + + for (c = 0; c < hos - vid->hsync_offset; c++) { + if (vid->array[3] & 4) { if (vid->mode & 1) buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = cols[0]; else buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = 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) + hos_offs] = 0; else buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = 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) + hos_offs] = (vid->col & 15) + 16; else @@ -606,35 +610,35 @@ vid_render(tandy_t *dev, int line, int hos_offs) } static void -vid_render_blank(tandy_t *dev, int line, int hos_offs_tot) +vid_render_blank(tandy_t *dev, int line, int hos_tot) { t1kvid_t *vid = dev->vid; if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_offs_tot, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_tot, (vid->array[2] & 0xf) + 16); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_offs_tot, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_tot, (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) + hos_offs_tot, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_tot, cols); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_offs_tot, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_tot, cols); } } static void -vid_render_process(tandy_t *dev, int line, int hos_offs_tot) +vid_render_process(tandy_t *dev, int line, int hos_tot) { t1kvid_t *vid = dev->vid; int x; if (vid->mode & 1) - x = (vid->crtc[1] << 3) + hos_offs_tot; + x = (vid->crtc[1] << 3) + hos_tot; else - x = (vid->crtc[1] << 4) + hos_offs_tot; + x = (vid->crtc[1] << 4) + hos_tot; if (!dev->is_sl2 && vid->composite) Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); @@ -653,10 +657,9 @@ vid_poll(void *priv) int oldvc; int scanline_old; int old_ma; - int hscale = vid_h_scale(vid); - int hscale_tot = hscale << 1; - int hos_offs = hscale + vid->hsync_offset; - int hos_offs_tot = hscale_tot + vid->hsync_offset; + int hos = vid_get_char_width(vid); + int hos_tot = hos << 1; + int hos_offs = hos + vid->hsync_offset; if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); @@ -665,20 +668,6 @@ vid_poll(void *priv) scanline_old = vid->scanline; if ((vid->crtc[8] & 3) == 3) vid->scanline = (vid->scanline << 1) & 7; - - int border_col; - if (vid->array[3] & 4) { - border_col = (vid->array[2] & 0xf) + 16; - } else { - border_col = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; - } - if (vid->double_type > DOUBLE_NONE) { - hline(buffer32, 0, vid->displine << 1, xsize, border_col); - hline(buffer32, 0, (vid->displine << 1) + 1, xsize, border_col); - } else { - hline(buffer32, 0, vid->displine, xsize, border_col); - } - if (vid->dispon) { if (vid->displine < vid->firstline) { vid->firstline = vid->displine; @@ -687,39 +676,39 @@ vid_poll(void *priv) vid->lastline = vid->displine; switch (vid->double_type) { default: - vid_render(dev, vid->displine << 1, hos_offs); - vid_render_blank(dev, (vid->displine << 1) + 1, hos_offs_tot); + vid_render(dev, vid->displine << 1, hos, hos_offs); + vid_render_blank(dev, (vid->displine << 1) + 1, hos_tot); break; case DOUBLE_NONE: - vid_render(dev, vid->displine, hos_offs); + vid_render(dev, vid->displine, hos, hos_offs); break; case DOUBLE_SIMPLE: old_ma = vid->memaddr; - vid_render(dev, vid->displine << 1, hos_offs); + vid_render(dev, vid->displine << 1, hos, hos_offs); vid->memaddr = old_ma; - vid_render(dev, (vid->displine << 1) + 1, hos_offs); + vid_render(dev, (vid->displine << 1) + 1, hos, hos_offs); break; } } else switch (vid->double_type) { default: - vid_render_blank(dev, vid->displine << 1, hos_offs_tot); + vid_render_blank(dev, vid->displine << 1, hos_tot); break; case DOUBLE_NONE: - vid_render_blank(dev, vid->displine, hos_offs_tot); + vid_render_blank(dev, vid->displine, hos_tot); break; case DOUBLE_SIMPLE: - vid_render_blank(dev, vid->displine << 1, hos_offs_tot); - vid_render_blank(dev, (vid->displine << 1) + 1, hos_offs_tot); + vid_render_blank(dev, vid->displine << 1, hos_tot); + vid_render_blank(dev, (vid->displine << 1) + 1, hos_tot); break; } switch (vid->double_type) { default: - vid_render_process(dev, vid->displine << 1, hos_offs_tot); - vid_render_process(dev, (vid->displine << 1) + 1, hos_offs_tot); + vid_render_process(dev, vid->displine << 1, hos_tot); + vid_render_process(dev, (vid->displine << 1) + 1, hos_tot); break; case DOUBLE_NONE: - vid_render_process(dev, vid->displine, hos_offs_tot); + vid_render_process(dev, vid->displine, hos_tot); break; } @@ -789,9 +778,9 @@ vid_poll(void *priv) picint(1 << 5); if (vid->crtc[7]) { if (vid->mode & 1) - x = (vid->crtc[1] << 3) + hscale_tot; + x = (vid->crtc[1] << 3) + hos_tot; else - x = (vid->crtc[1] << 4) + hscale_tot; + x = (vid->crtc[1] << 4) + hos_tot; vid->lastline++; xs_temp = x; @@ -803,7 +792,7 @@ vid_poll(void *priv) if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xs_temp -= hscale_tot; + xs_temp -= hos_tot; if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { xsize = xs_temp; @@ -820,7 +809,7 @@ vid_poll(void *priv) xsize, ((vid->lastline - vid->firstline) << 1) + 16, vid->double_type); else - cga_blit_memtoscreen(hscale, (vid->firstline << 1) - (vid->vsync_offset << 1), + cga_blit_memtoscreen(hos, (vid->firstline << 1) - (vid->vsync_offset << 1), xsize, (vid->lastline - vid->firstline) << 1, vid->double_type); } else { @@ -828,7 +817,7 @@ vid_poll(void *priv) video_blit_memtoscreen(0, (vid->firstline - 4) - vid->vsync_offset, xsize, (vid->lastline - vid->firstline) + 8); else - video_blit_memtoscreen(hscale, vid->firstline - vid->vsync_offset, + video_blit_memtoscreen(hos, vid->firstline - vid->vsync_offset, xsize, vid->lastline - vid->firstline); } } @@ -901,7 +890,7 @@ tandy_vid_init(tandy_t *dev) vid = calloc(1, sizeof(t1kvid_t)); vid->baseline_hsyncpos = 0; vid->baseline_vsyncpos = 0; - vid->baseline_ready = 0; + vid->baseline_ready = false; vid->hsync_offset = 0; vid->vsync_offset = 0; vid->memctrl = -1; @@ -916,7 +905,7 @@ tandy_vid_init(tandy_t *dev) if (dev->is_sl2) { vid->b8000_limit = 0x8000; vid->planar_ctrl = 4; - overscan_x = vid_h_scale(vid) << 1; + overscan_x = vid_get_char_width(vid) << 1; overscan_y = 16; io_sethandler(0x0065, 1, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); From 83f729e46c609c98ef0a364f432f7c7b2a3f8b0b Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Fri, 19 Sep 2025 10:41:21 +0300 Subject: [PATCH 04/13] Replace dynamic horizontal overscan with fixed constants, fix character clock width calculation and remove vid_get_char_width() --- src/video/vid_tandy.c | 76 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index a26c1c38a..602b7d0d9 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -27,6 +27,8 @@ #include #include #define HAVE_STDARG_H +#define HOS 16 +#define HOS_SIDE 8 #include <86box/86box.h> #include <86box/timer.h> #include <86box/io.h> @@ -165,18 +167,6 @@ vid_update_latch(t1kvid_t *vid) vid->crtc[0x11] = lp_latch & 0xff; } -static int -vid_get_char_width(t1kvid_t *vid) -{ - if ((vid->mode & 2) && !(vid->mode & 1) && (vid->array[3] & 0x10)) { /*160x200*/ - return 32; - } else if (!(vid->mode & 16) && ((vid->mode & 2) || (vid->mode & 4))) { /*320x200 + 40-column text*/ - return 16; - } else { /*640x200 + 80-column text*/ - return 8; - } -} - static void baseline_calib_start(t1kvid_t *vid) { @@ -200,7 +190,7 @@ baseline_calib_finish(void *priv) static void vid_update_display_offset(t1kvid_t *vid, uint8_t reg) { - int hsync_scale = vid_get_char_width(vid); + int hsync_scale = (vid->mode & 1) ? 8 : 16; int vsync_scale = vid->crtc[9] + 1; if (reg == 1 || reg == 6) { @@ -403,7 +393,7 @@ vid_read(uint32_t addr, void *priv) } static void -vid_render(tandy_t *dev, int line, int hos, int hos_offs) +vid_render(tandy_t *dev, int line, int hos_offs) { t1kvid_t *vid = dev->vid; uint16_t cursoraddr = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; @@ -428,7 +418,7 @@ vid_render(tandy_t *dev, int line, int hos, int hos_offs) } } - for (c = 0; c < hos - vid->hsync_offset; c++) { + for (c = 0; c < HOS_SIDE - vid->hsync_offset; c++) { if (vid->array[3] & 4) { if (vid->mode & 1) buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = cols[0]; @@ -610,35 +600,35 @@ vid_render(tandy_t *dev, int line, int hos, int hos_offs) } static void -vid_render_blank(tandy_t *dev, int line, int hos_tot) +vid_render_blank(tandy_t *dev, int line) { t1kvid_t *vid = dev->vid; if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + hos_tot, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + HOS, (vid->array[2] & 0xf) + 16); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_tot, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + HOS, (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) + hos_tot, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + HOS, cols); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + hos_tot, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + HOS, cols); } } static void -vid_render_process(tandy_t *dev, int line, int hos_tot) +vid_render_process(tandy_t *dev, int line) { t1kvid_t *vid = dev->vid; int x; if (vid->mode & 1) - x = (vid->crtc[1] << 3) + hos_tot; + x = (vid->crtc[1] << 3) + HOS; else - x = (vid->crtc[1] << 4) + hos_tot; + x = (vid->crtc[1] << 4) + HOS; if (!dev->is_sl2 && vid->composite) Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); @@ -657,9 +647,7 @@ vid_poll(void *priv) int oldvc; int scanline_old; int old_ma; - int hos = vid_get_char_width(vid); - int hos_tot = hos << 1; - int hos_offs = hos + vid->hsync_offset; + int hos_offs = HOS_SIDE + vid->hsync_offset; if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); @@ -676,39 +664,39 @@ vid_poll(void *priv) vid->lastline = vid->displine; switch (vid->double_type) { default: - vid_render(dev, vid->displine << 1, hos, hos_offs); - vid_render_blank(dev, (vid->displine << 1) + 1, hos_tot); + vid_render(dev, vid->displine << 1, hos_offs); + vid_render_blank(dev, (vid->displine << 1) + 1); break; case DOUBLE_NONE: - vid_render(dev, vid->displine, hos, hos_offs); + vid_render(dev, vid->displine, hos_offs); break; case DOUBLE_SIMPLE: old_ma = vid->memaddr; - vid_render(dev, vid->displine << 1, hos, hos_offs); + vid_render(dev, vid->displine << 1, hos_offs); vid->memaddr = old_ma; - vid_render(dev, (vid->displine << 1) + 1, hos, hos_offs); + vid_render(dev, (vid->displine << 1) + 1, hos_offs); break; } } else switch (vid->double_type) { default: - vid_render_blank(dev, vid->displine << 1, hos_tot); + vid_render_blank(dev, vid->displine << 1); break; case DOUBLE_NONE: - vid_render_blank(dev, vid->displine, hos_tot); + vid_render_blank(dev, vid->displine); break; case DOUBLE_SIMPLE: - vid_render_blank(dev, vid->displine << 1, hos_tot); - vid_render_blank(dev, (vid->displine << 1) + 1, hos_tot); + vid_render_blank(dev, vid->displine << 1); + vid_render_blank(dev, (vid->displine << 1) + 1); break; } switch (vid->double_type) { default: - vid_render_process(dev, vid->displine << 1, hos_tot); - vid_render_process(dev, (vid->displine << 1) + 1, hos_tot); + vid_render_process(dev, vid->displine << 1); + vid_render_process(dev, (vid->displine << 1) + 1); break; case DOUBLE_NONE: - vid_render_process(dev, vid->displine, hos_tot); + vid_render_process(dev, vid->displine); break; } @@ -778,9 +766,9 @@ vid_poll(void *priv) picint(1 << 5); if (vid->crtc[7]) { if (vid->mode & 1) - x = (vid->crtc[1] << 3) + hos_tot; + x = (vid->crtc[1] << 3) + HOS; else - x = (vid->crtc[1] << 4) + hos_tot; + x = (vid->crtc[1] << 4) + HOS; vid->lastline++; xs_temp = x; @@ -792,7 +780,7 @@ vid_poll(void *priv) if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xs_temp -= hos_tot; + xs_temp -= HOS; if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { xsize = xs_temp; @@ -809,7 +797,7 @@ vid_poll(void *priv) xsize, ((vid->lastline - vid->firstline) << 1) + 16, vid->double_type); else - cga_blit_memtoscreen(hos, (vid->firstline << 1) - (vid->vsync_offset << 1), + cga_blit_memtoscreen(HOS_SIDE, (vid->firstline << 1) - (vid->vsync_offset << 1), xsize, (vid->lastline - vid->firstline) << 1, vid->double_type); } else { @@ -817,7 +805,7 @@ vid_poll(void *priv) video_blit_memtoscreen(0, (vid->firstline - 4) - vid->vsync_offset, xsize, (vid->lastline - vid->firstline) + 8); else - video_blit_memtoscreen(hos, vid->firstline - vid->vsync_offset, + video_blit_memtoscreen(HOS_SIDE, vid->firstline - vid->vsync_offset, xsize, vid->lastline - vid->firstline); } } @@ -905,7 +893,7 @@ tandy_vid_init(tandy_t *dev) if (dev->is_sl2) { vid->b8000_limit = 0x8000; vid->planar_ctrl = 4; - overscan_x = vid_get_char_width(vid) << 1; + overscan_x = HOS_SIDE; overscan_y = 16; io_sethandler(0x0065, 1, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); From aa7cb72c933cadaa0319b2651958aeeeae3557f0 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:42:17 +0300 Subject: [PATCH 05/13] Apply vsync_offset during scanline rendering instead of the final blit; clean up code --- src/video/vid_tandy.c | 88 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 602b7d0d9..978a03c8d 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -27,8 +27,6 @@ #include #include #define HAVE_STDARG_H -#define HOS 16 -#define HOS_SIDE 8 #include <86box/86box.h> #include <86box/timer.h> #include <86box/io.h> @@ -418,7 +416,7 @@ vid_render(tandy_t *dev, int line, int hos_offs) } } - for (c = 0; c < HOS_SIDE - vid->hsync_offset; c++) { + for (c = 0; c < 8 - vid->hsync_offset; c++) { if (vid->array[3] & 4) { if (vid->mode & 1) buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = cols[0]; @@ -606,16 +604,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) + HOS, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + HOS, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (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) + HOS, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, cols); else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + HOS, cols); + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); } } @@ -626,9 +624,9 @@ vid_render_process(tandy_t *dev, int line) int x; if (vid->mode & 1) - x = (vid->crtc[1] << 3) + HOS; + x = (vid->crtc[1] << 3) + 16; else - x = (vid->crtc[1] << 4) + HOS; + x = (vid->crtc[1] << 4) + 16; if (!dev->is_sl2 && vid->composite) Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); @@ -647,7 +645,9 @@ vid_poll(void *priv) int oldvc; int scanline_old; int old_ma; - int hos_offs = HOS_SIDE + vid->hsync_offset; + int hos_offs = 8 + vid->hsync_offset; + int displine_offs = vid->displine - vid->vsync_offset; + int displine_offs_double = (vid->displine << 1) - (vid->vsync_offset << 1); if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); @@ -664,39 +664,51 @@ vid_poll(void *priv) vid->lastline = vid->displine; switch (vid->double_type) { default: - vid_render(dev, vid->displine << 1, hos_offs); - vid_render_blank(dev, (vid->displine << 1) + 1); + if (displine_offs_double >= 0) { + vid_render(dev, displine_offs_double, hos_offs); + vid_render_blank(dev, displine_offs_double + 1); + } break; case DOUBLE_NONE: - vid_render(dev, vid->displine, hos_offs); + if (displine_offs >= 0) + vid_render(dev, displine_offs, hos_offs); break; case DOUBLE_SIMPLE: - old_ma = vid->memaddr; - vid_render(dev, vid->displine << 1, hos_offs); - vid->memaddr = old_ma; - vid_render(dev, (vid->displine << 1) + 1, hos_offs); + if (displine_offs_double >= 0) { + old_ma = vid->memaddr; + vid_render(dev, displine_offs_double, hos_offs); + vid->memaddr = old_ma; + vid_render(dev, displine_offs_double + 1, hos_offs); + } break; } } else switch (vid->double_type) { default: - vid_render_blank(dev, vid->displine << 1); + if (displine_offs_double >= 0) + vid_render_blank(dev, displine_offs_double); break; case DOUBLE_NONE: - vid_render_blank(dev, vid->displine); + if (displine_offs >= 0) + vid_render_blank(dev, displine_offs); break; case DOUBLE_SIMPLE: - vid_render_blank(dev, vid->displine << 1); - vid_render_blank(dev, (vid->displine << 1) + 1); + if (displine_offs_double >= 0) { + vid_render_blank(dev, displine_offs_double); + vid_render_blank(dev, displine_offs_double + 1); + } break; } switch (vid->double_type) { default: - vid_render_process(dev, vid->displine << 1); - vid_render_process(dev, (vid->displine << 1) + 1); + if (displine_offs_double >= 0) { + vid_render_process(dev, displine_offs_double); + vid_render_process(dev, displine_offs_double + 1); + } break; case DOUBLE_NONE: - vid_render_process(dev, vid->displine); + if (displine_offs >= 0) + vid_render_process(dev, displine_offs); break; } @@ -766,9 +778,9 @@ vid_poll(void *priv) picint(1 << 5); if (vid->crtc[7]) { if (vid->mode & 1) - x = (vid->crtc[1] << 3) + HOS; + x = (vid->crtc[1] << 3) + 16; else - x = (vid->crtc[1] << 4) + HOS; + x = (vid->crtc[1] << 4) + 16; vid->lastline++; xs_temp = x; @@ -780,7 +792,7 @@ vid_poll(void *priv) if (ys_temp < 32) ys_temp = 400; if (!enable_overscan) - xs_temp -= HOS; + xs_temp -= 16; if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { xsize = xs_temp; @@ -791,24 +803,9 @@ vid_poll(void *priv) video_force_resize_set(0); } - if (vid->double_type > DOUBLE_NONE) { - if (enable_overscan) - cga_blit_memtoscreen(0, ((vid->firstline - 4) << 1) - (vid->vsync_offset << 1), - xsize, ((vid->lastline - vid->firstline) << 1) + 16, - vid->double_type); - else - cga_blit_memtoscreen(HOS_SIDE, (vid->firstline << 1) - (vid->vsync_offset << 1), - xsize, (vid->lastline - vid->firstline) << 1, - vid->double_type); - } else { - if (enable_overscan) - video_blit_memtoscreen(0, (vid->firstline - 4) - vid->vsync_offset, - xsize, (vid->lastline - vid->firstline) + 8); - else - video_blit_memtoscreen(HOS_SIDE, vid->firstline - vid->vsync_offset, - xsize, vid->lastline - vid->firstline); - } + cga_do_blit(xsize, vid->firstline, vid->lastline, vid->double_type); } + frames++; video_res_x = xsize; @@ -893,8 +890,7 @@ tandy_vid_init(tandy_t *dev) if (dev->is_sl2) { vid->b8000_limit = 0x8000; vid->planar_ctrl = 4; - overscan_x = HOS_SIDE; - overscan_y = 16; + overscan_x = overscan_y = 16; io_sethandler(0x0065, 1, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); } else From 3e7b3d32e85d7626d28a7929c9be214b4e3b1499 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:57:10 +0300 Subject: [PATCH 06/13] Separate baseline calibration trigger from display offset updates, clamp crtc[7] position to valid range and use calibrated baseline_vsyncpos for vsync comparison to avoid display issues when overscan in enabled --- src/video/vid_tandy.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 978a03c8d..d680aba17 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -191,11 +191,6 @@ vid_update_display_offset(t1kvid_t *vid, uint8_t reg) int hsync_scale = (vid->mode & 1) ? 8 : 16; int vsync_scale = vid->crtc[9] + 1; - if (reg == 1 || reg == 6) { - baseline_calib_start(vid); - return; - } - if (!vid->baseline_ready) { vid->hsync_offset = 0; vid->vsync_offset = 0; @@ -206,6 +201,10 @@ vid_update_display_offset(t1kvid_t *vid, uint8_t reg) vid->hsync_offset = ((int)vid->baseline_hsyncpos - (int)vid->crtc[2]) * hsync_scale; break; case 7: + if (vid->crtc[7] < vid->crtc[6]) + vid->crtc[7] = vid->crtc[6]; + else if (vid->crtc[7] > vid->crtc[4]) + vid->crtc[7] = vid->crtc[4]; vid->vsync_offset = ((int)vid->baseline_vsyncpos - (int)vid->crtc[7]) * vsync_scale; break; } @@ -238,10 +237,10 @@ tandy_vid_out(uint16_t addr, uint8_t val, void *priv) vid->fullchange = changeframecount; recalc_timings(dev); } - if ((vid->crtcreg >= 0x01 && vid->crtcreg <= 0x02) || - (vid->crtcreg >= 0x06 && vid->crtcreg <= 0x07)) { + if (vid->crtcreg == 0x01 || vid->crtcreg == 0x06) + baseline_calib_start(vid); + if (vid->crtcreg == 0x02 || vid->crtcreg == 0x07) vid_update_display_offset(vid, vid->crtcreg); - } } break; @@ -771,7 +770,7 @@ vid_poll(void *priv) else vid->cursoron = vid->blink & 16; } - if (vid->vc == vid->crtc[7]) { + if (vid->vc == vid->baseline_vsyncpos) { vid->dispon = 0; vid->displine = 0; vid->vsynctime = 16; From beb373375795bda97d8531c1d56cb4633fe76b82 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:44:53 +0300 Subject: [PATCH 07/13] Defer vsync_offset application - Apply vsync_offset only during the vertical retrace period for a more accurate result - Change the calculation of displine_offs and remove redundant checks around rendering calls - Remove unnecessary clamping logic for crtc[7] - Remove a hack from the previous commit by correctly triggering VSYNC processing when the vertical counter matches the actual crtc[7] --- src/include/86box/m_tandy.h | 1 + src/video/vid_tandy.c | 54 ++++++++++++++----------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h index e8cfbae15..550801687 100644 --- a/src/include/86box/m_tandy.h +++ b/src/include/86box/m_tandy.h @@ -41,6 +41,7 @@ typedef struct t1kvid_t { bool baseline_ready; int hsync_offset; int vsync_offset; + int vsync_offset_pending; int linepos; int displine; diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 09fec5052..4244c3309 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -199,11 +199,7 @@ vid_update_display_offset(t1kvid_t *vid, uint8_t reg) vid->hsync_offset = ((int)vid->baseline_hsyncpos - (int)vid->crtc[2]) * hsync_scale; break; case 7: - if (vid->crtc[7] < vid->crtc[6]) - vid->crtc[7] = vid->crtc[6]; - else if (vid->crtc[7] > vid->crtc[4]) - vid->crtc[7] = vid->crtc[4]; - vid->vsync_offset = ((int)vid->baseline_vsyncpos - (int)vid->crtc[7]) * vsync_scale; + vid->vsync_offset_pending = ((int)vid->baseline_vsyncpos - (int)vid->crtc[7]) * vsync_scale; break; } } @@ -643,8 +639,8 @@ vid_poll(void *priv) int scanline_old; int old_ma; int hos_offs = 8 + vid->hsync_offset; - int displine_offs = vid->displine - vid->vsync_offset; - int displine_offs_double = (vid->displine << 1) - (vid->vsync_offset << 1); + int displine_offs = (vid->displine + vid->vsync_offset < 0) ? 0 : vid->displine + vid->vsync_offset; + int displine_offs_double = displine_offs << 1; if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); @@ -661,51 +657,39 @@ vid_poll(void *priv) vid->lastline = vid->displine; switch (vid->double_type) { default: - if (displine_offs_double >= 0) { - vid_render(dev, displine_offs_double, hos_offs); - vid_render_blank(dev, displine_offs_double + 1); - } + vid_render(dev, displine_offs_double, hos_offs); + vid_render_blank(dev, displine_offs_double + 1); break; case DOUBLE_NONE: - if (displine_offs >= 0) - vid_render(dev, displine_offs, hos_offs); + vid_render(dev, displine_offs, hos_offs); break; case DOUBLE_SIMPLE: - if (displine_offs_double >= 0) { - old_ma = vid->memaddr; - vid_render(dev, displine_offs_double, hos_offs); - vid->memaddr = old_ma; - vid_render(dev, displine_offs_double + 1, hos_offs); - } + old_ma = vid->memaddr; + vid_render(dev, displine_offs_double, hos_offs); + vid->memaddr = old_ma; + vid_render(dev, displine_offs_double + 1, hos_offs); break; } } else switch (vid->double_type) { default: - if (displine_offs_double >= 0) - vid_render_blank(dev, displine_offs_double); + vid_render_blank(dev, displine_offs_double); break; case DOUBLE_NONE: - if (displine_offs >= 0) - vid_render_blank(dev, displine_offs); + vid_render_blank(dev, displine_offs); break; case DOUBLE_SIMPLE: - if (displine_offs_double >= 0) { - vid_render_blank(dev, displine_offs_double); - vid_render_blank(dev, displine_offs_double + 1); - } + vid_render_blank(dev, displine_offs_double); + vid_render_blank(dev, displine_offs_double + 1); break; } switch (vid->double_type) { default: - if (displine_offs_double >= 0) { - vid_render_process(dev, displine_offs_double); - vid_render_process(dev, displine_offs_double + 1); - } + vid_render_process(dev, displine_offs_double); + vid_render_process(dev, displine_offs_double + 1); break; case DOUBLE_NONE: - if (displine_offs >= 0) - vid_render_process(dev, displine_offs); + vid_render_process(dev, displine_offs); break; } @@ -768,7 +752,8 @@ vid_poll(void *priv) else vid->cursoron = vid->blink & 16; } - if (vid->vc == vid->baseline_vsyncpos) { + if (vid->vc == vid->crtc[7]) { + vid->vsync_offset = vid->vsync_offset_pending; vid->dispon = 0; vid->displine = 0; vid->vsynctime = 16; @@ -875,6 +860,7 @@ tandy_vid_init(tandy_t *dev) vid->baseline_ready = false; vid->hsync_offset = 0; vid->vsync_offset = 0; + vid->vsync_offset_pending = 0; vid->memctrl = -1; video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); From 362e7a9ffdc753b3f2fc83faf12a348c5c4da873 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Sun, 5 Oct 2025 20:34:54 +0300 Subject: [PATCH 08/13] Add bounds checking for negative line and horizontal coordinates in the rendering functions --- src/video/vid_tandy.c | 223 ++++++++++++++++++++++++------------------ 1 file changed, 130 insertions(+), 93 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 4244c3309..c3737eba3 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -396,35 +396,36 @@ vid_render(tandy_t *dev, int line, int hos_offs) uint16_t dat; int col; int cols[4]; + int out_x; cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < hos_offs; c++) { - if (vid->array[3] & 4) { - buffer32->line[line][c] = cols[0]; - } else if ((vid->mode & 0x12) == 0x12) { - buffer32->line[line][c] = 0; - } else { - buffer32->line[line][c] = buffer32->line[(line) + 1][c] = (vid->col & 15) + 16; + if (line >= 0) { + for (c = 0; c < hos_offs; c++) { + if (vid->array[3] & 4) { + buffer32->line[line][c] = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + buffer32->line[line][c] = 0; + } else { + buffer32->line[line][c] = buffer32->line[(line) + 1][c] = (vid->col & 15) + 16; + } } - } - for (c = 0; c < 8 - vid->hsync_offset; c++) { - if (vid->array[3] & 4) { + for (c = 0; c < 8 - vid->hsync_offset; c++) { if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = cols[0]; + out_x = c + (vid->crtc[1] << 3) + hos_offs; else - buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = cols[0]; - } else if ((vid->mode & 0x12) == 0x12) { - if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = 0; - else - buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = 0; - } else { - if (vid->mode & 1) - buffer32->line[line][c + (vid->crtc[1] << 3) + hos_offs] = (vid->col & 15) + 16; - else - buffer32->line[line][c + (vid->crtc[1] << 4) + hos_offs] = (vid->col & 15) + 16; + out_x = c + (vid->crtc[1] << 4) + hos_offs; + + if (out_x >= 0) { + if (vid->array[3] & 4) { + buffer32->line[line][out_x] = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + buffer32->line[line][out_x] = 0; + } else { + buffer32->line[line][out_x] = (vid->col & 15) + 16; + } + } } } @@ -432,24 +433,30 @@ vid_render(tandy_t *dev, int line, int hos_offs) 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) + hos_offs] = vid->array[((dat >> 12) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + hos_offs + 1] = vid->array[((dat >> 8) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + hos_offs + 2] = vid->array[((dat >> 4) & 0xf) + 16] + 16; - buffer32->line[line][(x << 2) + hos_offs + 3] = vid->array[(dat & 0xf) + 16] + 16; + out_x = (x << 2) + hos_offs; + if (line >= 0) { + if (out_x >= 0) buffer32->line[line][out_x] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + if (out_x + 1 >= 0) buffer32->line[line][out_x + 1] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + if (out_x + 2 >= 0) buffer32->line[line][out_x + 2] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + if (out_x + 3 >= 0) buffer32->line[line][out_x + 3] = 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) + hos_offs] = buffer32->line[line][(x << 3) + hos_offs + 1] = - vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + hos_offs + 2] = buffer32->line[line][(x << 3) + hos_offs + 3] = - vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + hos_offs + 4] = buffer32->line[line][(x << 3) + hos_offs + 5] = - vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 3) + hos_offs + 6] = buffer32->line[line][(x << 3) + hos_offs + 7] = - vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + out_x = (x << 3) + hos_offs; + if (line >= 0) { + if (out_x >= 0) buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = + vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 2 >= 0) buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = + vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 4 >= 0) buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = + vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 6 >= 0) buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = + vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } } } else if (vid->array[3] & 0x10) { /*160x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { @@ -460,18 +467,21 @@ vid_render(tandy_t *dev, int line, int hos_offs) 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) + hos_offs] = buffer32->line[line][(x << 4) + hos_offs + 1] = - buffer32->line[line][(x << 4) + hos_offs + 2] = buffer32->line[line][(x << 4) + hos_offs + 3] = - vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 4) + hos_offs + 4] = buffer32->line[line][(x << 4) + hos_offs + 5] = - buffer32->line[line][(x << 4) + hos_offs + 6] = buffer32->line[line][(x << 4) + hos_offs + 7] = - vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 4) + hos_offs + 8] = buffer32->line[line][(x << 4) + hos_offs + 9] = - buffer32->line[line][(x << 4) + hos_offs + 10] = buffer32->line[line][(x << 4) + hos_offs + 11] = - vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[line][(x << 4) + hos_offs + 12] = buffer32->line[line][(x << 4) + hos_offs + 13] = - buffer32->line[line][(x << 4) + hos_offs + 14] = buffer32->line[line][(x << 4) + hos_offs + 15] = - vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + out_x = (x << 4) + hos_offs; + if (line >= 0) { + if (out_x >= 0) buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = + buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = + vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 4 >= 0) buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = + buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = + vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 8 >= 0) buffer32->line[line][out_x + 8] = buffer32->line[line][out_x + 9] = + buffer32->line[line][out_x + 10] = buffer32->line[line][out_x + 11] = + vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + if (out_x + 12 >= 0) buffer32->line[line][out_x + 12] = buffer32->line[line][out_x + 13] = + buffer32->line[line][out_x + 14] = buffer32->line[line][out_x + 15] = + vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ for (x = 0; x < vid->crtc[1]; x++) { @@ -481,8 +491,10 @@ vid_render(tandy_t *dev, int line, int hos_offs) for (c = 0; c < 8; c++) { chr = (dat >> 6) & 2; chr |= ((dat >> 15) & 1); - buffer32->line[line][(x << 3) + hos_offs + c] = - vid->array[(chr & vid->array[1]) + 16] + 16; + out_x = (x << 3) + hos_offs + c; + if (out_x >= 0 && line >= 0) + buffer32->line[line][out_x] = + vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } } @@ -500,17 +512,27 @@ vid_render(tandy_t *dev, int line, int hos_offs) cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; 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 + hos_offs] = - ((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 + hos_offs] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - else - buffer32->line[line][(x << 3) + c + hos_offs] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (line >= 0) { + if (vid->scanline & 8) for (c = 0; c < 8; c++) { + out_x = (x << 3) + c + hos_offs; + if (out_x >= 0) + buffer32->line[line][out_x] = + ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; + } else for (c = 0; c < 8; c++) { + out_x = (x << 3) + c + hos_offs; + if (out_x >= 0) { + if (vid->scanline == 8) + buffer32->line[line][out_x] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + else + buffer32->line[line][out_x] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + if (drawcursor) for (c = 0; c < 8; c++) { + out_x = (x << 3) + c + hos_offs; + if (out_x >= 0) + buffer32->line[line][out_x] ^= 15; + } } - if (drawcursor) for (c = 0; c < 8; c++) - buffer32->line[line][(x << 3) + c + hos_offs] ^= 15; vid->memaddr++; } } else if (!(vid->mode & 2)) { @@ -528,22 +550,30 @@ vid_render(tandy_t *dev, int line, int hos_offs) cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; } vid->memaddr++; - if (vid->scanline & 8) for (c = 0; c < 8; c++) - buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = - ((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) + hos_offs] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = - cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - else - buffer32->line[line][(x << 4) + (c << 1) + hos_offs] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = - cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (line >= 0) { + if (vid->scanline & 8) for (c = 0; c < 8; c++) { + out_x = (x << 4) + (c << 1) + hos_offs; + if (out_x >= 0) buffer32->line[line][out_x] = + buffer32->line[line][out_x + 1] = + ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; + } else for (c = 0; c < 8; c++) { + out_x = (x << 4) + (c << 1) + hos_offs; + if (vid->scanline == 8) { + if (out_x >= 0) buffer32->line[line][out_x] = + buffer32->line[line][out_x + 1] = + cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + if (out_x >= 0) buffer32->line[line][out_x] = + buffer32->line[line][out_x + 1] = + cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + if (drawcursor) for (c = 0; c < 16; c++) { + out_x = (x << 4) + c + hos_offs; + if (out_x >= 0) + buffer32->line[line][out_x] ^= 15; + } } - if (drawcursor) for (c = 0; c < 16; c++) - buffer32->line[line][(x << 4) + c + hos_offs] ^= 15; } } else if (!(vid->mode & 16)) { cols[0] = (vid->col & 15); @@ -570,8 +600,9 @@ vid_render(tandy_t *dev, int line, int hos_offs) 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) + hos_offs] = - buffer32->line[line][(x << 4) + (c << 1) + 1 + hos_offs] = cols[dat >> 14]; + out_x = (x << 4) + (c << 1) + hos_offs; + if (out_x >= 0 && line >= 0) buffer32->line[line][out_x] = + buffer32->line[line][out_x + 1] = cols[dat >> 14]; dat <<= 2; } } @@ -583,7 +614,9 @@ vid_render(tandy_t *dev, int line, int hos_offs) 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 + hos_offs] = buffer32->line[(line) + 1][(x << 4) + c + hos_offs] = cols[dat >> 15]; + out_x = (x << 4) + c + hos_offs; + if (out_x >= 0 && line >= 0) + buffer32->line[line][out_x] = buffer32->line[(line) + 1][out_x] = cols[dat >> 15]; dat <<= 1; } } @@ -595,18 +628,20 @@ vid_render_blank(tandy_t *dev, int line) { t1kvid_t *vid = dev->vid; - if (vid->array[3] & 4) { - if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - } else { - int cols = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (line >= 0) { + if (vid->array[3] & 4) { + if (vid->mode & 1) + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (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); - else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); + if (vid->mode & 1) + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, cols); + else + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); + } } } @@ -621,10 +656,12 @@ vid_render_process(tandy_t *dev, int line) else x = (vid->crtc[1] << 4) + 16; - if (!dev->is_sl2 && vid->composite) - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); - else - video_process_8(x, line); + if (line >= 0) { + if (!dev->is_sl2 && vid->composite) + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); + else + video_process_8(x, line); + } } static void @@ -639,8 +676,8 @@ vid_poll(void *priv) int scanline_old; int old_ma; int hos_offs = 8 + vid->hsync_offset; - int displine_offs = (vid->displine + vid->vsync_offset < 0) ? 0 : vid->displine + vid->vsync_offset; - int displine_offs_double = displine_offs << 1; + int displine_offs = vid->displine + vid->vsync_offset; + int displine_offs_double = (vid->displine << 1) + (vid->vsync_offset << 1); if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); From f58164db1b118f9c089e04b39e8a7e65bccf7e12 Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Sat, 18 Oct 2025 00:50:13 +0300 Subject: [PATCH 09/13] Trigger baseline calibration on mode change instead of on specific CRTC register writes --- src/video/vid_tandy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index c3737eba3..14d6d8e69 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -231,8 +231,6 @@ tandy_vid_out(uint16_t addr, uint8_t val, void *priv) vid->fullchange = changeframecount; recalc_timings(dev); } - if (vid->crtcreg == 0x01 || vid->crtcreg == 0x06) - baseline_calib_start(vid); if (vid->crtcreg == 0x02 || vid->crtcreg == 0x07) vid_update_display_offset(vid, vid->crtcreg); } @@ -241,6 +239,8 @@ tandy_vid_out(uint16_t addr, uint8_t val, void *priv) case 0x03d8: old = vid->mode; vid->mode = val; + if (old != val) + baseline_calib_start(vid); if ((old ^ val) & 0x01) recalc_timings(dev); if (!dev->is_sl2) From e73c387e215616b137e2c2479609b17aeda900d2 Mon Sep 17 00:00:00 2001 From: Verloren50000 <110334428+Verloren50000@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:24:07 +0800 Subject: [PATCH 10/13] Added the 1998 Award v4.51PG BIOS to MS-5146 --- src/include/86box/machine.h | 3 ++ src/machine/m_at_socket7.c | 65 ++++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 2 +- 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 8cc928f91..ef9031068 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1105,6 +1105,9 @@ extern int machine_at_via809ds_init(const machine_t *); /* SiS 5571 */ extern int machine_at_cb52xsi_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t ms5146_device; +#endif extern int machine_at_ms5146_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t r534f_device; diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 15e0316f2..03f20f42e 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -1825,17 +1825,72 @@ machine_at_cb52xsi_init(const machine_t *model) return ret; } +static const device_config_t ms5146_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ms5146", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "AMIBIOS 6 (071595) - Revision 1.1", + .internal_name = "ms5146", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms5146/A546MS11.ROM", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 2.1", + .internal_name = "ms5146_451pg", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms5146/W546MS21.BIN", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ms5146_device = { + .name = "MSI MS-5146", + .internal_name = "ms5146_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ms5146_config +}; + int machine_at_ms5146_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/ms5146/A546MS11.ROM", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8816ce42c..e2861fd0f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16221,7 +16221,7 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &ms5146_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, From 258c89151ce1d76357096bf73590bfc23832596b Mon Sep 17 00:00:00 2001 From: pixel-jupiter <180155003+pixel-jupiter@users.noreply.github.com> Date: Fri, 24 Oct 2025 01:12:26 +0300 Subject: [PATCH 11/13] Optimize negative bounds checking in rendering loops --- src/video/vid_tandy.c | 257 ++++++++++++++++++++++++------------------ 1 file changed, 147 insertions(+), 110 deletions(-) diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 14d6d8e69..3d2be3a41 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -396,37 +396,51 @@ vid_render(tandy_t *dev, int line, int hos_offs) uint16_t dat; int col; int cols[4]; + uint32_t border_val; int out_x; + int c_start; cols[0] = (vid->array[2] & 0xf) + 16; - if (line >= 0) { + if (line < 0) { + if (dev->is_sl2 && (vid->array[5] & 1)) { + vid->memaddr += vid->crtc[1] * 2; + } else { + vid->memaddr += vid->crtc[1]; + } + return; + } + + if (vid->array[3] & 4) { + border_val = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + border_val = 0; + } else { + border_val = (vid->col & 15) + 16; + } + + if (vid->array[3] & 4) { for (c = 0; c < hos_offs; c++) { - if (vid->array[3] & 4) { - buffer32->line[line][c] = cols[0]; - } else if ((vid->mode & 0x12) == 0x12) { - buffer32->line[line][c] = 0; - } else { - buffer32->line[line][c] = buffer32->line[(line) + 1][c] = (vid->col & 15) + 16; - } + buffer32->line[line][c] = border_val; } - - for (c = 0; c < 8 - vid->hsync_offset; c++) { - if (vid->mode & 1) - out_x = c + (vid->crtc[1] << 3) + hos_offs; - else - out_x = c + (vid->crtc[1] << 4) + hos_offs; - - if (out_x >= 0) { - if (vid->array[3] & 4) { - buffer32->line[line][out_x] = cols[0]; - } else if ((vid->mode & 0x12) == 0x12) { - buffer32->line[line][out_x] = 0; - } else { - buffer32->line[line][out_x] = (vid->col & 15) + 16; - } - } + } else if ((vid->mode & 0x12) == 0x12) { + for (c = 0; c < hos_offs; c++) { + buffer32->line[line][c] = border_val; } + } else { + for (c = 0; c < hos_offs; c++) { + buffer32->line[line][c] = buffer32->line[(line) + 1][c] = border_val; + } + } + + if (vid->mode & 1) { + out_x = (vid->crtc[1] << 3) + hos_offs; + } else { + out_x = (vid->crtc[1] << 4) + hos_offs; + } + c_start = out_x < 0 ? -out_x : 0; + for (c = c_start; c < 8 - vid->hsync_offset; c++) { + buffer32->line[line][out_x + c] = border_val; } if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ @@ -434,11 +448,16 @@ vid_render(tandy_t *dev, int line, int hos_offs) dat = (vid->vram[(vid->memaddr << 1) & 0xffff] << 8) | vid->vram[((vid->memaddr << 1) + 1) & 0xffff]; vid->memaddr++; out_x = (x << 2) + hos_offs; - if (line >= 0) { - if (out_x >= 0) buffer32->line[line][out_x] = vid->array[((dat >> 12) & 0xf) + 16] + 16; - if (out_x + 1 >= 0) buffer32->line[line][out_x + 1] = vid->array[((dat >> 8) & 0xf) + 16] + 16; - if (out_x + 2 >= 0) buffer32->line[line][out_x + 2] = vid->array[((dat >> 4) & 0xf) + 16] + 16; - if (out_x + 3 >= 0) buffer32->line[line][out_x + 3] = vid->array[(dat & 0xf) + 16] + 16; + if (out_x >= 0) { + buffer32->line[line][out_x] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[line][out_x + 1] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[line][out_x + 2] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[line][out_x + 3] = vid->array[(dat & 0xf) + 16] + 16; + } else if (out_x > -4) { + for (c = -out_x; c < 4; c++) { + buffer32->line[line][out_x + c] = + vid->array[((dat >> (12 - c * 4)) & 0xf) + 16] + 16; + } } } } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ @@ -447,15 +466,20 @@ vid_render(tandy_t *dev, int line, int hos_offs) vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; vid->memaddr++; out_x = (x << 3) + hos_offs; - if (line >= 0) { - if (out_x >= 0) buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = + if (out_x >= 0) { + buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 2 >= 0) buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = + buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 4 >= 0) buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = + buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 6 >= 0) buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = + buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } else if (out_x > -8) { + for (c = -out_x; c < 8; c++) { + buffer32->line[line][out_x + c] = + vid->array[((dat >> 12 - (c >> 1) * 4) & vid->array[1] & 0x0f) + 16] + 16; + } } } } else if (vid->array[3] & 0x10) { /*160x200x16*/ @@ -468,19 +492,24 @@ vid_render(tandy_t *dev, int line, int hos_offs) vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; vid->memaddr++; out_x = (x << 4) + hos_offs; - if (line >= 0) { - if (out_x >= 0) buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = - buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = + if (out_x >= 0) { + buffer32->line[line][out_x] = buffer32->line[line][out_x + 1] = + buffer32->line[line][out_x + 2] = buffer32->line[line][out_x + 3] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 4 >= 0) buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = - buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = + buffer32->line[line][out_x + 4] = buffer32->line[line][out_x + 5] = + buffer32->line[line][out_x + 6] = buffer32->line[line][out_x + 7] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 8 >= 0) buffer32->line[line][out_x + 8] = buffer32->line[line][out_x + 9] = + buffer32->line[line][out_x + 8] = buffer32->line[line][out_x + 9] = buffer32->line[line][out_x + 10] = buffer32->line[line][out_x + 11] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - if (out_x + 12 >= 0) buffer32->line[line][out_x + 12] = buffer32->line[line][out_x + 13] = + buffer32->line[line][out_x + 12] = buffer32->line[line][out_x + 13] = buffer32->line[line][out_x + 14] = buffer32->line[line][out_x + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } else if (out_x > -16) { + for (c = -out_x; c < 16; c++) { + buffer32->line[line][out_x + c] = + vid->array[((dat >> 12 - (c >> 2) * 4) & vid->array[1] & 0x0f) + 16] + 16; + } } } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ @@ -488,14 +517,17 @@ vid_render(tandy_t *dev, int line, int hos_offs) 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++; - for (c = 0; c < 8; c++) { - chr = (dat >> 6) & 2; - chr |= ((dat >> 15) & 1); - out_x = (x << 3) + hos_offs + c; - if (out_x >= 0 && line >= 0) - buffer32->line[line][out_x] = + out_x = (x << 3) + hos_offs; + if (out_x > -8) { + c_start = out_x < 0 ? -out_x : 0; + dat <<= c_start; + for (c = c_start; c < 8; c++) { + chr = (dat >> 6) & 2; + chr |= ((dat >> 15) & 1); + buffer32->line[line][out_x + c] = vid->array[(chr & vid->array[1]) + 16] + 16; - dat <<= 1; + dat <<= 1; + } } } } else if (vid->mode & 1) { @@ -512,25 +544,20 @@ vid_render(tandy_t *dev, int line, int hos_offs) cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; } - if (line >= 0) { - if (vid->scanline & 8) for (c = 0; c < 8; c++) { - out_x = (x << 3) + c + hos_offs; - if (out_x >= 0) - buffer32->line[line][out_x] = - ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; - } else for (c = 0; c < 8; c++) { - out_x = (x << 3) + c + hos_offs; - if (out_x >= 0) { - if (vid->scanline == 8) - buffer32->line[line][out_x] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - else - buffer32->line[line][out_x] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } + out_x = (x << 3) + hos_offs; + if (out_x > -8) { + c_start = out_x < 0 ? -out_x : 0; + if (vid->scanline & 8) for (c = c_start; c < 8; c++) { + buffer32->line[line][out_x + c] = + ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; + } else for (c = c_start; c < 8; c++) { + if (vid->scanline == 8) + buffer32->line[line][out_x + c] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + else + buffer32->line[line][out_x + c] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } - if (drawcursor) for (c = 0; c < 8; c++) { - out_x = (x << 3) + c + hos_offs; - if (out_x >= 0) - buffer32->line[line][out_x] ^= 15; + if (drawcursor) for (c = c_start; c < 8; c++) { + buffer32->line[line][out_x + c] ^= 15; } } vid->memaddr++; @@ -550,28 +577,29 @@ vid_render(tandy_t *dev, int line, int hos_offs) cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; } vid->memaddr++; - if (line >= 0) { - if (vid->scanline & 8) for (c = 0; c < 8; c++) { - out_x = (x << 4) + (c << 1) + hos_offs; - if (out_x >= 0) buffer32->line[line][out_x] = - buffer32->line[line][out_x + 1] = + out_x = (x << 4) + hos_offs; + if (out_x > -16) { + c_start = out_x < 0 ? -out_x >> 1 : 0; + if (vid->scanline & 8) for (c = c_start; c < 8; c++) { + buffer32->line[line][out_x + (c << 1)] = + buffer32->line[line][out_x + 1 + (c << 1)] = ((chr >= 0xb3) && (chr <= 0xdf)) ? cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0] : cols[0]; - } else for (c = 0; c < 8; c++) { - out_x = (x << 4) + (c << 1) + hos_offs; + } else for (c = c_start; c < 8; c++) { if (vid->scanline == 8) { - if (out_x >= 0) buffer32->line[line][out_x] = - buffer32->line[line][out_x + 1] = + buffer32->line[line][out_x + (c << 1)] = + buffer32->line[line][out_x + 1 + (c << 1)] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; } else { - if (out_x >= 0) buffer32->line[line][out_x] = - buffer32->line[line][out_x + 1] = + buffer32->line[line][out_x + (c << 1)] = + buffer32->line[line][out_x + 1 + (c << 1)] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } - if (drawcursor) for (c = 0; c < 16; c++) { - out_x = (x << 4) + c + hos_offs; - if (out_x >= 0) - buffer32->line[line][out_x] ^= 15; + if (drawcursor) { + c_start = out_x < 0 ? -out_x : 0; + for (c = c_start; c < 16; c++) { + buffer32->line[line][out_x + c] ^= 15; + } } } } @@ -599,11 +627,15 @@ vid_render(tandy_t *dev, int line, int hos_offs) dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; vid->memaddr++; - for (c = 0; c < 8; c++) { - out_x = (x << 4) + (c << 1) + hos_offs; - if (out_x >= 0 && line >= 0) buffer32->line[line][out_x] = - buffer32->line[line][out_x + 1] = cols[dat >> 14]; - dat <<= 2; + out_x = (x << 4) + hos_offs; + if (out_x > -16) { + c_start = out_x < 0 ? -out_x >> 1 : 0; + dat <<= (c_start > 0 ? c_start << 1 : 0); + for (c = c_start; c < 8; c++) { + buffer32->line[line][out_x + (c << 1)] = + buffer32->line[line][out_x + 1 + (c << 1)] = cols[dat >> 14]; + dat <<= 2; + } } } } else { @@ -613,11 +645,14 @@ vid_render(tandy_t *dev, int line, int hos_offs) dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; vid->memaddr++; - for (c = 0; c < 16; c++) { - out_x = (x << 4) + c + hos_offs; - if (out_x >= 0 && line >= 0) - buffer32->line[line][out_x] = buffer32->line[(line) + 1][out_x] = cols[dat >> 15]; - dat <<= 1; + out_x = (x << 4) + hos_offs; + if (out_x > -16) { + c_start = out_x < 0 ? -out_x : 0; + dat <<= (c_start > 0 ? c_start : 0); + for (c = c_start; c < 16; c++) { + buffer32->line[line][out_x + c] = buffer32->line[(line) + 1][out_x + c] = cols[dat >> 15]; + dat <<= 1; + } } } } @@ -628,20 +663,21 @@ vid_render_blank(tandy_t *dev, int line) { t1kvid_t *vid = dev->vid; - if (line >= 0) { - if (vid->array[3] & 4) { - if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - } else { - int cols = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (line < 0) + return; - if (vid->mode & 1) - hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, cols); - else - hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); - } + if (vid->array[3] & 4) { + if (vid->mode & 1) + hline(buffer32, 0, line, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, (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); + else + hline(buffer32, 0, line, (vid->crtc[1] << 4) + 16, cols); } } @@ -651,17 +687,18 @@ vid_render_process(tandy_t *dev, int line) t1kvid_t *vid = dev->vid; int x; + if (line < 0) + return; + if (vid->mode & 1) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; - if (line >= 0) { - if (!dev->is_sl2 && vid->composite) - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); - else - video_process_8(x, line); - } + if (!dev->is_sl2 && vid->composite) + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[line]); + else + video_process_8(x, line); } static void From 5c5bc12ffc3fd2063eac364e182692ce5d799b1e Mon Sep 17 00:00:00 2001 From: Verloren50000 <110334428+Verloren50000@users.noreply.github.com> Date: Sun, 26 Oct 2025 18:49:03 +0800 Subject: [PATCH 12/13] Rename the Machine Name of Packard Bell PB68x Rename the Machine Name of Packard Bell PB68x: Old name: [i430VX] Packard Bell Orlando/2D/2D/MMX (PB680/PB682/PB683/PB685) New name: [i430VX] Packard Bell Orlando/2D/3D/MMX (PB680/PB682/PB683/PB685) --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 7628d29fa..fe3f4da6e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15410,7 +15410,7 @@ const machine_t machines[] = { PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ { - .name = "[i430VX] Packard Bell Orlando/2D/2D/MMX (PB680/PB682/PB683/PB685)", + .name = "[i430VX] Packard Bell Orlando/2D/3D/MMX (PB680/PB682/PB683/PB685)", .internal_name = "pb680", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, From 8d92dbd0c270586d2953d6c704c481c5f3f4d547 Mon Sep 17 00:00:00 2001 From: WNT50 <173389620+WNT50@users.noreply.github.com> Date: Wed, 29 Oct 2025 22:58:14 +0800 Subject: [PATCH 13/13] IBM PS/55 CPU and name update --- src/machine/machine_table.c | 90 ++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b65dd5d51..205ad9309 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6851,7 +6851,7 @@ const machine_t machines[] = { }, /* Has IBM PS/55 5551-Sxx, Txx stage 2 firmware. */ { - .name = "[MCA] IBM PS/55 model 5550-T", + .name = "[MCA] IBM PS/55 model 5550-S/T Stage II", .internal_name = "ibmps55_m50t", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_PROPRIETARY, @@ -6893,50 +6893,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has IBM PS/55 5551-V0x, V1x firmware. */ - { - .name = "[MCA] IBM PS/55 model 5550-V", - .internal_name = "ibmps55_m50v", - .type = MACHINE_TYPE_386DX, - .chipset = MACHINE_CHIPSET_PROPRIETARY, - .init = machine_ps55_model_50v_init, - .p1_handler = machine_generic_p1_handler, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_386DX | CPU_PKG_486BL, - .block = CPU_BLOCK_NONE, - .min_bus = 0, - .max_bus = 0, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_PS2_MCA, - .flags = MACHINE_VIDEO | MACHINE_KEYBOARD_JIS | MACHINE_APM, - .ram = { - .min = 4096, - .max = 16384, - .step = 4096 - }, - .nvrmask = 63, - .jumpered_ecp_dma = 0, - .default_jumpered_ecp_dma = -1, - .kbc_device = &kbc_at_device, - .kbc_params = KBC_VEN_IBM, - .kbc_p1 = 0x00000cf0, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .kbd_device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* 386DX/486 machines */ /* Winbond W83C42 - ASIC that clones AMI 'F'. */ @@ -7160,6 +7116,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has IBM PS/55 5551-V0x, V1x firmware. */ + { + .name = "[MCA] IBM PS/55 model 5550-V0/V1", + .internal_name = "ibmps55_m50v", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps55_model_50v_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO | MACHINE_KEYBOARD_JIS | MACHINE_APM, + .ram = { + .min = 4096, + .max = 16384, + .step = 4096 + }, + .nvrmask = 63, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_IBM, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 486 machines - Socket 1 */ /* Has JetKey V5 KBC Firmware - we now have a photo of the board and its POST