diff --git a/src/include/86box/m_pcjr.h b/src/include/86box/m_pcjr.h new file mode 100644 index 000000000..8ba0c4414 --- /dev/null +++ b/src/include/86box/m_pcjr.h @@ -0,0 +1,72 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header files for the PCjr keyboard and video subsystems. + * + * + * + * Authors: Connor Hyde, + * + * Copyright 2025 starfrost + */ + +#pragma once + +#define PCJR_RGB 0 +#define PCJR_COMPOSITE 1 + +typedef struct pcjr_s +{ + /* Video Controller stuff. */ + mem_mapping_t mapping; + uint8_t crtc[32]; + int crtcreg; + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl; + uint8_t stat; + int addr_mode; + uint8_t *vram; + uint8_t *b8000; + int linepos; + int displine; + int sc; + int vc; + int dispon; + int cursorvisible; // Is the cursor visible on the current scanline? + int cursoron; + int blink; + int vsynctime; + int fullchange; + int vadj; + uint16_t ma; + uint16_t maback; + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; + int firstline; + int lastline; + int composite; + int apply_hd; + + /* Keyboard Controller stuff. */ + int latched; + int data; + int serial_data[44]; + int serial_pos; + uint8_t pa; + uint8_t pb; + pc_timer_t send_delay_timer; + +} pcjr_t; + +void pcjr_recalc_timings(pcjr_t *pcjr); + +// Note: This is a temporary solution until the pcjr video is made its own gfx card +void pcjr_vid_init(pcjr_t *pcjr); \ No newline at end of file diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h new file mode 100644 index 000000000..3bafafd46 --- /dev/null +++ b/src/include/86box/m_tandy.h @@ -0,0 +1,95 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header files for the Tandy keyboard and video subsystems. + * + * + * + * Authors: Connor Hyde, + * + * Copyright 2025 starfrost + */ + +typedef struct t1kvid_t { + mem_mapping_t mapping; + mem_mapping_t vram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[256]; + int memctrl; + uint8_t mode; + uint8_t col; + uint8_t stat; + + uint8_t *vram; + uint8_t *b8000; + uint32_t b8000_mask; + uint32_t b8000_limit; + uint8_t planar_ctrl; + uint8_t lp_strobe; + + int linepos; + int displine; + int sc; + int vc; + int dispon; + int cursorvisible; + int cursoron; + int blink; + int fullchange; + int vsynctime; + int vadj; + uint16_t ma; + uint16_t maback; + + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; + int firstline; + int lastline; + + int composite; +} t1kvid_t; + +typedef struct t1keep_t { + char *path; + + int state; + int count; + int addr; + int clk; + uint16_t data; + uint16_t store[64]; +} t1keep_t; + +typedef struct tandy_t { + mem_mapping_t ram_mapping; + mem_mapping_t rom_mapping; /* SL2 */ + + uint8_t *rom; /* SL2 */ + uint8_t ram_bank; + uint8_t rom_bank; /* SL2 */ + int rom_offset; /* SL2 */ + + uint32_t base; + uint32_t mask; + int is_hx; + int is_sl2; + + t1kvid_t *vid; +} tandy_t; + +void tandy_vid_init(tandy_t* dev); +uint8_t tandy_vid_in(uint16_t addr, void* priv); +void tandy_vid_out(uint16_t addr, uint8_t val, void *priv); + +void tandy_vid_close(void* priv); +void tandy_recalc_address_sl(tandy_t* dev); //this function is needed by both m_ and vid_tandy.c diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 2a36eeade..add92c708 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -11,7 +11,8 @@ * * * Authors: Sarah Walker, - * Miran Grca, + * Miran Grca, , + * Connor Hyde / starfrost, * * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. @@ -56,6 +57,7 @@ typedef enum cga_crtc_registers_e CGA_CRTC_LIGHT_PEN_ADDR_LOW = 0x11, // Light pen address low 8 bits (not currently supported) } cga_crtc_registers; +// Registers for the CGA typedef enum cga_registers_e { CGA_REGISTER_CRTC_INDEX = 0x3D4, @@ -88,7 +90,7 @@ typedef struct cga_t { int sc; int vc; int cgadispon; - int con; + int cursorvisible; // Determines if the cursor is visible FOR THE CURRENT SCANLINE. int cursoron; int cgablink; int vsynctime; diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index c4c0ea2d7..19461ba2b 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -68,7 +68,7 @@ typedef struct ega_t { int chain4; int chain2_read; int chain2_write; - int con; + int cursorvisible; int oddeven_page; int oddeven_chain; int vc; @@ -193,7 +193,7 @@ extern int sc; extern uint32_t ma; extern uint32_t ca; -extern int con; +extern int cursorvisible; extern int cursoron; extern int cgablink; diff --git a/src/include/86box/vid_hercules.h b/src/include/86box/vid_hercules.h index a468dce55..46b0e16a7 100644 --- a/src/include/86box/vid_hercules.h +++ b/src/include/86box/vid_hercules.h @@ -46,7 +46,7 @@ typedef struct { int sc; uint16_t ma; uint16_t maback; - int con; + int cursorvisible; int cursoron; int dispon; int blink; diff --git a/src/include/86box/vid_mda.h b/src/include/86box/vid_mda.h index eeea5a093..15a1cabde 100644 --- a/src/include/86box/vid_mda.h +++ b/src/include/86box/vid_mda.h @@ -28,7 +28,7 @@ typedef struct mda_t { int sc; uint16_t ma; uint16_t maback; - int con; + int cursorvisible; int cursoron; int dispon; int blink; diff --git a/src/include/86box/vid_pgc.h b/src/include/86box/vid_pgc.h index 43226a0f5..d7906f2bc 100644 --- a/src/include/86box/vid_pgc.h +++ b/src/include/86box/vid_pgc.h @@ -115,7 +115,7 @@ typedef struct pgc { int displine; int vc; int cgadispon; - int con; + int cursorvisible; int cursoron; int cgablink; int vsynctime; diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 6b817f0ee..aec33d95c 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -105,7 +105,7 @@ typedef struct svga_t { int vslines; int linecountff; int oddeven; - int con; + int cursorvisible; int cursoron; int blink; int scrollcache; diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index babac7592..a96610d4a 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -27,7 +27,7 @@ extern int sc; extern uint32_t ma; extern uint32_t ca; -extern int con; +extern int cursorvisible; extern int cursoron; extern int cgablink; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index bd3101d84..6ab375370 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -395,6 +395,7 @@ extern const device_t gd5480_pci_device; /* Compaq CGA */ extern const device_t compaq_cga_device; extern const device_t compaq_cga_2_device; +extern const device_t compaq_plasma_device; /* Olivetti OGC */ extern const device_t ogc_device; @@ -609,6 +610,11 @@ extern const device_t velocity_200_agp_device; /* Wyse 700 */ extern const device_t wy700_device; +/* Tandy */ +extern const device_t tandy_1000_video_device; +extern const device_t tandy_1000hx_video_device; +extern const device_t tandy_1000sl_video_device; + #endif #endif /*EMU_VIDEO_H*/ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 8cd54edec..f91eeb17d 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -23,7 +23,6 @@ add_library(mch OBJECT m_xt_laserxt.c m_xt_philips.c m_xt_t1000.c - m_xt_t1000_vid.c m_xt_xi8088.c m_xt_zenith.c m_pcjr.c @@ -37,7 +36,6 @@ add_library(mch OBJECT m_at_commodore.c m_at_grid.c m_at_t3100e.c - m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 57e8367ff..43800a8bc 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -116,7 +116,7 @@ typedef struct amsvid_t { int sc; int vc; int cgadispon; - int con; + int cursorvisible; int cursoron; int cgablink; int vsynctime; @@ -369,26 +369,26 @@ vid_poll_1512(void *priv) for (c = 0; c < 8; c++) { if ((vid->cgamode & 0x12) == 0x12) { buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->border & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; } else { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; } } else { buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; } else { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; } } } - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { for (x = 0; x < 80; x++) { chr = vid->vram[(vid->ma << 1) & 0x3fff]; attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { + drawcursor = ((vid->ma == ca) && vid->cursorvisible && vid->cursoron); + if (vid->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) @@ -408,12 +408,12 @@ vid_poll_1512(void *priv) } vid->ma++; } - } else if (!(vid->cgamode & 2)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_GRAPHICS)) { for (x = 0; x < 40; x++) { chr = vid->vram[(vid->ma << 1) & 0x3fff]; attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { + drawcursor = ((vid->ma == ca) && vid->cursorvisible && vid->cursoron); + if (vid->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((vid->blink & 16) && (attr & 0x80)) @@ -433,10 +433,10 @@ vid_poll_1512(void *priv) } } } - } else if (!(vid->cgamode & 16)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { cols[0] = (vid->cgacol & 15) | 16; col = (vid->cgacol & 16) ? 24 : 16; - if (vid->cgamode & 4) { + if (vid->cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; cols[2] = col | 4; cols[3] = col | 7; @@ -477,7 +477,7 @@ vid_poll_1512(void *priv) } } else { cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); } else { @@ -486,7 +486,7 @@ vid_poll_1512(void *priv) } } - if (vid->cgamode & 1) + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; @@ -513,7 +513,7 @@ vid_poll_1512(void *priv) vid->stat &= ~8; } if (vid->sc == (vid->crtc[11] & 31)) { - vid->con = 0; + vid->cursorvisible = 0; } if (vid->vadj) { vid->sc++; @@ -545,7 +545,7 @@ vid_poll_1512(void *priv) vid->displine = 0; vid->vsynctime = 46; - if (vid->cgamode & 1) + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; @@ -582,15 +582,15 @@ vid_poll_1512(void *priv) video_res_x = xsize; video_res_y = ysize; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; video_res_y /= vid->crtc[9] + 1; video_bpp = 0; - } else if (!(vid->cgamode & 2)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; video_res_y /= vid->crtc[9] + 1; video_bpp = 0; - } else if (!(vid->cgamode & 16)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else { @@ -607,7 +607,7 @@ vid_poll_1512(void *priv) vid->ma = vid->maback; } if (vid->sc == (vid->crtc[10] & 31)) - vid->con = 1; + vid->cursorvisible = 1; } } @@ -1292,7 +1292,7 @@ lcdm_poll(amsvid_t *vid) for (x = 0; x < mda->crtc[1]; x++) { chr = mda->vram[(mda->ma << 1) & 0xfff]; attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; - drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + drawcursor = ((mda->ma == ca) && mda->cursorvisible && mda->cursoron); blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); lcd_draw_char_80(vid, &(buffer32->line[mda->displine])[x * 8], chr, attr, drawcursor, blink, mda->sc, 0, mda->ctrl); @@ -1316,7 +1316,7 @@ lcdm_poll(amsvid_t *vid) mda->stat &= ~8; } if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { - mda->con = 0; + mda->cursorvisible = 0; } if (mda->vadj) { mda->sc++; @@ -1383,7 +1383,7 @@ lcdm_poll(amsvid_t *vid) mda->ma = mda->maback; } if (mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1))) - mda->con = 1; + mda->cursorvisible = 1; } } @@ -1403,14 +1403,14 @@ lcdc_poll(amsvid_t *vid) uint16_t ca; int blink; - ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + ca = (cga->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (cga->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; if (!cga->linepos) { timer_advance_u64(&vid->timer, cga->dispofftime); cga->cgastat |= 1; cga->linepos = 1; oldsc = cga->sc; - if ((cga->crtc[8] & 3) == 3) + if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3) cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; if (cga->cgadispon) { if (cga->displine < cga->firstline) { @@ -1419,28 +1419,28 @@ lcdc_poll(amsvid_t *vid) } cga->lastline = cga->displine; - if (cga->cgamode & 1) { - for (x = 0; x < cga->crtc[1]; x++) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { chr = cga->charbuffer[x << 1]; attr = cga->charbuffer[(x << 1) + 1]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + drawcursor = ((cga->ma == ca) && cga->cursorvisible && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); lcd_draw_char_80(vid, &(buffer32->line[cga->displine << 1])[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); lcd_draw_char_80(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); cga->ma++; } - } else if (!(cga->cgamode & 2)) { - for (x = 0; x < cga->crtc[1]; x++) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { chr = cga->vram[(cga->ma << 1) & 0x3fff]; attr = cga->vram[((cga->ma << 1) + 1) & 0x3fff]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + drawcursor = ((cga->ma == ca) && cga->cursorvisible && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); lcd_draw_char_40(vid, &(buffer32->line[cga->displine << 1])[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); lcd_draw_char_40(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); cga->ma++; } } else { /* Graphics mode */ - for (x = 0; x < cga->crtc[1]; x++) { + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; cga->ma++; for (uint8_t c = 0; c < 16; c++) { @@ -1450,22 +1450,22 @@ lcdc_poll(amsvid_t *vid) } } } else { - if (cga->cgamode & 1) { - hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 3), green); - hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 3), green); + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[CGA_CRTC_HDISP] << 3), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[CGA_CRTC_HDISP] << 3), green); } else { - hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 4), green); - hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 4), green); + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[CGA_CRTC_HDISP] << 4), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[CGA_CRTC_HDISP] << 4), green); } } - if (cga->cgamode & 1) - x = (cga->crtc[1] << 3); + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (cga->crtc[CGA_CRTC_HDISP] << 3); else - x = (cga->crtc[1] << 4); + x = (cga->crtc[CGA_CRTC_HDISP] << 4); cga->sc = oldsc; - if (cga->vc == cga->crtc[7] && !cga->sc) + if (cga->vc == cga->crtc[CGA_CRTC_VSYNC] && !cga->sc) cga->cgastat |= 8; cga->displine++; if (cga->displine >= 360) @@ -1478,10 +1478,10 @@ lcdc_poll(amsvid_t *vid) if (!cga->vsynctime) cga->cgastat &= ~8; } - if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) { - cga->con = 0; + if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_END] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + cga->cursorvisible = 0; } - if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == (cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) cga->maback = cga->ma; if (cga->vadj) { cga->sc++; @@ -1490,41 +1490,41 @@ lcdc_poll(amsvid_t *vid) cga->vadj--; if (!cga->vadj) { cga->cgadispon = 1; - cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->ma = cga->maback = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; cga->sc = 0; } - } else if (cga->sc == cga->crtc[9]) { + } else if (cga->sc == cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { cga->maback = cga->ma; cga->sc = 0; oldvc = cga->vc; cga->vc++; cga->vc &= 127; - if (cga->vc == cga->crtc[6]) + if (cga->vc == cga->crtc[CGA_CRTC_VDISP]) cga->cgadispon = 0; - if (oldvc == cga->crtc[4]) { + if (oldvc == cga->crtc[CGA_CRTC_VTOTAL]) { cga->vc = 0; - cga->vadj = cga->crtc[5]; + cga->vadj = cga->crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!cga->vadj) cga->cgadispon = 1; if (!cga->vadj) - cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; - if ((cga->crtc[10] & 0x60) == 0x20) + cga->ma = cga->maback = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((cga->crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) cga->cursoron = 0; else cga->cursoron = cga->cgablink & 8; } - if (cga->vc == cga->crtc[7]) { + if (cga->vc == cga->crtc[CGA_CRTC_VSYNC]) { cga->cgadispon = 0; cga->displine = 0; cga->vsynctime = 16; - if (cga->crtc[7]) { - if (cga->cgamode & 1) - x = (cga->crtc[1] << 3); + if (cga->crtc[CGA_CRTC_VSYNC]) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (cga->crtc[CGA_CRTC_HDISP] << 3); else - x = (cga->crtc[1] << 4); + x = (cga->crtc[CGA_CRTC_HDISP] << 4); cga->lastline++; xs_temp = x; @@ -1536,7 +1536,7 @@ lcdc_poll(amsvid_t *vid) if (ys_temp < 32) ys_temp = 400; - if ((cga->cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; ysize = ys_temp; set_screen_size(xsize, ysize); @@ -1553,15 +1553,15 @@ lcdc_poll(amsvid_t *vid) video_res_x = xsize; video_res_y = ysize; - if (cga->cgamode & 1) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= cga->crtc[9] + 1; + video_res_y /= cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(cga->cgamode & 2)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= cga->crtc[9] + 1; + video_res_y /= cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(cga->cgamode & 16)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else @@ -1579,10 +1579,10 @@ lcdc_poll(amsvid_t *vid) } if (cga->cgadispon) cga->cgastat &= ~1; - if (cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1))) - cga->con = 1; - if (cga->cgadispon && (cga->cgamode & 1)) { - for (x = 0; x < (cga->crtc[1] << 1); x++) + if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_START] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + cga->cursorvisible = 1; + if (cga->cgadispon && (cga->cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (cga->crtc[CGA_CRTC_HDISP] << 1); x++) cga->charbuffer[x] = cga->vram[((cga->ma << 1) + x) & 0x3fff]; } } diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 1f5ecdb58..2fbfed0ff 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -44,9 +44,6 @@ #include <86box/vid_cga_comp.h> #include <86box/plat_unused.h> - -static video_timings_t timing_compaq_plasma = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; - enum { COMPAQ_PORTABLEII = 0, COMPAQ_PORTABLEIII, @@ -55,752 +52,11 @@ enum { COMPAQ_DESKPRO386_05_1988 }; -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 - -/*Very rough estimate*/ -#define VID_CLOCK (double) (651 * 416 * 60) - -/* Mapping of attributes to colours */ -static uint32_t amber; -static uint32_t black; -static uint32_t blinkcols[256][2]; -static uint32_t normcols[256][2]; - -/* Video options set by the motherboard; they will be picked up by the card - * on the next poll. - * - * Bit 3: Disable built-in video (for add-on card) - * Bit 2: Thin font - * Bits 0,1: Font set (not currently implemented) - */ -static int8_t cpq_st_display_internal = -1; - -static uint8_t mdaattr[256][2][2]; - -static void -compaq_plasma_display_set(uint8_t internal) -{ - cpq_st_display_internal = internal; -} - -typedef struct compaq_plasma_t { - cga_t cga; - mem_mapping_t font_ram_mapping; - uint8_t *font_ram; - uint8_t port_13c6; - uint8_t port_23c6; - uint8_t port_27c6; - uint8_t internal_monitor; -} compaq_plasma_t; - static int compaq_machine_type = 0; /* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ static mem_mapping_t ram_mapping; -static void compaq_plasma_recalcattrs(compaq_plasma_t *self); - -static void -compaq_plasma_recalctimings(compaq_plasma_t *self) -{ - double _dispontime; - double _dispofftime; - double disptime; - - if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { - cga_recalctimings(&self->cga); - return; - } - - disptime = 651; - _dispontime = 640; - _dispofftime = disptime - _dispontime; - self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); - self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); -} - -static void -compaq_plasma_waitstates(UNUSED(void *priv)) -{ - int ws_array[16] = { 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8 }; - int ws; - - ws = ws_array[cycles & 0xf]; - sub_cycles(ws); -} - -static void -compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - if (self->port_23c6 & 0x08) - self->font_ram[addr & 0x1fff] = val; - else - self->cga.vram[addr & 0x7fff] = val; - - compaq_plasma_waitstates(&self->cga); -} -static uint8_t -compaq_plasma_read(uint32_t addr, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t ret; - - compaq_plasma_waitstates(&self->cga); - - if (self->port_23c6 & 0x08) - ret = (self->font_ram[addr & 0x1fff]); - else - ret = (self->cga.vram[addr & 0x7fff]); - - return ret; -} - -static void -compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - switch (addr) { - /* Emulated CRTC, register select */ - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - cga_out(addr, val, &self->cga); - break; - - /* Emulated CRTC, value */ - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - cga_out(addr, val, &self->cga); - compaq_plasma_recalctimings(self); - break; - case 0x3d8: - case 0x3d9: - cga_out(addr, val, &self->cga); - break; - - case 0x13c6: - self->port_13c6 = val; - compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); - /* - For bits 2-0, John gives 0 = CGA, 1 = EGA, 3 = MDA; - Another source (Ralf Brown?) gives 4 = CGA, 5 = EGA, 7 = MDA; - This leads me to believe bit 2 is not relevant to the mode. - */ - if ((val & 0x03) == 0x03) - mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x08000); - else - mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x08000); - break; - - case 0x23c6: - self->port_23c6 = val; - compaq_plasma_recalcattrs(self); - break; - - case 0x27c6: - self->port_27c6 = val; - break; - - default: - break; - } -} - -static uint8_t -compaq_plasma_in(uint16_t addr, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x3d4: - case 0x3da: - case 0x3db: - case 0x3dc: - ret = cga_in(addr, &self->cga); - break; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - ret = cga_in(addr, &self->cga); - break; - - case 0x3d8: - ret = self->cga.cgamode; - break; - - case 0x13c6: - ret = self->port_13c6; -#if 0 - if ((self->cga.cgamode & 0x28) == 0x00) - ret |= 0x04; -#endif - break; - - case 0x17c6: - ret = 0xe6; - break; - - case 0x1bc6: - ret = 0x40; - break; - - case 0x23c6: - ret = self->port_23c6; - break; - - case 0x27c6: - ret = self->port_27c6 & 0x3f; - break; - - default: - break; - } - - return ret; -} - -static void -compaq_plasma_poll(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t chr; - uint8_t attr; - uint8_t sc; - uint16_t ma = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (self->cga.crtc[15] | (self->cga.crtc[14] << 8)) & 0x7fff; - uint16_t addr; - int drawcursor; - int cursorline; - int blink = 0; - int underline = 0; - int c; - int x; - uint32_t ink = 0; - uint32_t fg = (self->cga.cgacol & 0x0f) ? amber : black; - uint32_t bg = black; - uint32_t cols[2]; - uint8_t dat; - uint8_t pattern; - uint32_t ink0 = 0; - uint32_t ink1 = 0; - - /* Switch between internal plasma and external CRT display. */ - if ((cpq_st_display_internal != -1) && (cpq_st_display_internal != self->internal_monitor)) { - self->internal_monitor = cpq_st_display_internal; - compaq_plasma_recalctimings(self); - } - - /* graphic mode and not mode 40h */ - if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { - /* standard cga mode */ - cga_poll(&self->cga); - return; - } else { - /* mode 40h or text mode */ - if (!self->cga.linepos) { - timer_advance_u64(&self->cga.timer, self->cga.dispofftime); - self->cga.cgastat |= 1; - self->cga.linepos = 1; - if (self->cga.cgadispon) { - if (self->cga.displine == 0) - video_wait_for_buffer(); - - /* 80-col */ - if (self->cga.cgamode & 0x01) { - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 80) << 1; - ma += (self->cga.displine >> 4) * 80; - - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); - - /* for each text column */ - for (x = 0; x < 80; x++) { - /* video output enabled */ - if (self->cga.cgamode & 0x08) { - /* character */ - chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; - /* text attributes */ - attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else { - chr = 0x00; - attr = 0x00; - } - uint8_t hi_bit = attr & 0x08; - /* check if cursor has to be drawn */ - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); - /* check if character underline mode should be set */ - underline = ((attr & 0x07) == 0x01); - underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); - if (underline) { - /* set forecolor to white */ - attr = attr | 0x7; - } - blink = 0; - /* set foreground */ - cols[1] = blinkcols[attr][1]; - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { - /* set blinking */ - cols[1] = cols[0]; - blink = 1; - } - } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; - } - - /* character address */ - uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && hi_bit) - chr_addr |= 0x1000; - - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; - } - - if (hi_bit) { - if ((self->port_23c6 >> 5) == 1) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] ^= (amber ^ black); - } else if ((self->port_23c6 >> 5) == 4) { - for (c = 0; c < 8; c++) { - uint32_t b = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 1) & 0x7f; - uint32_t g = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 9) & 0x7f; - uint32_t r = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 17) & 0x7f; - buffer32->line[self->cga.displine][(x << 3) + c] = b | (g << 8) || (r << 16); - } - } - } - ma++; - } - } - /* 40-col */ - else if (!(self->cga.cgamode & 0x02)) { - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 40) << 1; - ma += (self->cga.displine >> 4) * 40; - - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); - - for (x = 0; x < 40; x++) { - /* video output enabled */ - if (self->cga.cgamode & 0x08) { - /* character */ - chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; - /* text attributes */ - attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else { - chr = 0x00; - attr = 0x00; - } - uint8_t hi_bit = attr & 0x08; - /* check if cursor has to be drawn */ - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); - /* check if character underline mode should be set */ - underline = ((attr & 0x07) == 0x01); - underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); - if (underline) { - /* set forecolor to white */ - attr = attr | 0x7; - } - blink = 0; - /* set foreground */ - cols[1] = blinkcols[attr][1]; - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { - /* set blinking */ - cols[1] = cols[0]; - blink = 1; - } - } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; - } - - /* character address */ - uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && hi_bit) - chr_addr |= 0x1000; - - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; - } - - if (hi_bit) { - if ((self->port_23c6 >> 5) == 1) - for (c = 0; c < 8; c++) { - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] ^= (amber ^ black); - buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] ^= (amber ^ black); - } - else if ((self->port_23c6 >> 5) == 4) - for (c = 0; c < 8; c++) { - uint32_t b = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 1) & 0x7f; - uint32_t g = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 9) & 0x7f; - uint32_t r = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 17) & 0x7f; - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = b | (g << 8) || (r << 16); - } - } - ma++; - } - } else { - if (self->cga.cgamode & 0x10) { - /* 640x400 mode */ - if (self->port_23c6 & 0x01) /* 640*400 */ { - addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7fff]; - addr++; - - for (uint8_t c = 0; c < 8; c++) { - ink = (dat & 0x80) ? fg : bg; - if (!(self->cga.cgamode & 0x08)) - ink = black; - buffer32->line[self->cga.displine][(x << 3) + c] = ink; - dat <<= 1; - } - } - } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7fff]; - addr++; - - for (uint8_t c = 0; c < 4; c++) { - pattern = (dat & 0xC0) >> 6; - if (!(self->cga.cgamode & 0x08)) - pattern = 0; - - switch (pattern & 3) { - case 0: - ink0 = ink1 = black; - break; - case 1: - if (self->cga.displine & 0x01) { - ink0 = black; - ink1 = black; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 2: - if (self->cga.displine & 0x01) { - ink0 = black; - ink1 = amber; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 3: - ink0 = ink1 = amber; - break; - - default: - break; - } - buffer32->line[self->cga.displine][(x << 3) + (c << 1)] = ink0; - buffer32->line[self->cga.displine][(x << 3) + (c << 1) + 1] = ink1; - dat <<= 2; - } - } - } - } - } - self->cga.displine++; - /* Hardcode a fixed refresh rate and VSYNC timing */ - if (self->cga.displine == 400) { /* Start of VSYNC */ - self->cga.cgastat |= 8; - self->cga.cgadispon = 0; - } - if (self->cga.displine == 416) { /* End of VSYNC */ - self->cga.displine = 0; - self->cga.cgastat &= ~8; - self->cga.cgadispon = 1; - } - } else { - timer_advance_u64(&self->cga.timer, self->cga.dispontime); - if (self->cga.cgadispon) - self->cga.cgastat &= ~1; - - self->cga.linepos = 0; - - if (self->cga.displine == 400) { - xsize = 640; - ysize = 400; - - if ((self->cga.cgamode & 0x08) || video_force_resize_get()) { - set_screen_size(xsize, ysize); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - /* Plasma specific */ - video_blit_memtoscreen(0, 0, xsize, ysize); - frames++; - - /* Fixed 640x400 resolution */ - video_res_x = 640; - video_res_y = 400; - - if (self->cga.cgamode & 0x02) { - if (self->cga.cgamode & 0x10) - video_bpp = 1; - else - video_bpp = 2; - } else - video_bpp = 0; - - self->cga.cgablink++; - } - } - } -} - -static void -compaq_plasma_mdaattr_rebuild(void) -{ - for (uint16_t c = 0; c < 256; c++) { - mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; - if (c & 8) - mdaattr[c][0][1] = 15 + 16; - else - mdaattr[c][0][1] = 7 + 16; - } - - mdaattr[0x70][0][1] = 16; - mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; - mdaattr[0xF0][0][1] = 16; - mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; - mdaattr[0x78][0][1] = 16 + 7; - mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; - mdaattr[0xF8][0][1] = 16 + 7; - mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; - mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; - mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; - mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; - mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; -} - -static void -compaq_plasma_recalcattrs(compaq_plasma_t *self) -{ - int n; - - /* val behaves as follows: - * Bit 0: Attributes 01-06, 08-0E are inverse video - * Bit 1: Attributes 01-06, 08-0E are bold - * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are inverse video - * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are bold */ - - /* Set up colours */ - amber = makecol(0xff, 0x7d, 0x00); - black = makecol(0x64, 0x19, 0x00); - - /* Initialize the attribute mapping. Start by defaulting everything - * to black on amber, and with bold set by bit 3 */ - for (n = 0; n < 256; n++) { - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - } - - /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the - * passed value. Exclude x0 and x8, which are always black on - * amber. */ - for (n = 0x11; n <= 0xFF; n++) { - if ((n & 7) == 0) - continue; - if ((self->port_23c6 >> 5) == 1) { /* Inverse */ - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - } else { /* Normal */ - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - } - } - /* Set up the 01-0E range, controlled by bits 0 and 1 of the - * passed value. When blinking is enabled this also affects 81-8E. */ - for (n = 0x01; n <= 0x0E; n++) { - if (n == 7) - continue; - if ((self->port_23c6 >> 5) == 1) { - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - blinkcols[n + 128][0] = amber; - blinkcols[n + 128][1] = black; - } else { - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - blinkcols[n + 128][0] = black; - blinkcols[n + 128][1] = amber; - } - } - /* Colours 07 and 0F are always amber on black. If blinking is - * enabled so are 87 and 8F. */ - for (n = 0x07; n <= 0x0F; n += 8) { - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - blinkcols[n + 128][0] = black; - blinkcols[n + 128][1] = amber; - } - /* When not blinking, colours 81-8F are always amber on black. */ - for (n = 0x81; n <= 0x8F; n++) { - normcols[n][0] = black; - normcols[n][1] = amber; - } - - /* Finally do the ones which are solid black. These differ between - * the normal and blinking mappings */ - for (n = 0; n <= 0xFF; n += 0x11) - normcols[n][0] = normcols[n][1] = black; - - /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */ - for (n = 0; n <= 0x77; n += 0x11) { - blinkcols[n][0] = blinkcols[n][1] = black; - blinkcols[n + 128][0] = blinkcols[n + 128][1] = black; - } -} - -static void * -compaq_plasma_init(UNUSED(const device_t *info)) -{ - compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); - - cga_init(&self->cga); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); - - self->cga.composite = 0; - self->cga.revision = 0; - - self->cga.vram = malloc(0x8000); - self->internal_monitor = 1; - self->font_ram = malloc(0x2000); - - cga_comp_init(self->cga.revision); - timer_set_callback(&self->cga.timer, compaq_plasma_poll); - timer_set_p(&self->cga.timer, self); - - mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, - compaq_plasma_read, NULL, NULL, - compaq_plasma_write, NULL, NULL, - NULL, MEM_MAPPING_EXTERNAL, self); - for (int i = 1; i <= 2; i++) { - io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - } - io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - - overscan_x = overscan_y = 16; - - self->cga.rgb_type = device_get_config_int("rgb_type"); - cga_palette = (self->cga.rgb_type << 1); - cgapal_rebuild(); - compaq_plasma_mdaattr_rebuild(); - - return self; -} - -static void -compaq_plasma_close(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - free(self->cga.vram); - free(self->font_ram); - free(self); -} - -static void -compaq_plasma_speed_changed(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - compaq_plasma_recalctimings(self); -} - -const device_config_t compaq_plasma_config[] = { - // clang-format off - { - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "Color", .value = 0 }, - { .description = "Green Monochrome", .value = 1 }, - { .description = "Amber Monochrome", .value = 2 }, - { .description = "Gray Monochrome", .value = 3 }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -const device_t compaq_plasma_device = { - .name = "Compaq Plasma", - .internal_name = "compaq_plasma", - .flags = 0, - .local = 0, - .init = compaq_plasma_init, - .close = compaq_plasma_close, - .reset = NULL, - .available = NULL, - .speed_changed = compaq_plasma_speed_changed, - .force_redraw = NULL, - .config = compaq_plasma_config -}; static uint8_t read_ram(uint32_t addr, UNUSED(void *priv)) diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c index 812755898..628333aba 100644 --- a/src/machine/m_elt.c +++ b/src/machine/m_elt.c @@ -58,13 +58,13 @@ static void elt_vid_off_poll(void *priv) { cga_t *cga = priv; - uint8_t hdisp = cga->crtc[1]; + uint8_t hdisp = cga->crtc[CGA_CRTC_HDISP]; /* Don't display anything. * TODO: Do something less stupid to emulate backlight off. */ - cga->crtc[1] = 0; + cga->crtc[CGA_CRTC_HDISP] = 0; cga_poll(cga); - cga->crtc[1] = hdisp; + cga->crtc[CGA_CRTC_HDISP] = hdisp; } static void diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index f2da2e2b5..e76889d93 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -48,11 +48,10 @@ #include <86box/snd_sn76489.h> #include <86box/video.h> #include <86box/vid_cga_comp.h> +#include <86box/m_pcjr.h> #include <86box/machine.h> #include <86box/plat_unused.h> -#define PCJR_RGB 0 -#define PCJR_COMPOSITE 1 #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 @@ -63,49 +62,10 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -typedef struct pcjr_t { - /* Video Controller stuff. */ - mem_mapping_t mapping; - uint8_t crtc[32]; - int crtcreg; - int array_index; - uint8_t array[32]; - int array_ff; - int memctrl; - uint8_t stat; - int addr_mode; - uint8_t *vram; - uint8_t *b8000; - int linepos; - int displine; - int sc; - int vc; - int dispon; - int con; - int cursoron; - int blink; - int vsynctime; - int fullchange; - int vadj; - uint16_t ma; - uint16_t maback; - uint64_t dispontime; - uint64_t dispofftime; - pc_timer_t timer; - int firstline; - int lastline; - int composite; - int apply_hd; - /* Keyboard Controller stuff. */ - int latched; - int data; - int serial_data[44]; - int serial_pos; - uint8_t pa; - uint8_t pb; - pc_timer_t send_delay_timer; -} pcjr_t; +static uint8_t key_queue[16]; +static int key_queue_start = 0; +static int key_queue_end = 0; /*PCjr keyboard has no escape scancodes, and no scancodes beyond 54 Map right alt to 54h (FN) */ @@ -626,643 +586,6 @@ const scancode scancode_pcjr[512] = { // clang-format on }; -static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ - -static uint8_t crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static uint8_t key_queue[16]; -static int key_queue_start = 0; -static int key_queue_end = 0; - -static void -recalc_address(pcjr_t *pcjr) -{ - uint8_t masked_memctrl = pcjr->memctrl; - - /* According to the Technical Reference, bits 2 and 5 are - ignored if there is only 64k of RAM and there are only - 4 pages. */ - if (mem_size < 128) - masked_memctrl &= ~0x24; - - if ((pcjr->memctrl & 0xc0) == 0xc0) { - pcjr->vram = &ram[(masked_memctrl & 0x06) << 14]; - pcjr->b8000 = &ram[(masked_memctrl & 0x30) << 11]; - } else { - pcjr->vram = &ram[(masked_memctrl & 0x07) << 14]; - pcjr->b8000 = &ram[(masked_memctrl & 0x38) << 11]; - } -} - -static void -recalc_timings(pcjr_t *pcjr) -{ - double _dispontime; - double _dispofftime; - double disptime; - - if (pcjr->array[0] & 1) { - disptime = pcjr->crtc[0] + 1; - _dispontime = pcjr->crtc[1]; - } else { - disptime = (pcjr->crtc[0] + 1) << 1; - _dispontime = pcjr->crtc[1] << 1; - } - - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST; - _dispofftime *= CGACONST; - pcjr->dispontime = (uint64_t) (_dispontime); - pcjr->dispofftime = (uint64_t) (_dispofftime); -} - -static int -vid_get_h_overscan_size(pcjr_t *pcjr) -{ - int ret; - - if (pcjr->array[0] & 1) - ret = 128; - else - ret = 256; - - return ret; -} - -static void -vid_out(uint16_t addr, uint8_t val, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint8_t old; - - switch (addr) { - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - pcjr->crtcreg = val & 0x1f; - return; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - old = pcjr->crtc[pcjr->crtcreg]; - pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; - if (pcjr->crtcreg == 2) - overscan_x = vid_get_h_overscan_size(pcjr); - if (old != val) { - if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { - pcjr->fullchange = changeframecount; - recalc_timings(pcjr); - } - } - return; - - case 0x3da: - if (!pcjr->array_ff) - pcjr->array_index = val & 0x1f; - else { - if (pcjr->array_index & 0x10) - val &= 0x0f; - pcjr->array[pcjr->array_index & 0x1f] = val; - if (!(pcjr->array_index & 0x1f)) - update_cga16_color(val); - } - pcjr->array_ff = !pcjr->array_ff; - break; - - case 0x3df: - pcjr->memctrl = val; - pcjr->pa = val; /* The PCjr BIOS expects the value written to 3DF to - then be readable from port 60, others it errors out - with only 64k RAM set (but somehow, still works with - 128k or more RAM). */ - pcjr->addr_mode = val >> 6; - recalc_address(pcjr); - break; - - default: - break; - } -} - -static uint8_t -vid_in(uint16_t addr, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - ret = pcjr->crtcreg; - break; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - ret = pcjr->crtc[pcjr->crtcreg]; - break; - - case 0x3da: - pcjr->array_ff = 0; - pcjr->stat ^= 0x10; - ret = pcjr->stat; - break; - - default: - break; - } - - return ret; -} - -static void -vid_write(uint32_t addr, uint8_t val, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - - if (pcjr->memctrl == -1) - return; - - pcjr->b8000[addr & 0x3fff] = val; -} - -static uint8_t -vid_read(uint32_t addr, void *priv) -{ - const pcjr_t *pcjr = (pcjr_t *) priv; - - if (pcjr->memctrl == -1) - return 0xff; - - return (pcjr->b8000[addr & 0x3fff]); -} - -static int -vid_get_h_overscan_delta(pcjr_t *pcjr) -{ - int def; - int coef; - int ret; - - switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { - case 0x13: /*320x200x16*/ - def = 0x56; - coef = 8; - break; - case 0x12: /*160x200x16*/ - def = 0x2c; /* I'm going to assume a datasheet erratum here. */ - coef = 16; - break; - case 0x03: /*640x200x4*/ - def = 0x56; - coef = 8; - break; - case 0x01: /*80 column text*/ - def = 0x5a; - coef = 8; - break; - case 0x00: /*40 column text*/ - default: - def = 0x2c; - coef = 16; - break; - case 0x02: /*320x200x4*/ - def = 0x2b; - coef = 16; - break; - case 0x102: /*640x200x2*/ - def = 0x2b; - coef = 16; - break; - } - - ret = pcjr->crtc[0x02] - def; - - if (ret < -8) - ret = -8; - - if (ret > 8) - ret = 8; - - return ret * coef; -} - -static void -vid_blit_h_overscan(pcjr_t *pcjr) -{ - int cols = (pcjr->array[2] & 0xf) + 16;; - int y0 = pcjr->firstline << 1; - int y = (pcjr->lastline << 1) + 16; - int ho_s = vid_get_h_overscan_size(pcjr); - int i; - int x; - - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - - for (i = 0; i < 16; i++) { - hline(buffer32, 0, y0 + i, x, cols); - hline(buffer32, 0, y + i, x, cols); - - if (pcjr->composite) { - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y0 + i]); - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y + i]); - } else { - video_process_8(x, y0 + i); - video_process_8(x, y + i); - } - } -} - -static void -vid_poll(void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint16_t dat; - int cols[4]; - int oldsc; - int l = (pcjr->displine << 1) + 16; - int ho_s = vid_get_h_overscan_size(pcjr); - int ho_d = vid_get_h_overscan_delta(pcjr) + (ho_s / 2); - - if (!pcjr->linepos) { - timer_advance_u64(&pcjr->timer, pcjr->dispofftime); - pcjr->stat &= ~1; - pcjr->linepos = 1; - oldsc = pcjr->sc; - if ((pcjr->crtc[8] & 3) == 3) - pcjr->sc = (pcjr->sc << 1) & 7; - if (pcjr->dispon) { - uint16_t offset = 0; - uint16_t mask = 0x1fff; - - if (pcjr->displine < pcjr->firstline) { - pcjr->firstline = pcjr->displine; - video_wait_for_buffer(); - } - pcjr->lastline = pcjr->displine; - cols[0] = (pcjr->array[2] & 0xf) + 16; - - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - } - - switch (pcjr->addr_mode) { - case 0: /*Alpha*/ - offset = 0; - mask = 0x3fff; - break; - case 1: /*Low resolution graphics*/ - offset = (pcjr->sc & 1) * 0x2000; - break; - case 3: /*High resolution graphics*/ - offset = (pcjr->sc & 3) * 0x2000; - break; - default: - break; - } - switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { - case 0x13: /*320x200x16*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = - buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = - pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = - buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = - pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = - buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = - pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = - buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = - pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; - } - break; - case 0x12: /*160x200x16*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = - buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = - buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = - buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = - pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = - buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = - buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = - buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = - pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 8] = buffer32->line[l][ef_x + 9] = - buffer32->line[l][ef_x + 10] = buffer32->line[l][ef_x + 11] = - buffer32->line[l + 1][ef_x + 8] = buffer32->line[l + 1][ef_x + 9] = - buffer32->line[l + 1][ef_x + 10] = buffer32->line[l + 1][ef_x + 11] = - pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 12] = buffer32->line[l][ef_x + 13] = - buffer32->line[l][ef_x + 14] = buffer32->line[l][ef_x + 15] = - buffer32->line[l + 1][ef_x + 12] = buffer32->line[l + 1][ef_x + 13] = - buffer32->line[l + 1][ef_x + 14] = buffer32->line[l + 1][ef_x + 15] = - pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; - } - break; - case 0x03: /*640x200x4*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - pcjr->ma++; - for (uint8_t c = 0; c < 8; c++) { - chr = (dat >> 7) & 1; - chr |= ((dat >> 14) & 2); - buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = - pcjr->array[(chr & pcjr->array[1] & 0x0f) + 16] + 16; - dat <<= 1; - } - } - break; - case 0x01: /*80 column text*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); - if (pcjr->array[3] & 4) { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - } - if (pcjr->sc & 8) - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + c] = - buffer32->line[l + 1][ef_x + c] = cols[0]; - else - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + c] = - buffer32->line[l + 1][ef_x + c] = - cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - if (drawcursor) - for (uint8_t c = 0; c < 8; c++) { - buffer32->line[l][ef_x + c] ^= 15; - buffer32->line[l + 1][ef_x + c] ^= 15; - } - pcjr->ma++; - } - break; - case 0x00: /*40 column text*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); - if (pcjr->array[3] & 4) { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - } - pcjr->ma++; - if (pcjr->sc & 8) - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[0]; - else - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = - cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - if (drawcursor) - for (uint8_t c = 0; c < 16; c++) { - buffer32->line[l][ef_x + c] ^= 15; - buffer32->line[l + 1][ef_x + c] ^= 15; - } - } - break; - case 0x02: /*320x200x4*/ - cols[0] = pcjr->array[0 + 16] + 16; - cols[1] = pcjr->array[1 + 16] + 16; - cols[2] = pcjr->array[2 + 16] + 16; - cols[3] = pcjr->array[3 + 16] + 16; - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - for (uint8_t c = 0; c < 8; c++) { - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[dat >> 14]; - dat <<= 2; - } - } - break; - case 0x102: /*640x200x2*/ - cols[0] = pcjr->array[0 + 16] + 16; - cols[1] = pcjr->array[1 + 16] + 16; - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - for (uint8_t c = 0; c < 16; c++) { - buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = - cols[dat >> 15]; - dat <<= 1; - } - } - break; - - default: - break; - } - } else { - if (pcjr->array[3] & 4) { - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); - } - } else { - cols[0] = pcjr->array[0 + 16] + 16; - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - } - } - } - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - if (pcjr->composite) { - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l]); - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l + 1]); - } else { - video_process_8(x, l); - video_process_8(x, l + 1); - } - pcjr->sc = oldsc; - if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { - pcjr->stat |= 8; - } - pcjr->displine++; - if (pcjr->displine >= 360) - pcjr->displine = 0; - } else { - timer_advance_u64(&pcjr->timer, pcjr->dispontime); - if (pcjr->dispon) - pcjr->stat |= 1; - pcjr->linepos = 0; - if (pcjr->vsynctime) { - pcjr->vsynctime--; - if (!pcjr->vsynctime) { - pcjr->stat &= ~8; - } - } - if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { - pcjr->con = 0; - } - if (pcjr->vadj) { - pcjr->sc++; - pcjr->sc &= 31; - pcjr->ma = pcjr->maback; - pcjr->vadj--; - if (!pcjr->vadj) { - pcjr->dispon = 1; - pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; - pcjr->sc = 0; - } - } else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) { - pcjr->maback = pcjr->ma; - pcjr->sc = 0; - oldvc = pcjr->vc; - pcjr->vc++; - pcjr->vc &= 127; - if (pcjr->vc == pcjr->crtc[6]) - pcjr->dispon = 0; - if (oldvc == pcjr->crtc[4]) { - pcjr->vc = 0; - pcjr->vadj = pcjr->crtc[5]; - if (!pcjr->vadj) - pcjr->dispon = 1; - if (!pcjr->vadj) - pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; - if ((pcjr->crtc[10] & 0x60) == 0x20) - pcjr->cursoron = 0; - else - pcjr->cursoron = pcjr->blink & 16; - } - if (pcjr->vc == pcjr->crtc[7]) { - pcjr->dispon = 0; - pcjr->displine = 0; - pcjr->vsynctime = 16; - picint(1 << 5); - if (pcjr->crtc[7]) { - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - pcjr->lastline++; - - xs_temp = x; - ys_temp = (pcjr->lastline - pcjr->firstline) << 1; - - if ((xs_temp > 0) && (ys_temp > 0)) { - int actual_ys = ys_temp; - - if (xs_temp < 64) - xs_temp = 656; - if (ys_temp < 32) - ys_temp = 400; - if (!enable_overscan) - xs_temp -= ho_s; - - 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)); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - vid_blit_h_overscan(pcjr); - - if (enable_overscan) { - video_blit_memtoscreen(0, pcjr->firstline << 1, - xsize, actual_ys + 32); - } else if (pcjr->apply_hd) { - video_blit_memtoscreen(ho_s / 2, (pcjr->firstline << 1) + 16, - xsize, actual_ys); - } else { - video_blit_memtoscreen(ho_d, (pcjr->firstline << 1) + 16, - xsize, actual_ys); - } - } - - frames++; - video_res_x = xsize; - video_res_y = ysize; - } - pcjr->firstline = 1000; - pcjr->lastline = 0; - pcjr->blink++; - } - } else { - pcjr->sc++; - pcjr->sc &= 31; - pcjr->ma = pcjr->maback; - } - if (pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1))) - pcjr->con = 1; - } -} static void kbd_write(uint16_t port, uint8_t val, void *priv) @@ -1433,35 +756,7 @@ speed_changed(void *priv) { pcjr_t *pcjr = (pcjr_t *) priv; - recalc_timings(pcjr); -} - -static void -pcjr_vid_init(pcjr_t *pcjr) -{ - int display_type; - - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); - - pcjr->memctrl = -1; - if (mem_size < 128) - pcjr->memctrl &= ~0x24; - - display_type = device_get_config_int("display_type"); - pcjr->composite = (display_type != PCJR_RGB); - pcjr->apply_hd = device_get_config_int("apply_hd"); - overscan_x = 256; - overscan_y = 32; - - mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, pcjr); - io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); - timer_add(&pcjr->timer, vid_poll, pcjr, 1); - - cga_palette = 0; - cgapal_rebuild(); + pcjr_recalc_timings(pcjr); } void diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 4d0768378..69200febe 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -44,12 +44,9 @@ #include <86box/video.h> #include <86box/vid_cga_comp.h> #include <86box/machine.h> +#include <86box/m_tandy.h> #include <86box/plat_unused.h> -enum { - TANDY_RGB = 0, - TANDY_COMPOSITE -}; enum { TYPE_TANDY = 0, @@ -65,79 +62,6 @@ enum { EEPROM_WRITE }; -typedef struct t1kvid_t { - mem_mapping_t mapping; - mem_mapping_t vram_mapping; - - uint8_t crtc[32]; - int crtcreg; - - int array_index; - uint8_t array[256]; - int memctrl; - uint8_t mode; - uint8_t col; - uint8_t stat; - - uint8_t *vram; - uint8_t *b8000; - uint32_t b8000_mask; - uint32_t b8000_limit; - uint8_t planar_ctrl; - uint8_t lp_strobe; - - int linepos; - int displine; - int sc; - int vc; - int dispon; - int con; - int cursoron; - int blink; - int fullchange; - int vsynctime; - int vadj; - uint16_t ma; - uint16_t maback; - - uint64_t dispontime; - uint64_t dispofftime; - pc_timer_t timer; - int firstline; - int lastline; - - int composite; -} t1kvid_t; - -typedef struct t1keep_t { - char *path; - - int state; - int count; - int addr; - int clk; - uint16_t data; - uint16_t store[64]; -} t1keep_t; - -typedef struct tandy_t { - mem_mapping_t ram_mapping; - mem_mapping_t rom_mapping; /* SL2 */ - - uint8_t *rom; /* SL2 */ - uint8_t ram_bank; - uint8_t rom_bank; /* SL2 */ - int rom_offset; /* SL2 */ - - uint32_t base; - uint32_t mask; - int is_hx; - int is_sl2; - - t1kvid_t *vid; -} tandy_t; - -static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ static const scancode scancode_tandy[512] = { // clang-format off @@ -655,22 +579,8 @@ static const scancode scancode_tandy[512] = { { .mk = { 0 }, .brk = { 0 } } /* 1ff */ // clang-format on }; -static uint8_t crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static uint8_t crtcmask_sl[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static int eep_data_out; -static uint8_t vid_in(uint16_t addr, void *priv); -static void vid_out(uint16_t addr, uint8_t val, void *priv); +static int eep_data_out; #ifdef ENABLE_TANDY_LOG int tandy_do_log = ENABLE_TANDY_LOG; @@ -690,762 +600,7 @@ tandy_log(const char *fmt, ...) # define tandy_log(fmt, ...) #endif -static void -recalc_mapping(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - mem_mapping_disable(&vid->mapping); - io_removehandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - - if (vid->planar_ctrl & 4) { - mem_mapping_enable(&vid->mapping); - if (vid->array[5] & 1) - mem_mapping_set_addr(&vid->mapping, 0xa0000, 0x10000); - else - mem_mapping_set_addr(&vid->mapping, 0xb8000, 0x8000); - io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - } -} - -static void -recalc_timings(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - double _dispontime; - double _dispofftime; - double disptime; - - if (vid->mode & 1) { - disptime = vid->crtc[0] + 1; - _dispontime = vid->crtc[1]; - } else { - disptime = (vid->crtc[0] + 1) << 1; - _dispontime = vid->crtc[1] << 1; - } - - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST; - _dispofftime *= CGACONST; - vid->dispontime = (uint64_t) (_dispontime); - vid->dispofftime = (uint64_t) (_dispofftime); -} - -static void -recalc_address(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - if ((vid->memctrl & 0xc0) == 0xc0) { - vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; - vid->b8000_mask = 0x7fff; - } else { - vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; - vid->b8000_mask = 0x3fff; - } -} - -static void -recalc_address_sl(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - vid->b8000_limit = 0x8000; - - if (vid->array[5] & 1) { - vid->vram = &ram[((vid->memctrl & 0x04) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x20) << 11) + dev->base]; - } else if ((vid->memctrl & 0xc0) == 0xc0) { - vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; - } else { - vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; - if ((vid->memctrl & 0x38) == 0x38) - vid->b8000_limit = 0x4000; - } -} - -static void -vid_update_latch(t1kvid_t *vid) -{ - uint32_t lp_latch = vid->displine * vid->crtc[1]; - - vid->crtc[0x10] = (lp_latch >> 8) & 0x3f; - vid->crtc[0x11] = lp_latch & 0xff; -} - -static void -vid_out(uint16_t addr, uint8_t val, void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint8_t old; - - if ((addr >= 0x3d0) && (addr <= 0x3d7)) - addr = (addr & 0xff9) | 0x004; - - switch (addr) { - case 0x03d4: - vid->crtcreg = val & 0x1f; - break; - - case 0x03d5: - old = vid->crtc[vid->crtcreg]; - if (dev->is_sl2) - vid->crtc[vid->crtcreg] = val & crtcmask_sl[vid->crtcreg]; - else - vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; - if (old != val) { - if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - vid->fullchange = changeframecount; - recalc_timings(dev); - } - } - break; - - case 0x03d8: - old = vid->mode; - vid->mode = val; - if ((old ^ val) & 0x01) - recalc_timings(dev); - if (!dev->is_sl2) - update_cga16_color(vid->mode); - break; - - case 0x03d9: - vid->col = val; - break; - - case 0x03da: - vid->array_index = val & 0x1f; - break; - - case 0x3db: - if (!dev->is_sl2 && (vid->lp_strobe == 1)) - vid->lp_strobe = 0; - break; - - case 0x3dc: - if (!dev->is_sl2 && (vid->lp_strobe == 0)) { - vid->lp_strobe = 1; - vid_update_latch(vid); - } - break; - - case 0x03de: - if (vid->array_index & 16) - val &= 0xf; - vid->array[vid->array_index & 0x1f] = val; - if (dev->is_sl2) { - if ((vid->array_index & 0x1f) == 5) { - recalc_mapping(dev); - recalc_address_sl(dev); - } - } - break; - - case 0x03df: - vid->memctrl = val; - if (dev->is_sl2) - recalc_address_sl(dev); - else - recalc_address(dev); - break; - - case 0x0065: - if (val == 8) - return; /*Hack*/ - vid->planar_ctrl = val; - recalc_mapping(dev); - break; - - default: - break; - } -} - -static uint8_t -vid_in(uint16_t addr, void *priv) -{ - const tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint8_t ret = 0xff; - - if ((addr >= 0x3d0) && (addr <= 0x3d7)) - addr = (addr & 0xff9) | 0x004; - - switch (addr) { - case 0x03d4: - ret = vid->crtcreg; - break; - - case 0x03d5: - ret = vid->crtc[vid->crtcreg]; - break; - - case 0x03da: - ret = vid->stat; - break; - - case 0x3db: - if (!dev->is_sl2 && (vid->lp_strobe == 1)) - vid->lp_strobe = 0; - break; - - case 0x3dc: - if (!dev->is_sl2 && (vid->lp_strobe == 0)) { - vid->lp_strobe = 1; - vid_update_latch(vid); - } - break; - - default: - break; - } - - return ret; -} - -static void -vid_write(uint32_t addr, uint8_t val, void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - - if (vid->memctrl == -1) - return; - - if (dev->is_sl2) { - if (vid->array[5] & 1) - vid->b8000[addr & 0xffff] = val; - else { - if ((addr & 0x7fff) < vid->b8000_limit) - vid->b8000[addr & 0x7fff] = val; - } - } else { - vid->b8000[addr & vid->b8000_mask] = val; - } -} - -static uint8_t -vid_read(uint32_t addr, void *priv) -{ - const tandy_t *dev = (tandy_t *) priv; - const t1kvid_t *vid = dev->vid; - - if (vid->memctrl == -1) - return 0xff; - - if (dev->is_sl2) { - if (vid->array[5] & 1) - return (vid->b8000[addr & 0xffff]); - if ((addr & 0x7fff) < vid->b8000_limit) - return (vid->b8000[addr & 0x7fff]); - else - return 0xff; - } else { - return (vid->b8000[addr & vid->b8000_mask]); - } -} - -static void -vid_poll(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x; - int c; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint16_t dat; - int cols[4]; - int col; - int oldsc; - - if (!vid->linepos) { - timer_advance_u64(&vid->timer, vid->dispofftime); - vid->stat |= 1; - vid->linepos = 1; - oldsc = vid->sc; - if ((vid->crtc[8] & 3) == 3) - vid->sc = (vid->sc << 1) & 7; - if (vid->dispon) { - if (vid->displine < vid->firstline) { - vid->firstline = vid->displine; - video_wait_for_buffer(); - } - vid->lastline = vid->displine; - cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < 8; c++) { - if (vid->array[3] & 4) { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = cols[0]; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = cols[0]; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = cols[0]; - } - } else if ((vid->mode & 0x12) == 0x12) { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = 0; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; - } - } else { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->col & 15) + 16; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; - } - } - } - if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ - for (x = 0; x < vid->crtc[1] * 2; x++) { - dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | vid->vram[((vid->ma << 1) + 1) & 0xffff]; - vid->ma++; - buffer32->line[vid->displine << 1][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 11] = 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->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - buffer32->line[vid->displine << 1][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = buffer32->line[vid->displine << 1][(x << 3) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 10] = buffer32->line[vid->displine << 1][(x << 3) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 12] = buffer32->line[vid->displine << 1][(x << 3) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 14] = buffer32->line[vid->displine << 1][(x << 3) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; - } - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - for (x = 0; x < vid->crtc[1]; x++) { - if (dev->is_sl2) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - } else { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - } - vid->ma++; - buffer32->line[vid->displine << 1][(x << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 8] = buffer32->line[vid->displine << 1][(x << 4) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 9] = buffer32->line[vid->displine << 1][(x << 4) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 10] = buffer32->line[vid->displine << 1][(x << 4) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 12] = buffer32->line[vid->displine << 1][(x << 4) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 13] = buffer32->line[vid->displine << 1][(x << 4) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 14] = buffer32->line[vid->displine << 1][(x << 4) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 16] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 16] = buffer32->line[vid->displine << 1][(x << 4) + 17] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 17] = buffer32->line[vid->displine << 1][(x << 4) + 18] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 18] = buffer32->line[vid->displine << 1][(x << 4) + 19] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 20] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 20] = buffer32->line[vid->displine << 1][(x << 4) + 21] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 21] = buffer32->line[vid->displine << 1][(x << 4) + 22] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 22] = buffer32->line[vid->displine << 1][(x << 4) + 23] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 23] = 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++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - chr = (dat >> 6) & 2; - chr |= ((dat >> 15) & 1); - buffer32->line[vid->displine << 1][(x << 3) + 8 + c] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; - dat <<= 1; - } - } - } else if (vid->mode & 1) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - if (vid->sc & 8) { - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[0]; - } - } else { - for (c = 0; c < 8; c++) { - if (vid->sc == 8) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - } else { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } - if (drawcursor) { - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] ^= 15; - buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] ^= 15; - } - } - vid->ma++; - } - } else if (!(vid->mode & 2)) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - vid->ma++; - if (vid->sc & 8) { - for (c = 0; c < 8; c++) - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; - } else { - for (c = 0; c < 8; c++) { - if (vid->sc == 8) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - } else { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } - if (drawcursor) { - for (c = 0; c < 16; c++) { - buffer32->line[vid->displine << 1][(x << 4) + c + 8] ^= 15; - buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] ^= 15; - } - } - } - } else if (!(vid->mode & 16)) { - cols[0] = (vid->col & 15); - col = (vid->col & 16) ? 8 : 0; - if (vid->mode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (vid->col & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - cols[0] = vid->array[(cols[0] & vid->array[1]) + 16] + 16; - cols[1] = vid->array[(cols[1] & vid->array[1]) + 16] + 16; - cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; - cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } else { - cols[0] = 0; - cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 16; c++) { - buffer32->line[vid->displine << 1][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = cols[dat >> 15]; - dat <<= 1; - } - } - } - } else { - if (vid->array[3] & 4) { - if (vid->mode & 1) { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - } else { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - } - } else { - cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; - if (vid->mode & 1) { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); - } else { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, cols[0]); - } - } - } - - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - if (!dev->is_sl2 && vid->composite) { - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine << 1]); - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1) + 1]); - } else { - video_process_8(x, vid->displine << 1); - video_process_8(x, (vid->displine << 1) + 1); - } - vid->sc = oldsc; - if (vid->vc == vid->crtc[7] && !vid->sc) - vid->stat |= 8; - vid->displine++; - if (vid->displine >= 360) - vid->displine = 0; - } else { - timer_advance_u64(&vid->timer, vid->dispontime); - if (vid->dispon) - vid->stat &= ~1; - vid->linepos = 0; - if (vid->vsynctime) { - vid->vsynctime--; - if (!vid->vsynctime) - vid->stat &= ~8; - } - if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { - vid->con = 0; - } - if (vid->vadj) { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - vid->vadj--; - if (!vid->vadj) { - vid->dispon = 1; - if (dev->is_sl2 && (vid->array[5] & 1)) - vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); - else - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - vid->sc = 0; - } - } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { - vid->maback = vid->ma; - vid->sc = 0; - oldvc = vid->vc; - vid->vc++; - if (dev->is_sl2) - vid->vc &= 255; - else - vid->vc &= 127; - if (vid->vc == vid->crtc[6]) - vid->dispon = 0; - if (oldvc == vid->crtc[4]) { - vid->vc = 0; - vid->vadj = vid->crtc[5]; - if (!vid->vadj) - vid->dispon = 1; - if (!vid->vadj) { - if (dev->is_sl2 && (vid->array[5] & 1)) - vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); - else - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - } - if ((vid->crtc[10] & 0x60) == 0x20) - vid->cursoron = 0; - else - vid->cursoron = vid->blink & 16; - } - if (vid->vc == vid->crtc[7]) { - vid->dispon = 0; - vid->displine = 0; - vid->vsynctime = 16; - picint(1 << 5); - if (vid->crtc[7]) { - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - vid->lastline++; - - xs_temp = x; - ys_temp = (vid->lastline - vid->firstline) << 1; - - if ((xs_temp > 0) && (ys_temp > 0)) { - if (xs_temp < 64) - xs_temp = 656; - if (ys_temp < 32) - ys_temp = 400; - if (!enable_overscan) - xs_temp -= 16; - - 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)); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - if (enable_overscan) { - video_blit_memtoscreen(0, (vid->firstline - 4) << 1, - xsize, ((vid->lastline - vid->firstline) + 8) << 1); - } else { - video_blit_memtoscreen(8, vid->firstline << 1, - xsize, (vid->lastline - vid->firstline) << 1); - } - } - - frames++; - - video_res_x = xsize; - video_res_y = ysize; - if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ - video_res_x /= 2; - video_bpp = 4; - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - video_res_x /= 4; - video_bpp = 4; - } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - video_bpp = 2; - } else if (vid->mode & 1) { - video_res_x /= 8; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (!(vid->mode & 2)) { - video_res_x /= 16; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (!(vid->mode & 16)) { - video_res_x /= 2; - video_bpp = 2; - } else { - video_bpp = 1; - } - } - vid->firstline = 1000; - vid->lastline = 0; - vid->blink++; - } - } else { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - } - if (vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1))) - vid->con = 1; - } -} - -static void -vid_speed_changed(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - - recalc_timings(dev); -} - -static void -vid_close(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - - free(dev->vid); - dev->vid = NULL; -} - -static void -vid_init(tandy_t *dev) -{ - int display_type; - t1kvid_t *vid; - - vid = calloc(1, sizeof(t1kvid_t)); - vid->memctrl = -1; - - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); - - display_type = device_get_config_int("display_type"); - vid->composite = (display_type != TANDY_RGB); - - cga_comp_init(1); - - if (dev->is_sl2) { - vid->b8000_limit = 0x8000; - vid->planar_ctrl = 4; - overscan_x = overscan_y = 16; - - io_sethandler(0x0065, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - } else - vid->b8000_mask = 0x3fff; - - timer_add(&vid->timer, vid_poll, dev, 1); - mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); - io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - - dev->vid = vid; -} - -const device_config_t vid_config[] = { - // clang-format off - { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = TANDY_RGB, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "RGB", .value = TANDY_RGB }, - { .description = "Composite", .value = TANDY_COMPOSITE }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -const device_t vid_device = { - .name = "Tandy 1000", - .internal_name = "tandy1000_video", - .flags = 0, - .local = 0, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = vid_config -}; - -const device_t vid_device_hx = { - .name = "Tandy 1000 HX", - .internal_name = "tandy1000_hx_video", - .flags = 0, - .local = 0, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = vid_config -}; - -const device_t vid_device_sl = { - .name = "Tandy 1000SL2", - .internal_name = "tandy1000_sl_video", - .flags = 0, - .local = 1, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = NULL -}; static void eep_write(UNUSED(uint16_t addr), uint8_t val, void *priv) @@ -1630,12 +785,12 @@ tandy_write(uint16_t addr, uint8_t val, void *priv) } if (dev->is_hx) { io_removehandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); if (val & 0x01) mem_mapping_disable(&dev->vid->mapping); else { io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); mem_mapping_set_addr(&dev->vid->mapping, 0xb8000, 0x8000); } } else { @@ -1654,7 +809,7 @@ tandy_write(uint16_t addr, uint8_t val, void *priv) mem_mapping_set_addr(&dev->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); - recalc_address_sl(dev); + tandy_recalc_address_sl(dev); dev->ram_bank = val; break; @@ -1803,10 +958,10 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device); - vid_init(dev); + device_context(&tandy_1000_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device, dev); + device_add_ex(&tandy_1000_video_device, dev); device_add((type == TYPE_TANDY1000SX) ? &ncr8496_device : &sn76489_device); break; @@ -1815,10 +970,10 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device_hx); - vid_init(dev); + device_context(&tandy_1000hx_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device_hx, dev); + device_add_ex(&tandy_1000hx_video_device, dev); device_add(&ncr8496_device); device_add(&eep_1000hx_device); break; @@ -1828,10 +983,10 @@ machine_tandy1k_init(const machine_t *model, int type) init_rom(dev); io_sethandler(0xffe8, 8, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device_sl); - vid_init(dev); + device_context(&tandy_1000sl_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device_sl, dev); + device_add_ex(&tandy_1000sl_video_device, dev); device_add(&pssj_device); device_add(&eep_1000sl2_device); break; diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index acdb77fd1..8e37dce1f 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -1918,7 +1918,7 @@ m19_vid_out(uint16_t addr, uint8_t val, void *priv) /* activating plantronics mode */ if (addr == 0x3dd) { /* already in graphics mode */ - if ((val & 0x30) && (vid->ogc.cga.cgamode & 0x2)) + if ((val & 0x30) && (vid->ogc.cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) vid->mode = PLANTRONICS_MODE; else vid->mode = OLIVETTI_OGC_MODE; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 13ac1bee1..28d4a9a6a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -39,8 +39,10 @@ // Temporarily here till we move everything out into the right files extern const device_t pcjr_device; extern const device_t m19_vid_device; -extern const device_t vid_device; -extern const device_t vid_device_hx; +extern const device_t tandy_1000_video_device; +extern const device_t tandy_1000hx_video_device; +extern const device_t tandy_1000sl_video_device; + extern const device_t t1000_video_device; extern const device_t xi8088_device; extern const device_t cga_device; @@ -50,7 +52,6 @@ extern const device_t vid_pc2086_device; extern const device_t vid_pc3086_device; extern const device_t vid_200_device; extern const device_t vid_ppc512_device; -extern const device_t vid_device_sl; extern const device_t t1200_video_device; extern const device_t compaq_plasma_device; extern const device_t ps1_2011_device; @@ -1591,7 +1592,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device, + .vid_device = &tandy_1000_video_device, .snd_device = NULL, .net_device = NULL }, @@ -1630,7 +1631,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device_hx, + .vid_device = &tandy_1000hx_video_device, .snd_device = NULL, .net_device = NULL }, @@ -2531,7 +2532,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device_sl, + .vid_device = &tandy_1000sl_video_device, .snd_device = NULL, .net_device = NULL }, diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 062fc272a..09c49dabe 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -11,20 +11,32 @@ # Authors: David Hrdlička, # # Copyright 2020-2021 David Hrdlička. +# Copyright 2025 starfrost # add_library(vid OBJECT agpgart.c video.c vid_table.c + # CGA vid_cga.c vid_cga_comp.c - vid_compaq_cga.c + vid_cga_compaq.c + vid_cga_compaq_plasma.c + vid_cga_colorplus.c + vid_cga_ncr.c + vid_cga_olivetti.c + vid_cga_toshiba_t1000.c + vid_cga_toshiba_t3100e.c + + # PCJr/Tandy + vid_pcjr.c + vid_tandy.c + vid_mda.c vid_hercules.c - vid_herculesplus.c - vid_incolor.c - vid_colorplus.c + vid_hercules_plus.c + vid_hercules_incolor.c vid_genius.c vid_pgc.c vid_im1024.c @@ -70,9 +82,7 @@ add_library(vid OBJECT vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c - vid_ogc.c vid_mga.c - vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 4a9a032c5..38dac61c7 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -75,7 +75,7 @@ cga_update_latch(cga_t *cga) { uint32_t lp_latch = cga->displine * cga->crtc[CGA_CRTC_HDISP]; - cga->crtc[0x10] = (lp_latch >> 8) & 0x3f; + cga->crtc[CGA_CRTC_LIGHT_PEN_ADDR_HIGH] = (lp_latch >> 8) & 0x3f; cga->crtc[CGA_CRTC_LIGHT_PEN_ADDR_LOW] = lp_latch & 0xff; } @@ -289,7 +289,7 @@ cga_render(cga_t *cga, int line) attr = cga->charbuffer[(x << 1) + 1]; } else chr = attr = 0; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + drawcursor = ((cga->ma == ca) && cga->cursorvisible && cga->cursoron); cols[1] = (attr & 15) + 16; if (cga->cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; @@ -310,14 +310,14 @@ cga_render(cga_t *cga, int line) } cga->ma++; } - } else if (!(cga->cgamode & 2)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { if (cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { chr = cga->vram[(cga->ma << 1) & 0x3fff]; attr = cga->vram[((cga->ma << 1) + 1) & 0x3fff]; } else chr = attr = 0; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + drawcursor = ((cga->ma == ca) && cga->cursorvisible && cga->cursoron); cols[1] = (attr & 15) + 16; if (cga->cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; @@ -594,7 +594,7 @@ cga_poll(void *priv) } if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_END] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { - cga->con = 0; + cga->cursorvisible = 0; } if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == (cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) cga->maback = cga->ma; @@ -625,6 +625,7 @@ cga_poll(void *priv) cga->cgadispon = 1; cga->ma = cga->maback = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; } + switch (cga->crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: cga->cursoron = 0; @@ -724,7 +725,7 @@ cga_poll(void *priv) cga->cgastat &= ~1; if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_START] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) - cga->con = 1; + cga->cursorvisible = 1; if (cga->cgadispon && (cga->cgamode & CGA_MODE_FLAG_HIGHRES)) { for (x = 0; x < (cga->crtc[CGA_CRTC_HDISP] << 1); x++) cga->charbuffer[x] = cga->vram[((cga->ma << 1) + x) & 0x3fff]; diff --git a/src/video/vid_colorplus.c b/src/video/vid_cga_colorplus.c similarity index 81% rename from src/video/vid_colorplus.c rename to src/video/vid_cga_colorplus.c index 7daba018e..efa8ab3a7 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_cga_colorplus.c @@ -37,16 +37,19 @@ #include <86box/plat_unused.h> /* Bits in the colorplus control register: */ -#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ -#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ -#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ -#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ +#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ +#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ +#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ +#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 -#define COMPOSITE_OLD 0 -#define COMPOSITE_NEW 1 +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +// Plantronics specific registers +#define COLORPLUS_CONTROL 0x3DD video_timings_t timing_colorplus = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; @@ -57,7 +60,7 @@ colorplus_out(uint16_t addr, uint8_t val, void *priv) { colorplus_t *colorplus = (colorplus_t *) priv; - if (addr == 0x3DD) { + if (addr == COLORPLUS_CONTROL) { colorplus->control = val & 0x70; } else { cga_out(addr, val, &colorplus->cga); @@ -147,7 +150,7 @@ colorplus_poll(void *priv) colorplus->cga.cgastat |= 1; colorplus->cga.linepos = 1; oldsc = colorplus->cga.sc; - if ((colorplus->cga.crtc[8] & 3) == 3) + if ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) colorplus->cga.sc = ((colorplus->cga.sc << 1) + colorplus->cga.oddeven) & 7; if (colorplus->cga.cgadispon) { if (colorplus->cga.displine < colorplus->cga.firstline) { @@ -157,10 +160,10 @@ colorplus_poll(void *priv) colorplus->cga.lastline = colorplus->cga.displine; /* Left / right border */ for (c = 0; c < 8; c++) { - buffer32->line[colorplus->cga.displine][c] = buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + buffer32->line[colorplus->cga.displine][c] = buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; } if (colorplus->control & COLORPLUS_320x200_MODE) { - for (x = 0; x < colorplus->cga.crtc[1]; x++) { + for (x = 0; x < colorplus->cga.crtc[CGA_CRTC_HDISP]; x++) { dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; colorplus->cga.ma++; @@ -173,7 +176,7 @@ colorplus_poll(void *priv) } else if (colorplus->control & COLORPLUS_640x200_MODE) { cols[0] = (colorplus->cga.cgacol & 15) | 16; col = (colorplus->cga.cgacol & 16) ? 24 : 16; - if (colorplus->cga.cgamode & 4) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; cols[2] = col | 4; cols[3] = col | 7; @@ -186,7 +189,7 @@ colorplus_poll(void *priv) cols[2] = col | 4; cols[3] = col | 6; } - for (x = 0; x < colorplus->cga.crtc[1]; x++) { + for (x = 0; x < colorplus->cga.crtc[CGA_CRTC_HDISP]; x++) { dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; colorplus->cga.ma++; @@ -200,10 +203,10 @@ colorplus_poll(void *priv) } else /* Top / bottom border */ { cols[0] = (colorplus->cga.cgacol & 15) + 16; - hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16, cols[0]); } - x = (colorplus->cga.crtc[1] << 4) + 16; + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; if (colorplus->cga.composite) Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); @@ -211,7 +214,7 @@ colorplus_poll(void *priv) video_process_8(x, colorplus->cga.displine); colorplus->cga.sc = oldsc; - if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VSYNC] && !colorplus->cga.sc) colorplus->cga.cgastat |= 8; colorplus->cga.displine++; if (colorplus->cga.displine >= 360) @@ -224,10 +227,11 @@ colorplus_poll(void *priv) if (!colorplus->cga.vsynctime) colorplus->cga.cgastat &= ~8; } - if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) { - colorplus->cga.con = 0; + if (colorplus->cga.sc == (colorplus->cga.crtc[CGA_CRTC_CURSOR_END] & 31) + || ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + colorplus->cga.cursorvisible = 0; } - if ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[9] >> 1)) + if ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) colorplus->cga.maback = colorplus->cga.ma; if (colorplus->cga.vadj) { colorplus->cga.sc++; @@ -236,41 +240,41 @@ colorplus_poll(void *priv) colorplus->cga.vadj--; if (!colorplus->cga.vadj) { colorplus->cga.cgadispon = 1; - colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; + colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (colorplus->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; colorplus->cga.sc = 0; } - } else if (colorplus->cga.sc == colorplus->cga.crtc[9]) { + } else if (colorplus->cga.sc == colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { colorplus->cga.maback = colorplus->cga.ma; colorplus->cga.sc = 0; oldvc = colorplus->cga.vc; colorplus->cga.vc++; colorplus->cga.vc &= 127; - if (colorplus->cga.vc == colorplus->cga.crtc[6]) + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VDISP]) colorplus->cga.cgadispon = 0; - if (oldvc == colorplus->cga.crtc[4]) { + if (oldvc == colorplus->cga.crtc[CGA_CRTC_VTOTAL]) { colorplus->cga.vc = 0; - colorplus->cga.vadj = colorplus->cga.crtc[5]; + colorplus->cga.vadj = colorplus->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!colorplus->cga.vadj) colorplus->cga.cgadispon = 1; if (!colorplus->cga.vadj) - colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; - if ((colorplus->cga.crtc[10] & 0x60) == 0x20) + colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (colorplus->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) colorplus->cga.cursoron = 0; else colorplus->cga.cursoron = colorplus->cga.cgablink & 8; } - if (colorplus->cga.vc == colorplus->cga.crtc[7]) { + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VSYNC]) { colorplus->cga.cgadispon = 0; colorplus->cga.displine = 0; colorplus->cga.vsynctime = 16; - if (colorplus->cga.crtc[7]) { - if (colorplus->cga.cgamode & 1) - x = (colorplus->cga.crtc[1] << 3) + 16; + if (colorplus->cga.crtc[CGA_CRTC_VSYNC]) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (colorplus->cga.crtc[1] << 4) + 16; + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; colorplus->cga.lastline++; if (x != xsize || (colorplus->cga.lastline - colorplus->cga.firstline) != ysize) { xsize = x; @@ -287,15 +291,15 @@ colorplus_poll(void *priv) video_res_x = xsize - 16; video_res_y = ysize; - if (colorplus->cga.cgamode & 1) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= colorplus->cga.crtc[9] + 1; + video_res_y /= colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(colorplus->cga.cgamode & 2)) { + } else if (!(colorplus->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= colorplus->cga.crtc[9] + 1; + video_res_y /= colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(colorplus->cga.cgamode & 16)) { + } else if (!(colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else { @@ -314,10 +318,10 @@ colorplus_poll(void *priv) } if (colorplus->cga.cgadispon) colorplus->cga.cgastat &= ~1; - if (colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1))) - colorplus->cga.con = 1; - if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & 1)) { - for (x = 0; x < (colorplus->cga.crtc[1] << 1); x++) + if (colorplus->cga.sc == (colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + colorplus->cga.cursorvisible = 1; + if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (colorplus->cga.crtc[CGA_CRTC_HDISP] << 1); x++) colorplus->cga.charbuffer[x] = colorplus->cga.vram[((colorplus->cga.ma << 1) + x) & 0x3fff]; } } diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index 6ad6a6b0a..ca9c2c9df 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -135,7 +135,7 @@ update_cga16_color(uint8_t cgamode) int left = (x >> 6) & 15; int rc = right; int lc = left; - if ((cgamode & 4) != 0) { + if ((cgamode & CGA_MODE_FLAG_BW) != 0) { rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); } @@ -240,7 +240,7 @@ Composite_Process(uint8_t cgamode, uint8_t border, uint32_t blocks /*, bool doub for (uint8_t x = 0; x < 5; ++x) OUT(b[x & 3]); - if ((cgamode & 4) != 0) { + if ((cgamode & CGA_MODE_FLAG_BW) != 0) { /* Decode */ i = temp + 5; srgb = TempLine; diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_cga_compaq.c similarity index 83% rename from src/video/vid_compaq_cga.c rename to src/video/vid_cga_compaq.c index 5b06e23d2..c36af38b1 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_cga_compaq.c @@ -68,9 +68,9 @@ compaq_cga_recalctimings(cga_t *dev) double _dispontime; double _dispofftime; double disptime; - disptime = dev->crtc[0] + 1; + disptime = dev->crtc[CGA_CRTC_HTOTAL] + 1; - _dispontime = dev->crtc[1]; + _dispontime = dev->crtc[CGA_CRTC_HDISP]; _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; @@ -81,24 +81,26 @@ compaq_cga_recalctimings(cga_t *dev) static void compaq_cga_poll(void *priv) { - cga_t *dev = (cga_t *) priv; - uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; - int underline = 0; - int blink = 0; - int drawcursor; - int x; - int c; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint8_t border; - uint8_t cols[4]; - int oldsc; + cga_t *dev = (cga_t *) priv; + uint16_t ca = (dev->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (dev->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; + int drawcursor; + int x; + int c; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint8_t border; + uint8_t cols[4]; + int oldsc; + int underline = 0; + int blink = 0; + + int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); /* If in graphics mode or character height is not 13, behave as CGA */ - if ((dev->cgamode & 0x12) || (dev->crtc[9] != 13)) { + if ((dev->cgamode & highres_graphics_flag) || (dev->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] != 13)) { overscan_x = overscan_y = 16; cga_poll(dev); return; @@ -111,7 +113,7 @@ compaq_cga_poll(void *priv) dev->cgastat |= 1; dev->linepos = 1; oldsc = dev->sc; - if ((dev->crtc[8] & 3) == 3) + if ((dev->crtc[CGA_CRTC_INTERLACE] & 3) == 3) dev->sc = ((dev->sc << 1) + dev->oddeven) & 7; if (dev->cgadispon) { if (dev->displine < dev->firstline) { @@ -125,21 +127,21 @@ compaq_cga_poll(void *priv) for (c = 0; c < 8; c++) { buffer32->line[dev->displine][c] = cols[0]; - if (dev->cgamode & 1) - buffer32->line[dev->displine][c + (dev->crtc[1] << 3) + 8] = cols[0]; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + buffer32->line[dev->displine][c + (dev->crtc[CGA_CRTC_HDISP] << 3) + 8] = cols[0]; else - buffer32->line[dev->displine][c + (dev->crtc[1] << 4) + 8] = cols[0]; + buffer32->line[dev->displine][c + (dev->crtc[CGA_CRTC_HDISP] << 4) + 8] = cols[0]; } - if (dev->cgamode & 1) { - for (x = 0; x < dev->crtc[1]; x++) { + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) { + for (x = 0; x < dev->crtc[CGA_CRTC_HDISP]; x++) { chr = dev->charbuffer[x << 1]; attr = dev->charbuffer[(x << 1) + 1]; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->ma == ca) && dev->cursorvisible && dev->cursoron); if (vflags) { underline = 0; - blink = ((dev->cgablink & 8) && (dev->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((dev->cgablink & 8) && (dev->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); } if (vflags && (dev->cgamode & 0x80)) { @@ -148,7 +150,7 @@ compaq_cga_poll(void *priv) if ((dev->sc == 12) && ((attr & 7) == 1)) underline = 1; - } else if (dev->cgamode & 0x20) { + } else if (dev->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; @@ -179,14 +181,14 @@ compaq_cga_poll(void *priv) dev->ma++; } } else { - for (x = 0; x < dev->crtc[1]; x++) { + for (x = 0; x < dev->crtc[CGA_CRTC_HDISP]; x++) { chr = dev->vram[(dev->ma << 1) & 0x3fff]; attr = dev->vram[((dev->ma << 1) + 1) & 0x3fff]; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->ma == ca) && dev->cursorvisible && dev->cursoron); if (vflags) { underline = 0; - blink = ((dev->cgablink & 8) && (dev->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((dev->cgablink & 8) && (dev->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); } if (vflags && (dev->cgamode & 0x80)) { @@ -194,7 +196,7 @@ compaq_cga_poll(void *priv) cols[1] = mdaattr[attr][blink][1]; if (dev->sc == 12 && (attr & 7) == 1) underline = 1; - } else if (dev->cgamode & 0x20) { + } else if (dev->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; @@ -231,19 +233,19 @@ compaq_cga_poll(void *priv) } else { cols[0] = (dev->cgacol & 15) + 16; - if (dev->cgamode & 1) - hline(buffer32, 0, dev->displine, (dev->crtc[1] << 3) + 16, cols[0]); + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + hline(buffer32, 0, dev->displine, (dev->crtc[CGA_CRTC_HDISP] << 3) + 16, cols[0]); else - hline(buffer32, 0, dev->displine, (dev->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, dev->displine, (dev->crtc[CGA_CRTC_HDISP] << 4) + 16, cols[0]); } - if (dev->cgamode & 1) - x = (dev->crtc[1] << 3) + 16; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (dev->crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (dev->crtc[1] << 4) + 16; + x = (dev->crtc[CGA_CRTC_HDISP] << 4) + 16; if (dev->composite) { - if (dev->cgamode & 0x10) + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) border = 0x00; else border = dev->cgacol & 0x0f; @@ -256,7 +258,7 @@ compaq_cga_poll(void *priv) video_process_8(x, dev->displine); dev->sc = oldsc; - if (dev->vc == dev->crtc[7] && !dev->sc) + if (dev->vc == dev->crtc[CGA_CRTC_VSYNC] && !dev->sc) dev->cgastat |= 8; dev->displine++; if (dev->displine >= 500) @@ -270,9 +272,8 @@ compaq_cga_poll(void *priv) dev->cgastat &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || (((dev->crtc[8] & 3) == 3) && - (dev->sc == ((dev->crtc[11] & 31) >> 1)))) { - dev->con = 0; + if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { + dev->cursorvisible = 0; } if ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1)) dev->maback = dev->ma; @@ -284,14 +285,14 @@ compaq_cga_poll(void *priv) if (!dev->vadj) { dev->cgadispon = 1; dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - dev->sc = 0; + dev->sc = 0; } } else if (dev->sc == dev->crtc[9]) { dev->maback = dev->ma; dev->sc = 0; - oldvc = dev->vc; + oldvc = dev->vc; dev->vc++; - dev->vc &= 127; + dev->vc &= 127; if (dev->vc == dev->crtc[6]) dev->cgadispon = 0; @@ -321,10 +322,10 @@ compaq_cga_poll(void *priv) compaq_cga_log("Lastline %i Firstline %i %i\n", dev->lastline, dev->firstline, dev->lastline - dev->firstline); - if (dev->cgamode & 1) - x = (dev->crtc[1] << 3) + 16; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (dev->crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (dev->crtc[1] << 4) + 16; + x = (dev->crtc[CGA_CRTC_HDISP] << 4) + 16; dev->lastline++; @@ -339,8 +340,7 @@ compaq_cga_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((dev->cgamode & 8) && ((xs_temp != xsize) || - (ys_temp != ysize) || video_force_resize_get())) { + if ((dev->cgamode & 8) && ((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)); @@ -361,7 +361,7 @@ compaq_cga_poll(void *priv) if (enable_overscan) xsize -= 16; video_res_y = ysize; - if (dev->cgamode & 1) { + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; video_res_y /= dev->crtc[9] + 1; video_bpp = 0; @@ -390,12 +390,11 @@ compaq_cga_poll(void *priv) if (dev->cgadispon) dev->cgastat &= ~1; - if (dev->sc == (dev->crtc[10] & 31) || - (((dev->crtc[8] & 3) == 3) && (dev->sc == ((dev->crtc[10] & 31) >> 1)))) - dev->con = 1; + if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) + dev->cursorvisible = 1; - if (dev->cgadispon && (dev->cgamode & 1)) { - for (x = 0; x < (dev->crtc[1] << 1); x++) + if (dev->cgadispon && (dev->cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (dev->crtc[CGA_CRTC_HDISP] << 1); x++) dev->charbuffer[x] = dev->vram[((dev->ma << 1) + x) & 0x3fff]; } } @@ -475,8 +474,7 @@ compaq_cga_speed_changed(void *priv) { cga_t *dev = (cga_t *) priv; - if (dev->crtc[9] == 13) - /* Character height */ + if (dev->crtc[9] == 13) /* Character height */ compaq_cga_recalctimings(dev); else cga_recalctimings(dev); diff --git a/src/video/vid_cga_compaq_plasma.c b/src/video/vid_cga_compaq_plasma.c new file mode 100644 index 000000000..feb9a12c8 --- /dev/null +++ b/src/video/vid_cga_compaq_plasma.c @@ -0,0 +1,784 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the plasma displays on early Compaq Portables and laptops. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2025 starfrost + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/vid_cga_comp.h> +#include <86box/plat_unused.h> + +static video_timings_t timing_compaq_plasma = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +/*Very rough estimate*/ +#define VID_CLOCK (double) (651 * 416 * 60) + +/* Mapping of attributes to colours */ +static uint32_t amber; +static uint32_t black; +static uint32_t blinkcols[256][2]; +static uint32_t normcols[256][2]; + +/* Video options set by the motherboard; they will be picked up by the card + * on the next poll. + * + * Bit 3: Disable built-in video (for add-on card) + * Bit 2: Thin font + * Bits 0,1: Font set (not currently implemented) + */ +static int8_t cpq_st_display_internal = -1; + +static uint8_t mdaattr[256][2][2]; + +static void +compaq_plasma_display_set(uint8_t internal) +{ + cpq_st_display_internal = internal; +} + +typedef struct compaq_plasma_t { + cga_t cga; + mem_mapping_t font_ram_mapping; + uint8_t *font_ram; + uint8_t port_13c6; + uint8_t port_23c6; + uint8_t port_27c6; + uint8_t internal_monitor; +} compaq_plasma_t; + + +static void compaq_plasma_recalcattrs(compaq_plasma_t *self); + +static void +compaq_plasma_recalctimings(compaq_plasma_t *self) +{ + double _dispontime; + double _dispofftime; + double disptime; + + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { + cga_recalctimings(&self->cga); + return; + } + + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); + self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); +} + +static void +compaq_plasma_waitstates(UNUSED(void *priv)) +{ + int ws_array[16] = { 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8 }; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + +static void +compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + if (self->port_23c6 & 0x08) + self->font_ram[addr & 0x1fff] = val; + else + self->cga.vram[addr & 0x7fff] = val; + + compaq_plasma_waitstates(&self->cga); +} +static uint8_t +compaq_plasma_read(uint32_t addr, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t ret; + + compaq_plasma_waitstates(&self->cga); + + if (self->port_23c6 & 0x08) + ret = (self->font_ram[addr & 0x1fff]); + else + ret = (self->cga.vram[addr & 0x7fff]); + + return ret; +} + +static void +compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + switch (addr) { + /* Emulated CRTC, register select */ + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + cga_out(addr, val, &self->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + cga_out(addr, val, &self->cga); + compaq_plasma_recalctimings(self); + break; + case 0x3d8: + case 0x3d9: + cga_out(addr, val, &self->cga); + break; + + case 0x13c6: + self->port_13c6 = val; + compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); + /* + For bits 2-0, John gives 0 = CGA, 1 = EGA, 3 = MDA; + Another source (Ralf Brown?) gives 4 = CGA, 5 = EGA, 7 = MDA; + This leads me to believe bit 2 is not relevant to the mode. + */ + if ((val & 0x03) == 0x03) + mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x08000); + else + mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x08000); + break; + + case 0x23c6: + self->port_23c6 = val; + compaq_plasma_recalcattrs(self); + break; + + case 0x27c6: + self->port_27c6 = val; + break; + + default: + break; + } +} + +static uint8_t +compaq_plasma_in(uint16_t addr, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d4: + case 0x3da: + case 0x3db: + case 0x3dc: + ret = cga_in(addr, &self->cga); + break; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + ret = cga_in(addr, &self->cga); + break; + + case 0x3d8: + ret = self->cga.cgamode; + break; + + case 0x13c6: + ret = self->port_13c6; +#if 0 + if ((self->cga.cgamode & 0x28) == 0x00) + ret |= 0x04; +#endif + break; + + case 0x17c6: + ret = 0xe6; + break; + + case 0x1bc6: + ret = 0x40; + break; + + case 0x23c6: + ret = self->port_23c6; + break; + + case 0x27c6: + ret = self->port_27c6 & 0x3f; + break; + + default: + break; + } + + return ret; +} + +static void +compaq_plasma_poll(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t chr; + uint8_t attr; + uint8_t sc; + uint16_t ma = (self->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (self->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t ca = (self->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (self->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t addr; + int drawcursor; + int cursorline; + int blink = 0; + int underline = 0; + int c; + int x; + uint32_t ink = 0; + uint32_t fg = (self->cga.cgacol & 0x0f) ? amber : black; + uint32_t bg = black; + uint32_t cols[2]; + uint8_t dat; + uint8_t pattern; + uint32_t ink0 = 0; + uint32_t ink1 = 0; + + /* Switch between internal plasma and external CRT display. */ + if ((cpq_st_display_internal != -1) && (cpq_st_display_internal != self->internal_monitor)) { + self->internal_monitor = cpq_st_display_internal; + compaq_plasma_recalctimings(self); + } + + /* graphic mode and not mode 40h */ + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { + /* standard cga mode */ + cga_poll(&self->cga); + return; + } else { + /* mode 40h or text mode */ + if (!self->cga.linepos) { + timer_advance_u64(&self->cga.timer, self->cga.dispofftime); + self->cga.cgastat |= 1; + self->cga.linepos = 1; + if (self->cga.cgadispon) { + if (self->cga.displine == 0) + video_wait_for_buffer(); + + /* 80-col */ + if (self->cga.cgamode & 0x01) { + sc = self->cga.displine & 0x0f; + addr = ((ma & ~1) + (self->cga.displine >> 4) * 80) << 1; + ma += (self->cga.displine >> 4) * 80; + + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = (((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) << 1) <= sc) && (((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) << 1) >= sc); + + /* for each text column */ + for (x = 0; x < 80; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else { + chr = 0x00; + attr = 0x00; + } + uint8_t hi_bit = attr & 0x08; + /* check if cursor has to be drawn */ + drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = ((attr & 0x07) == 0x01); + underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + + /* character address */ + uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && hi_bit) + chr_addr |= 0x1000; + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + + if (hi_bit) { + if ((self->port_23c6 >> 5) == 1) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] ^= (amber ^ black); + } else if ((self->port_23c6 >> 5) == 4) { + for (c = 0; c < 8; c++) { + uint32_t b = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 1) & 0x7f; + uint32_t g = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 9) & 0x7f; + uint32_t r = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 17) & 0x7f; + buffer32->line[self->cga.displine][(x << 3) + c] = b | (g << 8) || (r << 16); + } + } + } + ma++; + } + } + /* 40-col */ + else if (!(self->cga.cgamode & 0x02)) { + sc = self->cga.displine & 0x0f; + addr = ((ma & ~1) + (self->cga.displine >> 4) * 40) << 1; + ma += (self->cga.displine >> 4) * 40; + + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = (((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) << 1) <= sc) && (((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) << 1) >= sc); + + for (x = 0; x < 40; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else { + chr = 0x00; + attr = 0x00; + } + uint8_t hi_bit = attr & 0x08; + /* check if cursor has to be drawn */ + drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = ((attr & 0x07) == 0x01); + underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + + /* character address */ + uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && hi_bit) + chr_addr |= 0x1000; + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + + if (hi_bit) { + if ((self->port_23c6 >> 5) == 1) + for (c = 0; c < 8; c++) { + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] ^= (amber ^ black); + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] ^= (amber ^ black); + } + else if ((self->port_23c6 >> 5) == 4) + for (c = 0; c < 8; c++) { + uint32_t b = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 1) & 0x7f; + uint32_t g = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 9) & 0x7f; + uint32_t r = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 17) & 0x7f; + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = b | (g << 8) || (r << 16); + } + } + ma++; + } + } else { + if (self->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { + /* 640x400 mode */ + if (self->port_23c6 & 0x01) /* 640*400 */ { + addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + } else { + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + } + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; + + for (uint8_t c = 0; c < 8; c++) { + ink = (dat & 0x80) ? fg : bg; + if (!(self->cga.cgamode & 0x08)) + ink = black; + buffer32->line[self->cga.displine][(x << 3) + c] = ink; + dat <<= 1; + } + } + } else { + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; + + for (uint8_t c = 0; c < 4; c++) { + pattern = (dat & 0xC0) >> 6; + if (!(self->cga.cgamode & 0x08)) + pattern = 0; + + switch (pattern & 3) { + case 0: + ink0 = ink1 = black; + break; + case 1: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = black; + } else { + ink0 = amber; + ink1 = black; + } + break; + case 2: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = amber; + } else { + ink0 = amber; + ink1 = black; + } + break; + case 3: + ink0 = ink1 = amber; + break; + + default: + break; + } + buffer32->line[self->cga.displine][(x << 3) + (c << 1)] = ink0; + buffer32->line[self->cga.displine][(x << 3) + (c << 1) + 1] = ink1; + dat <<= 2; + } + } + } + } + } + self->cga.displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (self->cga.displine == 400) { /* Start of VSYNC */ + self->cga.cgastat |= 8; + self->cga.cgadispon = 0; + } + if (self->cga.displine == 416) { /* End of VSYNC */ + self->cga.displine = 0; + self->cga.cgastat &= ~8; + self->cga.cgadispon = 1; + } + } else { + timer_advance_u64(&self->cga.timer, self->cga.dispontime); + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; + + self->cga.linepos = 0; + + if (self->cga.displine == 400) { + xsize = 640; + ysize = 400; + + if ((self->cga.cgamode & 0x08) || video_force_resize_get()) { + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + /* Plasma specific */ + video_blit_memtoscreen(0, 0, xsize, ysize); + frames++; + + /* Fixed 640x400 resolution */ + video_res_x = 640; + video_res_y = 400; + + if (self->cga.cgamode & 0x02) { + if (self->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) + video_bpp = 1; + else + video_bpp = 2; + } else + video_bpp = 0; + + self->cga.cgablink++; + } + } + } +} + +static void +compaq_plasma_mdaattr_rebuild(void) +{ + for (uint16_t c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) + mdaattr[c][0][1] = 15 + 16; + else + mdaattr[c][0][1] = 7 + 16; + } + + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; +} + +static void +compaq_plasma_recalcattrs(compaq_plasma_t *self) +{ + int n; + + /* val behaves as follows: + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are inverse video + * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are bold */ + + /* Set up colours */ + amber = makecol(0xff, 0x7d, 0x00); + black = makecol(0x64, 0x19, 0x00); + + /* Initialize the attribute mapping. Start by defaulting everything + * to black on amber, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) { + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + } + + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always black on + * amber. */ + for (n = 0x11; n <= 0xFF; n++) { + if ((n & 7) == 0) + continue; + if ((self->port_23c6 >> 5) == 1) { /* Inverse */ + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + } else { /* Normal */ + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + } + } + /* Set up the 01-0E range, controlled by bits 0 and 1 of the + * passed value. When blinking is enabled this also affects 81-8E. */ + for (n = 0x01; n <= 0x0E; n++) { + if (n == 7) + continue; + if ((self->port_23c6 >> 5) == 1) { + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + blinkcols[n + 128][0] = amber; + blinkcols[n + 128][1] = black; + } else { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n + 128][0] = black; + blinkcols[n + 128][1] = amber; + } + } + /* Colours 07 and 0F are always amber on black. If blinking is + * enabled so are 87 and 8F. */ + for (n = 0x07; n <= 0x0F; n += 8) { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n + 128][0] = black; + blinkcols[n + 128][1] = amber; + } + /* When not blinking, colours 81-8F are always amber on black. */ + for (n = 0x81; n <= 0x8F; n++) { + normcols[n][0] = black; + normcols[n][1] = amber; + } + + /* Finally do the ones which are solid black. These differ between + * the normal and blinking mappings */ + for (n = 0; n <= 0xFF; n += 0x11) + normcols[n][0] = normcols[n][1] = black; + + /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */ + for (n = 0; n <= 0x77; n += 0x11) { + blinkcols[n][0] = blinkcols[n][1] = black; + blinkcols[n + 128][0] = blinkcols[n + 128][1] = black; + } +} + +static void * +compaq_plasma_init(UNUSED(const device_t *info)) +{ + compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); + + cga_init(&self->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); + + self->cga.composite = 0; + self->cga.revision = 0; + + self->cga.vram = malloc(0x8000); + self->internal_monitor = 1; + self->font_ram = malloc(0x2000); + + cga_comp_init(self->cga.revision); + timer_set_callback(&self->cga.timer, compaq_plasma_poll); + timer_set_p(&self->cga.timer, self); + + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, + compaq_plasma_read, NULL, NULL, + compaq_plasma_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, self); + for (int i = 1; i <= 2; i++) { + io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + } + io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + + overscan_x = overscan_y = 16; + + self->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (self->cga.rgb_type << 1); + cgapal_rebuild(); + compaq_plasma_mdaattr_rebuild(); + + return self; +} + +static void +compaq_plasma_close(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + free(self->cga.vram); + free(self->font_ram); + free(self); +} + +static void +compaq_plasma_speed_changed(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + compaq_plasma_recalctimings(self); +} + +const device_config_t compaq_plasma_config[] = { + // clang-format off + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t compaq_plasma_device = { + .name = "Compaq Plasma", + .internal_name = "compaq_plasma", + .flags = 0, + .local = 0, + .init = compaq_plasma_init, + .close = compaq_plasma_close, + .reset = NULL, + .available = NULL, + .speed_changed = compaq_plasma_speed_changed, + .force_redraw = NULL, + .config = compaq_plasma_config +}; diff --git a/src/video/vid_nga.c b/src/video/vid_cga_ncr.c similarity index 83% rename from src/video/vid_nga.c rename to src/video/vid_cga_ncr.c index 5fc81109c..2eb94220a 100644 --- a/src/video/vid_nga.c +++ b/src/video/vid_cga_ncr.c @@ -56,12 +56,12 @@ nga_recalctimings(nga_t *nga) double _dispofftime; double disptime; - if (nga->cga.cgamode & 1) { - disptime = nga->cga.crtc[0] + 1; - _dispontime = nga->cga.crtc[1]; + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + disptime = nga->cga.crtc[CGA_CRTC_HTOTAL] + 1; + _dispontime = nga->cga.crtc[CGA_CRTC_HDISP]; } else { - disptime = (nga->cga.crtc[0] + 1) << 1; - _dispontime = nga->cga.crtc[1] << 1; + disptime = (nga->cga.crtc[CGA_CRTC_HTOTAL] + 1) << 1; + _dispontime = nga->cga.crtc[CGA_CRTC_HDISP] << 1; } _dispofftime = disptime - _dispontime; @@ -148,7 +148,7 @@ nga_poll(void *priv) { nga_t *nga = (nga_t *) priv; /* set cursor position in memory */ - uint16_t ca = (nga->cga.crtc[15] | (nga->cga.crtc[14] << 8)) & 0x3fff; + uint16_t ca = (nga->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; int c; @@ -164,7 +164,7 @@ nga_poll(void *priv) int oldsc; /* graphic mode and not high-res modes */ - if ((nga->cga.cgamode & 2) && !(nga->cga.cgamode & 0x40)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS) && !(nga->cga.cgamode & 0x40)) { /* standard cga mode */ cga_poll(&nga->cga); return; @@ -176,7 +176,7 @@ nga_poll(void *priv) nga->cga.linepos = 1; oldsc = nga->cga.sc; /* if interlaced */ - if ((nga->cga.crtc[8] & 3) == 3) + if ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) nga->cga.sc = ((nga->cga.sc << 1) + nga->cga.oddeven) & 7; if (nga->cga.cgadispon) { if (nga->cga.displine < nga->cga.firstline) { @@ -185,11 +185,11 @@ nga_poll(void *priv) } nga->cga.lastline = nga->cga.displine; /* 80-col */ - if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 2)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && !(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video output enabled */ - if (nga->cga.cgamode & 8) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* character */ chr = nga->cga.charbuffer[x << 1]; /* text attributes */ @@ -197,11 +197,11 @@ nga_poll(void *priv) } else chr = attr = 0; /* check if cursor has to be drawn */ - drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + drawcursor = ((nga->cga.ma == ca) && nga->cga.cursorvisible && nga->cga.cursoron); /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (nga->cga.cgamode & 0x20) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; /* attribute 7 active and not cursor */ if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { @@ -224,20 +224,20 @@ nga_poll(void *priv) } } /* 40-col */ - else if (!(nga->cga.cgamode & 2)) { + else if (!(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { - if (nga->cga.cgamode & 8) { + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { chr = nga->cga.vram[((nga->cga.ma << 1) & 0x3fff) + nga->base]; attr = nga->cga.vram[(((nga->cga.ma << 1) + 1) & 0x3fff) + nga->base]; } else { chr = attr = 0; } - drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + drawcursor = ((nga->cga.ma == ca) && nga->cga.cursorvisible && nga->cga.cursoron); /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (nga->cga.cgamode & 0x20) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { /* set blinking */ @@ -262,7 +262,7 @@ nga_poll(void *priv) /* high res modes */ if (nga->cga.cgamode & 0x40) { /* 640x400x2 mode */ - if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { /* * Scanlines are read in the following order: * 0b8000-0b9f3f even scans (0,4,...) @@ -277,7 +277,7 @@ nga_poll(void *priv) } else { cols[0] = (nga->cga.cgacol & 15) | 16; col = (nga->cga.cgacol & 16) ? 24 : 16; - if (nga->cga.cgamode & 4) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; /* Cyan */ cols[2] = col | 4; /* Red */ cols[3] = col | 7; /* White */ @@ -306,11 +306,11 @@ nga_poll(void *priv) } /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video out */ - if (nga->cga.cgamode & 8) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* 640x400x2 */ - if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { /* read two bytes at a time */ dat = (nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2] << 8) | nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2 + 1]; /* each pixel is represented by one bit, so draw 16 pixels at a time */ @@ -347,26 +347,26 @@ nga_poll(void *priv) /* nga specific */ cols[0] = ((nga->cga.cgamode & 0x12) == 0x12) ? 0 : (nga->cga.cgacol & 15) + 16; /* 80-col */ - if (nga->cga.cgamode & 1) { - hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); - hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); } else { - hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); - hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); } } - if (nga->cga.cgamode & 1) + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) /* set screen width */ - x = (nga->cga.crtc[1] << 3) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (nga->cga.crtc[1] << 4) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; video_process_8(x, nga->cga.displine); nga->cga.sc = oldsc; /* vertical sync */ - if (nga->cga.vc == nga->cga.crtc[7] && !nga->cga.sc) + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VSYNC] && !nga->cga.sc) nga->cga.cgastat |= 8; nga->cga.displine++; if (nga->cga.displine >= 720) @@ -380,7 +380,7 @@ nga_poll(void *priv) nga->lineff ^= 1; /* text mode or 640x400x2 */ - if (nga->lineff && !((nga->cga.cgamode & 1) && (nga->cga.cgamode & 0x40))) { + if (nga->lineff && !((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && (nga->cga.cgamode & 0x40))) { nga->cga.ma = nga->cga.maback; /* 640x400x4 */ } else { @@ -390,11 +390,11 @@ nga_poll(void *priv) nga->cga.cgastat &= ~8; } /* cursor stop scanline */ - if (nga->cga.sc == (nga->cga.crtc[11] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[11] & 31) >> 1))) { - nga->cga.con = 0; + if (nga->cga.sc == (nga->cga.crtc[CGA_CRTC_CURSOR_END] & 31) || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + nga->cga.cursorvisible = 0; } /* interlaced and max scanline per char reached */ - if ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1)) + if ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) nga->cga.maback = nga->cga.ma; if (nga->cga.vadj) { @@ -405,12 +405,12 @@ nga_poll(void *priv) if (!nga->cga.vadj) { nga->cga.cgadispon = 1; /* change start of displayed page (crtc 12-13) */ - nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; + nga->cga.ma = nga->cga.maback = (nga->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; nga->cga.sc = 0; } /* nga specific */ /* end of character line reached */ - } else if (nga->cga.sc == nga->cga.crtc[9] || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1))) { + } else if (nga->cga.sc == nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { nga->cga.maback = nga->cga.ma; nga->cga.sc = 0; oldvc = nga->cga.vc; @@ -418,21 +418,21 @@ nga_poll(void *priv) nga->cga.vc &= 127; /* lines of character displayed */ - if (nga->cga.vc == nga->cga.crtc[6]) + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VDISP]) nga->cga.cgadispon = 0; /* total vertical lines */ - if (oldvc == nga->cga.crtc[4]) { + if (oldvc == nga->cga.crtc[CGA_CRTC_VTOTAL]) { nga->cga.vc = 0; /* adjust vertical lines */ - nga->cga.vadj = nga->cga.crtc[5]; + nga->cga.vadj = nga->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!nga->cga.vadj) { nga->cga.cgadispon = 1; /* change start of displayed page (crtc 12-13) */ - nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; + nga->cga.ma = nga->cga.maback = (nga->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; } /* cursor start */ - switch (nga->cga.crtc[10] & 0x60) { + switch (nga->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: nga->cga.cursoron = 0; break; @@ -445,18 +445,18 @@ nga_poll(void *priv) } } /* vertical line position */ - if (nga->cga.vc == nga->cga.crtc[7]) { + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VSYNC]) { nga->cga.cgadispon = 0; nga->cga.displine = 0; /* nga specific */ nga->cga.vsynctime = 16; /* vsync pos */ - if (nga->cga.crtc[7]) { - if (nga->cga.cgamode & 1) + if (nga->cga.crtc[CGA_CRTC_VSYNC]) { + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) /* set screen width */ - x = (nga->cga.crtc[1] << 3) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (nga->cga.crtc[1] << 4) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; nga->cga.lastline++; xs_temp = x; @@ -471,7 +471,7 @@ nga_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((nga->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((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)); @@ -493,14 +493,14 @@ nga_poll(void *priv) video_res_x = xsize; video_res_y = ysize; /* 80-col */ - if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 0x40)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && !(nga->cga.cgamode & 0x40)) { video_res_x /= 8; - video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_res_y /= (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; /* 40-col */ - } else if (!(nga->cga.cgamode & 2)) { + } else if (!(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_res_y /= (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; } else if (nga->cga.cgamode & 0x40) { video_res_x /= 8; @@ -523,13 +523,13 @@ nga_poll(void *priv) nga->cga.cgastat &= ~1; /* enable cursor if its scanline was reached */ - if (nga->cga.sc == (nga->cga.crtc[10] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[10] & 31) >> 1))) - nga->cga.con = 1; + if (nga->cga.sc == (nga->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + nga->cga.cursorvisible = 1; } /* 80-columns */ - if (nga->cga.cgadispon && (nga->cga.cgamode & 1)) { + if (nga->cga.cgadispon && (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { /* for each character per line */ - for (x = 0; x < (nga->cga.crtc[1] << 1); x++) + for (x = 0; x < (nga->cga.crtc[CGA_CRTC_HDISP] << 1); x++) nga->cga.charbuffer[x] = nga->cga.vram[(((nga->cga.ma << 1) + x) & 0x3fff) + nga->base]; } } diff --git a/src/video/vid_ogc.c b/src/video/vid_cga_olivetti.c similarity index 84% rename from src/video/vid_ogc.c rename to src/video/vid_cga_olivetti.c index 162cb9073..71073d464 100644 --- a/src/video/vid_ogc.c +++ b/src/video/vid_cga_olivetti.c @@ -65,12 +65,12 @@ ogc_recalctimings(ogc_t *ogc) double _dispofftime; double disptime; - if (ogc->cga.cgamode & 1) { - disptime = ogc->cga.crtc[0] + 1; - _dispontime = ogc->cga.crtc[1]; + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + disptime = ogc->cga.crtc[CGA_CRTC_HTOTAL] + 1; + _dispontime = ogc->cga.crtc[CGA_CRTC_HDISP]; } else { - disptime = (ogc->cga.crtc[0] + 1) << 1; - _dispontime = ogc->cga.crtc[1] << 1; + disptime = (ogc->cga.crtc[CGA_CRTC_HTOTAL] + 1) << 1; + _dispontime = ogc->cga.crtc[CGA_CRTC_HDISP] << 1; } _dispofftime = disptime - _dispontime; @@ -201,7 +201,7 @@ void ogc_poll(void *priv) { ogc_t *ogc = (ogc_t *) priv; - uint16_t ca = (ogc->cga.crtc[15] | (ogc->cga.crtc[14] << 8)) & 0x3fff; + uint16_t ca = (ogc->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; int c; @@ -217,10 +217,10 @@ ogc_poll(void *priv) int blink = 0; int underline = 0; - // composito colore appare blu scuro + // Composite color appears dark blue /* graphic mode and not mode 40h */ - if (!(ogc->ctrl_3de & 0x1 || !(ogc->cga.cgamode & 2))) { + if (!(ogc->ctrl_3de & 0x1 || !(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS))) { /* standard cga mode */ cga_poll(&ogc->cga); return; @@ -231,7 +231,7 @@ ogc_poll(void *priv) ogc->cga.cgastat |= 1; ogc->cga.linepos = 1; oldsc = ogc->cga.sc; - if ((ogc->cga.crtc[8] & 3) == 3) + if ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) ogc->cga.sc = ((ogc->cga.sc << 1) + ogc->cga.oddeven) & 7; if (ogc->cga.cgadispon) { if (ogc->cga.displine < ogc->cga.firstline) { @@ -240,11 +240,11 @@ ogc_poll(void *priv) } ogc->cga.lastline = ogc->cga.displine; /* 80-col */ - if (ogc->cga.cgamode & 1) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { /* for each text column */ - for (x = 0; x < ogc->cga.crtc[1]; x++) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video output enabled */ - if (ogc->cga.cgamode & 8) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* character */ chr = ogc->cga.charbuffer[x << 1]; /* text attributes */ @@ -252,7 +252,7 @@ ogc_poll(void *priv) } else chr = attr = 0; /* check if cursor has to be drawn */ - drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + drawcursor = ((ogc->cga.ma == ca) && ogc->cga.cursorvisible && ogc->cga.cursoron); /* check if character underline mode should be set */ underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); if (underline) { @@ -263,7 +263,7 @@ ogc_poll(void *priv) /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (ogc->cga.cgamode & 0x20) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; /* attribute 7 active and not cursor */ if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { @@ -293,15 +293,15 @@ ogc_poll(void *priv) } } /* 40-col */ - else if (!(ogc->cga.cgamode & 2)) { - for (x = 0; x < ogc->cga.crtc[1]; x++) { - if (ogc->cga.cgamode & 8) { + else if (!(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { chr = ogc->cga.vram[((ogc->cga.ma << 1) & 0x3fff) + ogc->base]; attr = ogc->cga.vram[(((ogc->cga.ma << 1) + 1) & 0x3fff) + ogc->base]; } else { chr = attr = 0; } - drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + drawcursor = ((ogc->cga.ma == ca) && ogc->cga.cursorvisible && ogc->cga.cursoron); /* check if character underline mode should be set */ underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); if (underline) { @@ -312,7 +312,7 @@ ogc_poll(void *priv) /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (ogc->cga.cgamode & 0x20) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { /* set blinking */ @@ -352,9 +352,9 @@ ogc_poll(void *priv) cols[1] = (ogc->cga.cgacol & 15) + 16; } - for (x = 0; x < ogc->cga.crtc[1]; x++) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video out */ - if (ogc->cga.cgamode & 8) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { dat = (ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2] << 8) | ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2 + 1]; } else { dat = 0; @@ -370,22 +370,22 @@ ogc_poll(void *priv) } else { /* ogc specific */ cols[0] = ((ogc->cga.cgamode & 0x12) == 0x12) ? 0 : (ogc->cga.cgacol & 15) + 16; - if (ogc->cga.cgamode & 1) - hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[1] << 3) + 16) << 2, cols[0]); + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); else - hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); } /* 80 columns */ - if (ogc->cga.cgamode & 1) - x = (ogc->cga.crtc[1] << 3) + 16; + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (ogc->cga.crtc[1] << 4) + 16; + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; video_process_8(x, ogc->cga.displine); ogc->cga.sc = oldsc; - if (ogc->cga.vc == ogc->cga.crtc[7] && !ogc->cga.sc) + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VSYNC] && !ogc->cga.sc) ogc->cga.cgastat |= 8; ogc->cga.displine++; if (ogc->cga.displine >= 720) @@ -405,10 +405,10 @@ ogc_poll(void *priv) if (!ogc->cga.vsynctime) ogc->cga.cgastat &= ~8; } - if (ogc->cga.sc == (ogc->cga.crtc[11] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[11] & 31) >> 1))) { - ogc->cga.con = 0; + if (ogc->cga.sc == (ogc->cga.crtc[CGA_CRTC_CURSOR_END] & 31) || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + ogc->cga.cursorvisible = 0; } - if ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1)) + if ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) ogc->cga.maback = ogc->cga.ma; if (ogc->cga.vadj) { ogc->cga.sc++; @@ -417,28 +417,28 @@ ogc_poll(void *priv) ogc->cga.vadj--; if (!ogc->cga.vadj) { ogc->cga.cgadispon = 1; - ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; + ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; ogc->cga.sc = 0; } - // potrebbe dare problemi con composito - } else if (ogc->cga.sc == ogc->cga.crtc[9] || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1))) { + // may cause problems with composite + } else if (ogc->cga.sc == ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { ogc->cga.maback = ogc->cga.ma; ogc->cga.sc = 0; oldvc = ogc->cga.vc; ogc->cga.vc++; ogc->cga.vc &= 127; - if (ogc->cga.vc == ogc->cga.crtc[6]) + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VDISP]) ogc->cga.cgadispon = 0; - if (oldvc == ogc->cga.crtc[4]) { + if (oldvc == ogc->cga.crtc[CGA_CRTC_VTOTAL]) { ogc->cga.vc = 0; - ogc->cga.vadj = ogc->cga.crtc[5]; + ogc->cga.vadj = ogc->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!ogc->cga.vadj) { ogc->cga.cgadispon = 1; - ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; + ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; } - switch (ogc->cga.crtc[10] & 0x60) { + switch (ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: ogc->cga.cursoron = 0; break; @@ -450,16 +450,16 @@ ogc_poll(void *priv) break; } } - if (ogc->cga.vc == ogc->cga.crtc[7]) { + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VSYNC]) { ogc->cga.cgadispon = 0; ogc->cga.displine = 0; /* ogc specific */ - ogc->cga.vsynctime = (ogc->cga.crtc[3] >> 4) + 1; - if (ogc->cga.crtc[7]) { - if (ogc->cga.cgamode & 1) - x = (ogc->cga.crtc[1] << 3) + 16; + ogc->cga.vsynctime = (ogc->cga.crtc[CGA_CRTC_HSYNC_WIDTH] >> 4) + 1; + if (ogc->cga.crtc[CGA_CRTC_VSYNC]) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (ogc->cga.crtc[1] << 4) + 16; + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; ogc->cga.lastline++; xs_temp = x; @@ -474,7 +474,7 @@ ogc_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((ogc->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((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)); @@ -496,14 +496,14 @@ ogc_poll(void *priv) video_res_x = xsize; video_res_y = ysize; /* 80-col */ - if (ogc->cga.cgamode & 1) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_res_y /= (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; /* 40-col */ - } else if (!(ogc->cga.cgamode & 2)) { + } else if (!(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_res_y /= (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; } else if (!(ogc->ctrl_3de & 1)) { video_res_y /= 2; @@ -524,12 +524,12 @@ ogc_poll(void *priv) if (ogc->cga.cgadispon) ogc->cga.cgastat &= ~1; - if (ogc->cga.sc == (ogc->cga.crtc[10] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[10] & 31) >> 1))) - ogc->cga.con = 1; + if (ogc->cga.sc == (ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + ogc->cga.cursorvisible = 1; } /* 80-columns */ - if (ogc->cga.cgadispon && (ogc->cga.cgamode & 1)) { - for (x = 0; x < (ogc->cga.crtc[1] << 1); x++) + if (ogc->cga.cgadispon && (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (ogc->cga.crtc[CGA_CRTC_HDISP] << 1); x++) ogc->cga.charbuffer[x] = ogc->cga.vram[(((ogc->cga.ma << 1) + x) & 0x3fff) + ogc->base]; } } diff --git a/src/machine/m_xt_t1000_vid.c b/src/video/vid_cga_toshiba_t1000.c similarity index 92% rename from src/machine/m_xt_t1000_vid.c rename to src/video/vid_cga_toshiba_t1000.c index efad869e1..8811309a0 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/video/vid_cga_toshiba_t1000.c @@ -246,24 +246,24 @@ t1000_text_row80(t1000_t *t1000) int blink; uint16_t addr; uint8_t sc; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; - uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + uint16_t ma = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t ca = (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; sc = (t1000->displine) & 7; addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2; ma += (t1000->displine >> 3) * 80; - if ((t1000->cga.crtc[10] & 0x60) == 0x20) { + if ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && ((t1000->cga.crtc[11] & 0x0F) >= sc); + cursorline = ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= sc) && ((t1000->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= sc); } for (uint8_t x = 0; x < 80; x++) { chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t1000->cga.cgablink & 16)); - blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t1000->video_options & 1) bold = boldcols[attr] ? chr : chr + 256; @@ -272,7 +272,7 @@ t1000_text_row80(t1000_t *t1000) if (t1000->video_options & 2) bold += 512; - if (t1000->cga.cgamode & 0x20) /* Blink */ + if (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -307,24 +307,24 @@ t1000_text_row40(t1000_t *t1000) int blink; uint16_t addr; uint8_t sc; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; - uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + uint16_t ma = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t ca = (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; sc = (t1000->displine) & 7; addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2; ma += (t1000->displine >> 3) * 40; - if ((t1000->cga.crtc[10] & 0x60) == 0x20) { + if ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && ((t1000->cga.crtc[11] & 0x0F) >= sc); + cursorline = ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= sc) && ((t1000->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= sc); } for (uint8_t x = 0; x < 40; x++) { chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t1000->cga.cgablink & 16)); - blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t1000->video_options & 1) bold = boldcols[attr] ? chr : chr + 256; @@ -333,7 +333,7 @@ t1000_text_row40(t1000_t *t1000) if (t1000->video_options & 2) bold += 512; - if (t1000->cga.cgamode & 0x20) /* Blink */ + if (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -366,7 +366,7 @@ t1000_cgaline6(t1000_t *t1000) uint32_t fg = (t1000->cga.cgacol & 0x0F) ? blue : grey; uint32_t bg = grey; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + uint16_t ma = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((ma & ~1) << 1); @@ -376,7 +376,7 @@ t1000_cgaline6(t1000_t *t1000) for (uint8_t c = 0; c < 8; c++) { ink = (dat & 0x80) ? fg : bg; - if (!(t1000->cga.cgamode & 8)) + if (!(t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) ink = grey; (buffer32->line[t1000->displine])[x * 8 + c] = ink; dat = dat << 1; @@ -395,7 +395,7 @@ t1000_cgaline4(t1000_t *t1000) uint32_t ink1; uint16_t addr; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + uint16_t ma = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((ma & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { @@ -404,7 +404,7 @@ t1000_cgaline4(t1000_t *t1000) for (uint8_t c = 0; c < 4; c++) { pattern = (dat & 0xC0) >> 6; - if (!(t1000->cga.cgamode & 8)) + if (!(t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) pattern = 0; switch (pattern & 3) { @@ -479,7 +479,7 @@ t1000_poll(void *priv) /* Graphics */ if (t1000->cga.cgamode & 0x02) { - if (t1000->cga.cgamode & 0x10) + if (t1000->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) t1000_cgaline6(t1000); else t1000_cgaline4(t1000); @@ -532,7 +532,7 @@ t1000_poll(void *priv) video_res_y = T1000_YSIZE; if (t1000->cga.cgamode & 0x02) { - if (t1000->cga.cgamode & 0x10) + if (t1000->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) video_bpp = 1; else video_bpp = 2; diff --git a/src/machine/m_at_t3100e_vid.c b/src/video/vid_cga_toshiba_t3100e.c similarity index 91% rename from src/machine/m_at_t3100e_vid.c rename to src/video/vid_cga_toshiba_t3100e.c index c827a05e5..0346fccd4 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/video/vid_cga_toshiba_t3100e.c @@ -255,24 +255,24 @@ t3100e_text_row80(t3100e_t *t3100e) int blink; uint16_t addr; uint8_t sc; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + uint16_t ma = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t ca = (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; sc = (t3100e->displine) & 15; addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2; ma += (t3100e->displine >> 4) * 80; - if ((t3100e->cga.crtc[10] & 0x60) == 0x20) { + if ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t3100e->cga.crtc[10] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[11] & 0x0F) * 2 >= sc); + cursorline = ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) * 2 >= sc); } for (uint8_t x = 0; x < 80; x++) { chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t3100e->cga.cgablink & 16)); - blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t3100e->video_options & 4) bold = boldcols[attr] ? chr + 256 : chr; @@ -280,7 +280,7 @@ t3100e_text_row80(t3100e_t *t3100e) bold = boldcols[attr] ? chr : chr + 256; bold += 512 * (t3100e->video_options & 3); - if (t3100e->cga.cgamode & 0x20) /* Blink */ + if (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -316,24 +316,24 @@ t3100e_text_row40(t3100e_t *t3100e) int blink; uint16_t addr; uint8_t sc; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + uint16_t ma = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t ca = (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; sc = (t3100e->displine) & 15; addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2; ma += (t3100e->displine >> 4) * 40; - if ((t3100e->cga.crtc[10] & 0x60) == 0x20) { + if ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t3100e->cga.crtc[10] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[11] & 0x0F) * 2 >= sc); + cursorline = ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) * 2 >= sc); } for (uint8_t x = 0; x < 40; x++) { chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t3100e->cga.cgablink & 16)); - blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t3100e->video_options & 4) bold = boldcols[attr] ? chr + 256 : chr; @@ -341,7 +341,7 @@ t3100e_text_row40(t3100e_t *t3100e) bold = boldcols[attr] ? chr : chr + 256; bold += 512 * (t3100e->video_options & 3); - if (t3100e->cga.cgamode & 0x20) /* Blink */ + if (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -374,9 +374,9 @@ t3100e_cgaline6(t3100e_t *t3100e) uint32_t fg = (t3100e->cga.cgacol & 0x0F) ? amber : black; uint32_t bg = black; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + uint16_t ma = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; - if (t3100e->cga.crtc[9] == 3) /* 640*400 */ + if (t3100e->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] == 3) /* 640*400 */ { addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); } else { @@ -388,7 +388,7 @@ t3100e_cgaline6(t3100e_t *t3100e) for (uint8_t c = 0; c < 8; c++) { ink = (dat & 0x80) ? fg : bg; - if (!(t3100e->cga.cgamode & 8)) + if (!(t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) ink = black; (buffer32->line[t3100e->displine])[x * 8 + c] = ink; dat = dat << 1; @@ -407,8 +407,8 @@ t3100e_cgaline4(t3100e_t *t3100e) uint32_t ink1 = 0; uint16_t addr; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - if (t3100e->cga.crtc[9] == 3) /* 320*400 undocumented */ + uint16_t ma = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] | (t3100e->cga.crtc[CGA_CRTC_CURSOR_END] << 8)) & 0x7fff; + if (t3100e->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] == 3) /* 320*400 undocumented */ { addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); } else /* 320*200 */ @@ -421,7 +421,7 @@ t3100e_cgaline4(t3100e_t *t3100e) for (uint8_t c = 0; c < 4; c++) { pattern = (dat & 0xC0) >> 6; - if (!(t3100e->cga.cgamode & 8)) + if (!(t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) pattern = 0; switch (pattern & 3) { @@ -498,7 +498,7 @@ t3100e_poll(void *priv) /* Graphics */ if (t3100e->cga.cgamode & 0x02) { - if (t3100e->cga.cgamode & 0x10) + if (t3100e->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) t3100e_cgaline6(t3100e); else t3100e_cgaline4(t3100e); @@ -551,7 +551,7 @@ t3100e_poll(void *priv) video_res_y = T3100E_YSIZE; if (t3100e->cga.cgamode & 0x02) { - if (t3100e->cga.cgamode & 0x10) + if (t3100e->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) video_bpp = 1; else video_bpp = 2; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index c21b7c714..6000a2f30 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -901,7 +901,7 @@ ega_poll(void *priv) ega->linepos = 0; if ((ega->sc == (ega->crtc[11] & 31)) || (ega->sc == ega->rowcount)) - ega->con = 0; + ega->cursorvisible = 0; if (ega->dispon) { /* TODO: Verify real hardware behaviour for out-of-range fine vertical scroll */ if (ega->linedbl && !ega->linecountff) { @@ -1037,7 +1037,7 @@ ega_poll(void *priv) ega->linecountff = 0; } if (ega->sc == (ega->crtc[10] & 31)) - ega->con = 1; + ega->cursorvisible = 1; } } diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 8a73ffbbb..b383e96b0 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -143,7 +143,7 @@ ega_render_text(ega_t *ega) for (int x = 0; x < (ega->hdisp + ega->scrollcache); x += charwidth) { uint32_t addr = ega->remap_func(ega, ega->ma) & ega->vrammask; - int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + int drawcursor = ((ega->ma == ega->ca) && ega->cursorvisible && ega->cursoron); uint32_t chr; uint32_t attr; diff --git a/src/video/vid_f82c425.c b/src/video/vid_f82c425.c index c607cda14..a8fd2227b 100644 --- a/src/video/vid_f82c425.c +++ b/src/video/vid_f82c425.c @@ -362,27 +362,27 @@ f82c425_text_row(f82c425_t *f82c425) int blink; uint16_t addr; uint8_t sc; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + uint16_t ma = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; uint16_t ca = (f82c425->cga.crtc[0x0f] | (f82c425->cga.crtc[0x0e] << 8)) & 0x3fff; - uint8_t sl = f82c425->cga.crtc[9] + 1; - int columns = f82c425->cga.crtc[1]; + uint8_t sl = f82c425->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; + int columns = f82c425->cga.crtc[CGA_CRTC_HDISP]; sc = (f82c425->displine) & 7; addr = ((ma & ~1) + (f82c425->displine >> 3) * columns) * 2; ma += (f82c425->displine >> 3) * columns; - if ((f82c425->cga.crtc[0x0a] & 0x60) == 0x20) { + if ((f82c425->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((f82c425->cga.crtc[0x0a] & 0x0F) <= sc) && ((f82c425->cga.crtc[0x0b] & 0x0F) >= sc); + cursorline = ((f82c425->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= sc) && ((f82c425->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= sc); } for (int x = 0; x < columns; x++) { chr = f82c425->vram[(addr + 2 * x) & 0x3FFF]; attr = f82c425->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (f82c425->cga.cgamode & 0x8) && (f82c425->cga.cgablink & 0x10)); + drawcursor = ((ma == ca) && cursorline && (f82c425->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (f82c425->cga.cgablink & 0x10)); - blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (drawcursor) { colors[0] = smartmap[~attr & 0xff][0]; @@ -418,7 +418,7 @@ f82c425_cgaline6(f82c425_t *f82c425) uint8_t dat; uint16_t addr; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + uint16_t ma = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((ma & ~1) << 1); @@ -442,7 +442,7 @@ f82c425_cgaline4(f82c425_t *f82c425) uint8_t pattern; uint16_t addr; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + uint16_t ma = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((ma & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { @@ -526,7 +526,7 @@ f82c425_poll(void *priv) f82c425->displine = 0; f82c425->cga.cgastat &= ~8; f82c425->dispon = 1; - } else if (f82c425->displine == (f82c425->cga.crtc[9] + 1) * f82c425->cga.crtc[6]) { + } else if (f82c425->displine == (f82c425->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * f82c425->cga.crtc[CGA_CRTC_VDISP]) { /* Start of VSYNC */ f82c425->cga.cgastat |= 8; f82c425->dispon = 0; diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index cf8ad8cf3..48037b3f4 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -341,7 +341,7 @@ hercules_poll(void *priv) attr = dev->charbuffer[(x << 1) + 1]; } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->ma == ca) && dev->cursorvisible && dev->cursoron); blink = ((dev->blink & 16) && (dev->ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (dev->sc == 12 && ((attr & 7) == 1)) { @@ -398,7 +398,7 @@ hercules_poll(void *priv) } if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + dev->cursorvisible = 0; } if (dev->vadj) { @@ -517,7 +517,7 @@ hercules_poll(void *priv) } if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + dev->cursorvisible = 1; if (dev->dispon && !(dev->ctrl & 0x02)) { for (x = 0; x < (dev->crtc[1] << 1); x++) { pa = (dev->ctrl & 0x80) ? ((x & 1) ? 0x0000 : 0x8000) : 0x0000; diff --git a/src/video/vid_incolor.c b/src/video/vid_hercules_incolor.c similarity index 99% rename from src/video/vid_incolor.c rename to src/video/vid_hercules_incolor.c index 034d54045..1d5e9d2aa 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_hercules_incolor.c @@ -167,7 +167,7 @@ typedef struct { int linepos, displine; int vc, sc; uint16_t ma, maback; - int con, cursoron; + int cursorvisible, cursoron; int dispon, blink; int vsynctime; int vadj; @@ -760,7 +760,7 @@ text_line(incolor_t *dev, uint16_t ca) } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->ma == ca) && dev->cursorvisible && dev->cursoron); switch (dev->crtc[INCOLOR_CRTC_XMODE] & 5) { case 0: @@ -898,7 +898,7 @@ incolor_poll(void *priv) } if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + dev->cursorvisible = 0; } if (dev->vadj) { @@ -977,7 +977,7 @@ incolor_poll(void *priv) } if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + dev->cursorvisible = 1; } } diff --git a/src/video/vid_herculesplus.c b/src/video/vid_hercules_plus.c similarity index 99% rename from src/video/vid_herculesplus.c rename to src/video/vid_hercules_plus.c index 42c68bf54..4c3f7867c 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_hercules_plus.c @@ -77,7 +77,7 @@ typedef struct { int linepos, displine; int vc, sc; uint16_t ma, maback; - int con, cursoron; + int cursorvisible, cursoron; int dispon, blink; int vsynctime; int vadj; @@ -418,7 +418,7 @@ text_line(herculesplus_t *dev, uint16_t ca) } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->ma == ca) && dev->cursorvisible && dev->cursoron); switch (dev->crtc[HERCULESPLUS_CRTC_XMODE] & 5) { case 0: @@ -535,7 +535,7 @@ herculesplus_poll(void *priv) } if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + dev->cursorvisible = 0; } if (dev->vadj) { dev->sc++; @@ -612,7 +612,7 @@ herculesplus_poll(void *priv) } if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + dev->cursorvisible = 1; } VIDEO_MONITOR_EPILOGUE(); diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4240f5e98..053ef0030 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -113,7 +113,7 @@ typedef struct jega_t { uint8_t attr_palette_enable; uint32_t *pallook; int is_vga; - int con; + int cursorvisible; int cursoron; int cursorblink_disable; int ca; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 70ca375fd..12f8a93ac 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -158,7 +158,7 @@ mda_poll(void *priv) for (x = 0; x < mda->crtc[1]; x++) { chr = mda->vram[(mda->ma << 1) & 0xfff]; attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; - drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + drawcursor = ((mda->ma == ca) && mda->cursorvisible && mda->cursoron); blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (mda->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) @@ -199,7 +199,7 @@ mda_poll(void *priv) } } if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { - mda->con = 0; + mda->cursorvisible = 0; } if (mda->vadj) { mda->sc++; @@ -266,7 +266,7 @@ mda_poll(void *priv) mda->ma = mda->maback; } if (mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1))) { - mda->con = 1; + mda->cursorvisible = 1; } } VIDEO_MONITOR_EPILOGUE(); diff --git a/src/video/vid_pcjr.c b/src/video/vid_pcjr.c new file mode 100644 index 000000000..9d1e3453e --- /dev/null +++ b/src/video/vid_pcjr.c @@ -0,0 +1,703 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PCjr video subsystem emulation + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Connor Hyde / starfrost + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2025 starfrost + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/mem.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/vid_cga_comp.h> + +#include <86box/m_pcjr.h> + +static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void +recalc_address(pcjr_t *pcjr) +{ + uint8_t masked_memctrl = pcjr->memctrl; + + /* According to the Technical Reference, bits 2 and 5 are + ignored if there is only 64k of RAM and there are only + 4 pages. */ + if (mem_size < 128) + masked_memctrl &= ~0x24; + + if ((pcjr->memctrl & 0xc0) == 0xc0) { + pcjr->vram = &ram[(masked_memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(masked_memctrl & 0x30) << 11]; + } else { + pcjr->vram = &ram[(masked_memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(masked_memctrl & 0x38) << 11]; + } +} + +void +pcjr_recalc_timings(pcjr_t *pcjr) +{ + double _dispontime; + double _dispofftime; + double disptime; + + if (pcjr->array[0] & 1) { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } else { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (uint64_t) (_dispontime); + pcjr->dispofftime = (uint64_t) (_dispofftime); +} + +static int +vid_get_h_overscan_size(pcjr_t *pcjr) +{ + int ret; + + if (pcjr->array[0] & 1) + ret = 128; + else + ret = 256; + + return ret; +} + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint8_t old; + + switch (addr) { + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + pcjr->crtcreg = val & 0x1f; + return; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (pcjr->crtcreg == 2) + overscan_x = vid_get_h_overscan_size(pcjr); + if (old != val) { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { + pcjr->fullchange = changeframecount; + pcjr_recalc_timings(pcjr); + } + } + return; + + case 0x3da: + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + if (!(pcjr->array_index & 0x1f)) + update_cga16_color(val); + } + pcjr->array_ff = !pcjr->array_ff; + break; + + case 0x3df: + pcjr->memctrl = val; + pcjr->pa = val; /* The PCjr BIOS expects the value written to 3DF to + then be readable from port 60, others it errors out + with only 64k RAM set (but somehow, still works with + 128k or more RAM). */ + pcjr->addr_mode = val >> 6; + recalc_address(pcjr); + break; + + default: + break; + } +} + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + ret = pcjr->crtcreg; + break; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + ret = pcjr->crtc[pcjr->crtcreg]; + break; + + case 0x3da: + pcjr->array_ff = 0; + pcjr->stat ^= 0x10; + ret = pcjr->stat; + break; + + default: + break; + } + + return ret; +} + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + + if (pcjr->memctrl == -1) + return; + + pcjr->b8000[addr & 0x3fff] = val; +} + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + const pcjr_t *pcjr = (pcjr_t *) priv; + + if (pcjr->memctrl == -1) + return 0xff; + + return (pcjr->b8000[addr & 0x3fff]); +} + +static int +vid_get_h_overscan_delta(pcjr_t *pcjr) +{ + int def; + int coef; + int ret; + + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { + case 0x13: /*320x200x16*/ + def = 0x56; + coef = 8; + break; + case 0x12: /*160x200x16*/ + def = 0x2c; /* I'm going to assume a datasheet erratum here. */ + coef = 16; + break; + case 0x03: /*640x200x4*/ + def = 0x56; + coef = 8; + break; + case 0x01: /*80 column text*/ + def = 0x5a; + coef = 8; + break; + case 0x00: /*40 column text*/ + default: + def = 0x2c; + coef = 16; + break; + case 0x02: /*320x200x4*/ + def = 0x2b; + coef = 16; + break; + case 0x102: /*640x200x2*/ + def = 0x2b; + coef = 16; + break; + } + + ret = pcjr->crtc[0x02] - def; + + if (ret < -8) + ret = -8; + + if (ret > 8) + ret = 8; + + return ret * coef; +} + +static void +vid_blit_h_overscan(pcjr_t *pcjr) +{ + int cols = (pcjr->array[2] & 0xf) + 16;; + int y0 = pcjr->firstline << 1; + int y = (pcjr->lastline << 1) + 16; + int ho_s = vid_get_h_overscan_size(pcjr); + int i; + int x; + + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + + for (i = 0; i < 16; i++) { + hline(buffer32, 0, y0 + i, x, cols); + hline(buffer32, 0, y + i, x, cols); + + if (pcjr->composite) { + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y0 + i]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y + i]); + } else { + video_process_8(x, y0 + i); + video_process_8(x, y + i); + } + } +} + +static void +vid_poll(void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint16_t dat; + int cols[4]; + int oldsc; + int l = (pcjr->displine << 1) + 16; + int ho_s = vid_get_h_overscan_size(pcjr); + int ho_d = vid_get_h_overscan_delta(pcjr) + (ho_s / 2); + + if (!pcjr->linepos) { + timer_advance_u64(&pcjr->timer, pcjr->dispofftime); + pcjr->stat &= ~1; + pcjr->linepos = 1; + oldsc = pcjr->sc; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->sc = (pcjr->sc << 1) & 7; + if (pcjr->dispon) { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) { + pcjr->firstline = pcjr->displine; + video_wait_for_buffer(); + } + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + } + + switch (pcjr->addr_mode) { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->sc & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->sc & 3) * 0x2000; + break; + default: + break; + } + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = + buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = + pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = + buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = + pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = + buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = + pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = + buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = + pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = + buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = + buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = + buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = + pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = + buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = + buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = + buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = + pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 8] = buffer32->line[l][ef_x + 9] = + buffer32->line[l][ef_x + 10] = buffer32->line[l][ef_x + 11] = + buffer32->line[l + 1][ef_x + 8] = buffer32->line[l + 1][ef_x + 9] = + buffer32->line[l + 1][ef_x + 10] = buffer32->line[l + 1][ef_x + 11] = + pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 12] = buffer32->line[l][ef_x + 13] = + buffer32->line[l][ef_x + 14] = buffer32->line[l][ef_x + 15] = + buffer32->line[l + 1][ef_x + 12] = buffer32->line[l + 1][ef_x + 13] = + buffer32->line[l + 1][ef_x + 14] = buffer32->line[l + 1][ef_x + 15] = + pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + pcjr->ma++; + for (uint8_t c = 0; c < 8; c++) { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = + pcjr->array[(chr & pcjr->array[1] & 0x0f) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->cursorvisible && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + } + if (pcjr->sc & 8) + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + c] = + buffer32->line[l + 1][ef_x + c] = cols[0]; + else + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + c] = + buffer32->line[l + 1][ef_x + c] = + cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (drawcursor) + for (uint8_t c = 0; c < 8; c++) { + buffer32->line[l][ef_x + c] ^= 15; + buffer32->line[l + 1][ef_x + c] ^= 15; + } + pcjr->ma++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->cursorvisible && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + } + pcjr->ma++; + if (pcjr->sc & 8) + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[0]; + else + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = + cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (drawcursor) + for (uint8_t c = 0; c < 16; c++) { + buffer32->line[l][ef_x + c] ^= 15; + buffer32->line[l + 1][ef_x + c] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (uint8_t c = 0; c < 8; c++) { + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (uint8_t c = 0; c < 16; c++) { + buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = + cols[dat >> 15]; + dat <<= 1; + } + } + break; + + default: + break; + } + } else { + if (pcjr->array[3] & 4) { + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); + } + } else { + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + } + } + } + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + if (pcjr->composite) { + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l + 1]); + } else { + video_process_8(x, l); + video_process_8(x, l + 1); + } + pcjr->sc = oldsc; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { + pcjr->stat |= 8; + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } else { + timer_advance_u64(&pcjr->timer, pcjr->dispontime); + if (pcjr->dispon) + pcjr->stat |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) { + pcjr->vsynctime--; + if (!pcjr->vsynctime) { + pcjr->stat &= ~8; + } + } + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { + pcjr->cursorvisible = 0; + } + if (pcjr->vadj) { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + pcjr->vadj--; + if (!pcjr->vadj) { + pcjr->dispon = 1; + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->sc = 0; + } + } else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) { + pcjr->maback = pcjr->ma; + pcjr->sc = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) { + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) + pcjr->cursoron = 0; + else + pcjr->cursoron = pcjr->blink & 16; + } + if (pcjr->vc == pcjr->crtc[7]) { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16; + picint(1 << 5); + if (pcjr->crtc[7]) { + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + pcjr->lastline++; + + xs_temp = x; + ys_temp = (pcjr->lastline - pcjr->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + int actual_ys = ys_temp; + + if (xs_temp < 64) + xs_temp = 656; + if (ys_temp < 32) + ys_temp = 400; + if (!enable_overscan) + xs_temp -= ho_s; + + 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)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + vid_blit_h_overscan(pcjr); + + if (enable_overscan) { + video_blit_memtoscreen(0, pcjr->firstline << 1, + xsize, actual_ys + 32); + } else if (pcjr->apply_hd) { + video_blit_memtoscreen(ho_s / 2, (pcjr->firstline << 1) + 16, + xsize, actual_ys); + } else { + video_blit_memtoscreen(ho_d, (pcjr->firstline << 1) + 16, + xsize, actual_ys); + } + } + + frames++; + video_res_x = xsize; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } else { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + } + if (pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1))) + pcjr->cursorvisible = 1; + } +} + + +void +pcjr_vid_init(pcjr_t *pcjr) +{ + int display_type; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + + pcjr->memctrl = -1; + if (mem_size < 128) + pcjr->memctrl &= ~0x24; + + display_type = device_get_config_int("display_type"); + pcjr->composite = (display_type != PCJR_RGB); + pcjr->apply_hd = device_get_config_int("apply_hd"); + overscan_x = 256; + overscan_y = 32; + + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 16, + vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); + timer_add(&pcjr->timer, vid_poll, pcjr, 1); + + cga_palette = 0; + cgapal_rebuild(); +} diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 2cc993b8c..46f9b0650 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -362,7 +362,7 @@ typedef struct da2_t { int vc; int sc; int linepos, vslines, linecountff; - int con, cursoron, blink, blinkconf; + int cursorvisible, cursoron, blink, blinkconf; int scrollcache; int char_width; @@ -2055,7 +2055,7 @@ da2_render_text(da2_t *da2) p[n] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */ } /* Drawing text cursor */ - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + drawcursor = ((da2->ma == da2->ca) && da2->cursorvisible && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */ @@ -2155,7 +2155,7 @@ da2_render_textm3(da2_t *da2) } chr_wide = 0; } - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + drawcursor = ((da2->ma == da2->ca) && da2->cursorvisible && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { // int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); // int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ @@ -3056,7 +3056,7 @@ da2_poll(void *priv) da2->linepos = 0; if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) - da2->con = 0; + da2->cursorvisible = 0; if (da2->dispon) { if (da2->sc == da2->rowcount) { da2->linecountff = 0; @@ -3145,7 +3145,7 @@ da2_poll(void *priv) da2->scrollcache = da2->attrc[LV_PANNING] & 7; } if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) - da2->con = 1; + da2->cursorvisible = 1; } } diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index c54af7119..9a5d184f9 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -158,7 +158,7 @@ typedef struct sigma_t { int linepos, displine; int sc, vc; int cgadispon; - int con, cursoron, cgablink; + int cursorvisible, cursoron, cgablink; int vsynctime, vadj; int oddeven; @@ -430,7 +430,7 @@ sigma_text80(sigma_t *sigma) for (uint32_t x = 0; x < (sigma->crtc[1] << 1); x++) { chr = vram[x << 1]; attr = vram[(x << 1) + 1]; - drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + drawcursor = ((ma == ca) && sigma->cursorvisible && sigma->cursoron); if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; @@ -485,7 +485,7 @@ sigma_text40(sigma_t *sigma) for (uint32_t x = 0; x < (sigma->crtc[1] << 1); x++) { chr = vram[x << 1]; attr = vram[(x << 1) + 1]; - drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + drawcursor = ((ma == ca) && sigma->cursorvisible && sigma->cursoron); if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; @@ -675,7 +675,7 @@ sigma_poll(void *priv) sigma->sigmastat &= ~STATUS_RETR_V; } if (sigma->sc == (sigma->crtc[11] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[11] & 31) >> 1))) { - sigma->con = 0; + sigma->cursorvisible = 0; } if ((sigma->crtc[8] & 3) == 3 && sigma->sc == (sigma->crtc[9] >> 1)) sigma->maback = sigma->ma; @@ -775,7 +775,7 @@ sigma_poll(void *priv) if (sigma->cgadispon) sigma->sigmastat &= ~STATUS_RETR_H; if (sigma->sc == (sigma->crtc[10] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[10] & 31) >> 1))) - sigma->con = 1; + sigma->cursorvisible = 1; } } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 0c9c24241..6290832df 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1332,7 +1332,7 @@ svga_poll(void *priv) svga->linepos = 0; if ((svga->sc == (svga->crtc[11] & 31)) || (svga->sc == svga->rowcount)) - svga->con = 0; + svga->cursorvisible = 0; if (svga->dispon) { /* TODO: Verify real hardware behaviour for out-of-range fine vertical scroll - S3 Trio64V2/DX: sc == rowcount, wrapping 5-bit counter. */ @@ -1503,7 +1503,7 @@ svga_poll(void *priv) svga->overlay_latch = svga->overlay; } if (svga->sc == (svga->crtc[10] & 31)) - svga->con = 1; + svga->cursorvisible = 1; } } diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index d47697a7e..348506e56 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -158,7 +158,7 @@ svga_render_text_40(svga_t *svga) if (!svga->force_old_addr) addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + drawcursor = ((svga->ma == svga->ca) && svga->cursorvisible && svga->cursoron); if (svga->force_old_addr) { chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; @@ -241,7 +241,7 @@ svga_render_text_80(svga_t *svga) if (!svga->force_old_addr) addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + drawcursor = ((svga->ma == svga->ca) && svga->cursorvisible && svga->cursoron); if (svga->force_old_addr) { chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; @@ -318,7 +318,7 @@ svga_render_text_80_ksc5601(svga_t *svga) for (int x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + drawcursor = ((svga->ma == svga->ca) && svga->cursorvisible && svga->cursoron); chr = svga->vram[addr]; nextchr = svga->vram[addr + 8]; attr = svga->vram[addr + 1]; diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c new file mode 100644 index 000000000..13d46a239 --- /dev/null +++ b/src/video/vid_tandy.c @@ -0,0 +1,827 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Tandy 1000 video emulation + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Connor Hyde / starfrost, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2025 starfrost + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/nmi.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/nvr.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/gameport.h> +#include <86box/keyboard.h> +#include <86box/sound.h> +#include <86box/snd_sn76489.h> +#include <86box/video.h> +#include <86box/vid_cga_comp.h> +#include <86box/m_tandy.h> +#include <86box/machine.h> +#include <86box/plat_unused.h> + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static uint8_t crtcmask_sl[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +enum { + TANDY_RGB = 0, + TANDY_COMPOSITE +}; + +static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ + +static void +recalc_mapping(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + mem_mapping_disable(&vid->mapping); + io_removehandler(0x03d0, 16, + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + + if (vid->planar_ctrl & 4) { + mem_mapping_enable(&vid->mapping); + if (vid->array[5] & 1) + mem_mapping_set_addr(&vid->mapping, 0xa0000, 0x10000); + else + mem_mapping_set_addr(&vid->mapping, 0xb8000, 0x8000); + io_sethandler(0x03d0, 16, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + } +} + +static void +recalc_timings(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + double _dispontime; + double _dispofftime; + double disptime; + + if (vid->mode & 1) { + disptime = vid->crtc[0] + 1; + _dispontime = vid->crtc[1]; + } else { + disptime = (vid->crtc[0] + 1) << 1; + _dispontime = vid->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (uint64_t) (_dispontime); + vid->dispofftime = (uint64_t) (_dispofftime); +} + +static void +recalc_address(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + vid->b8000_mask = 0x7fff; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + vid->b8000_mask = 0x3fff; + } +} + +void +tandy_recalc_address_sl(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + vid->b8000_limit = 0x8000; + + if (vid->array[5] & 1) { + vid->vram = &ram[((vid->memctrl & 0x04) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x20) << 11) + dev->base]; + } else if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + if ((vid->memctrl & 0x38) == 0x38) + vid->b8000_limit = 0x4000; + } +} + +static void +vid_update_latch(t1kvid_t *vid) +{ + uint32_t lp_latch = vid->displine * vid->crtc[1]; + + vid->crtc[0x10] = (lp_latch >> 8) & 0x3f; + vid->crtc[0x11] = lp_latch & 0xff; +} + +void +tandy_vid_out(uint16_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint8_t old; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 0x1f; + break; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + if (dev->is_sl2) + vid->crtc[vid->crtcreg] = val & crtcmask_sl[vid->crtcreg]; + else + vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + vid->fullchange = changeframecount; + recalc_timings(dev); + } + } + break; + + case 0x03d8: + old = vid->mode; + vid->mode = val; + if ((old ^ val) & 0x01) + recalc_timings(dev); + if (!dev->is_sl2) + update_cga16_color(vid->mode); + break; + + case 0x03d9: + vid->col = val; + break; + + case 0x03da: + vid->array_index = val & 0x1f; + break; + + case 0x3db: + if (!dev->is_sl2 && (vid->lp_strobe == 1)) + vid->lp_strobe = 0; + break; + + case 0x3dc: + if (!dev->is_sl2 && (vid->lp_strobe == 0)) { + vid->lp_strobe = 1; + vid_update_latch(vid); + } + break; + + case 0x03de: + if (vid->array_index & 16) + val &= 0xf; + vid->array[vid->array_index & 0x1f] = val; + if (dev->is_sl2) { + if ((vid->array_index & 0x1f) == 5) { + recalc_mapping(dev); + tandy_recalc_address_sl(dev); + } + } + break; + + case 0x03df: + vid->memctrl = val; + if (dev->is_sl2) + tandy_recalc_address_sl(dev); + else + recalc_address(dev); + break; + + case 0x0065: + if (val == 8) + return; /*Hack*/ + vid->planar_ctrl = val; + recalc_mapping(dev); + break; + + default: + break; + } +} + +uint8_t +tandy_vid_in(uint16_t addr, void *priv) +{ + const tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint8_t ret = 0xff; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + break; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + break; + + case 0x03da: + ret = vid->stat; + break; + + case 0x3db: + if (!dev->is_sl2 && (vid->lp_strobe == 1)) + vid->lp_strobe = 0; + break; + + case 0x3dc: + if (!dev->is_sl2 && (vid->lp_strobe == 0)) { + vid->lp_strobe = 1; + vid_update_latch(vid); + } + break; + + default: + break; + } + + return ret; +} + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) + return; + + if (dev->is_sl2) { + if (vid->array[5] & 1) + vid->b8000[addr & 0xffff] = val; + else { + if ((addr & 0x7fff) < vid->b8000_limit) + vid->b8000[addr & 0x7fff] = val; + } + } else { + vid->b8000[addr & vid->b8000_mask] = val; + } +} + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + const tandy_t *dev = (tandy_t *) priv; + const t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) + return 0xff; + + if (dev->is_sl2) { + if (vid->array[5] & 1) + return (vid->b8000[addr & 0xffff]); + if ((addr & 0x7fff) < vid->b8000_limit) + return (vid->b8000[addr & 0x7fff]); + else + return 0xff; + } else { + return (vid->b8000[addr & vid->b8000_mask]); + } +} + +static void +vid_poll(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int c; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!vid->linepos) { + timer_advance_u64(&vid->timer, vid->dispofftime); + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if ((vid->crtc[8] & 3) == 3) + vid->sc = (vid->sc << 1) & 7; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + cols[0] = (vid->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) { + if (vid->array[3] & 4) { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = cols[0]; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = cols[0]; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = cols[0]; + } + } else if ((vid->mode & 0x12) == 0x12) { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = 0; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; + } + } else { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->col & 15) + 16; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + } + } + } + if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ + for (x = 0; x < vid->crtc[1] * 2; x++) { + dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | vid->vram[((vid->ma << 1) + 1) & 0xffff]; + vid->ma++; + buffer32->line[vid->displine << 1][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 11] = 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->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + buffer32->line[vid->displine << 1][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = buffer32->line[vid->displine << 1][(x << 3) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 10] = buffer32->line[vid->displine << 1][(x << 3) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 12] = buffer32->line[vid->displine << 1][(x << 3) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 14] = buffer32->line[vid->displine << 1][(x << 3) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + if (dev->is_sl2) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + } else { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + } + vid->ma++; + buffer32->line[vid->displine << 1][(x << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 8] = buffer32->line[vid->displine << 1][(x << 4) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 9] = buffer32->line[vid->displine << 1][(x << 4) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 10] = buffer32->line[vid->displine << 1][(x << 4) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 12] = buffer32->line[vid->displine << 1][(x << 4) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 13] = buffer32->line[vid->displine << 1][(x << 4) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 14] = buffer32->line[vid->displine << 1][(x << 4) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 16] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 16] = buffer32->line[vid->displine << 1][(x << 4) + 17] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 17] = buffer32->line[vid->displine << 1][(x << 4) + 18] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 18] = buffer32->line[vid->displine << 1][(x << 4) + 19] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 20] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 20] = buffer32->line[vid->displine << 1][(x << 4) + 21] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 21] = buffer32->line[vid->displine << 1][(x << 4) + 22] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 22] = buffer32->line[vid->displine << 1][(x << 4) + 23] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 23] = 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++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + chr = (dat >> 6) & 2; + chr |= ((dat >> 15) & 1); + buffer32->line[vid->displine << 1][(x << 3) + 8 + c] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + dat <<= 1; + } + } + } else if (vid->mode & 1) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[(vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->cursorvisible && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + if (vid->sc & 8) { + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[0]; + } + } else { + for (c = 0; c < 8; c++) { + if (vid->sc == 8) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] ^= 15; + } + } + vid->ma++; + } + } else if (!(vid->mode & 2)) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[(vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->cursorvisible && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + vid->ma++; + if (vid->sc & 8) { + for (c = 0; c < 8; c++) + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) { + if (vid->sc == 8) { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + if (drawcursor) { + for (c = 0; c < 16; c++) { + buffer32->line[vid->displine << 1][(x << 4) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] ^= 15; + } + } + } + } else if (!(vid->mode & 16)) { + cols[0] = (vid->col & 15); + col = (vid->col & 16) ? 8 : 0; + if (vid->mode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->col & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + cols[0] = vid->array[(cols[0] & vid->array[1]) + 16] + 16; + cols[1] = vid->array[(cols[1] & vid->array[1]) + 16] + 16; + cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; + cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + cols[0] = 0; + cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 16; c++) { + buffer32->line[vid->displine << 1][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + if (vid->array[3] & 4) { + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + } + } else { + cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, cols[0]); + } + } + } + + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + if (!dev->is_sl2 && vid->composite) { + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine << 1]); + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1) + 1]); + } else { + video_process_8(x, vid->displine << 1); + video_process_8(x, (vid->displine << 1) + 1); + } + vid->sc = oldsc; + if (vid->vc == vid->crtc[7] && !vid->sc) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + timer_advance_u64(&vid->timer, vid->dispontime); + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (!vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { + vid->cursorvisible = 0; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (!vid->vadj) { + vid->dispon = 1; + if (dev->is_sl2 && (vid->array[5] & 1)) + vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { + vid->maback = vid->ma; + vid->sc = 0; + oldvc = vid->vc; + vid->vc++; + if (dev->is_sl2) + vid->vc &= 255; + else + vid->vc &= 127; + if (vid->vc == vid->crtc[6]) + vid->dispon = 0; + if (oldvc == vid->crtc[4]) { + vid->vc = 0; + vid->vadj = vid->crtc[5]; + if (!vid->vadj) + vid->dispon = 1; + if (!vid->vadj) { + if (dev->is_sl2 && (vid->array[5] & 1)) + vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + } + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + if (vid->vc == vid->crtc[7]) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 16; + picint(1 << 5); + if (vid->crtc[7]) { + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + + xs_temp = x; + ys_temp = (vid->lastline - vid->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) + xs_temp = 656; + if (ys_temp < 32) + ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + 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)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + video_blit_memtoscreen(0, (vid->firstline - 4) << 1, + xsize, ((vid->lastline - vid->firstline) + 8) << 1); + } else { + video_blit_memtoscreen(8, vid->firstline << 1, + xsize, (vid->lastline - vid->firstline) << 1); + } + } + + frames++; + + video_res_x = xsize; + video_res_y = ysize; + if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + video_res_x /= 2; + video_bpp = 4; + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + video_res_x /= 4; + video_bpp = 4; + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + } else if (vid->mode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (!(vid->mode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (!(vid->mode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 1; + } + } + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if (vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1))) + vid->cursorvisible = 1; + } +} + +void +tandy_vid_speed_changed(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + + recalc_timings(dev); +} + +void +tandy_vid_close(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + + free(dev->vid); + dev->vid = NULL; +} + +void +tandy_vid_init(tandy_t *dev) +{ + int display_type; + t1kvid_t *vid; + + vid = calloc(1, sizeof(t1kvid_t)); + vid->memctrl = -1; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + + display_type = device_get_config_int("display_type"); + vid->composite = (display_type != TANDY_RGB); + + cga_comp_init(1); + + if (dev->is_sl2) { + vid->b8000_limit = 0x8000; + vid->planar_ctrl = 4; + overscan_x = 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); + mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); + io_sethandler(0x03d0, 16, + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + + dev->vid = vid; +} + +const device_config_t vid_config[] = { + // clang-format off + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = TANDY_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = TANDY_RGB }, + { .description = "Composite", .value = TANDY_COMPOSITE }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t tandy_1000_video_device = { + .name = "Tandy 1000", + .internal_name = "tandy1000_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = vid_config +}; + +const device_t tandy_1000hx_video_device = { + .name = "Tandy 1000 HX", + .internal_name = "tandy1000_hx_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = vid_config +}; + +const device_t tandy_1000sl_video_device = { + .name = "Tandy 1000SL2", + .internal_name = "tandy1000_sl_video", + .flags = 0, + .local = 1, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = NULL +}; \ No newline at end of file