/* * (C) Copyright 1992, ..., 2004 the "DOSEMU-Development-Team". * * for details see file COPYING in the DOSEMU distribution */ /* * DANG_BEGIN_MODULE * * REMARK * The VGA CRT Controller emulator for VGAEmu. * /REMARK * DANG_END_MODULE * * DANG_BEGIN_CHANGELOG * * 1999/01/05: Correct initial values for standard VGA modes. * -- sw (Steffen Winterfeldt ) * * DANG_END_CHANGELOG * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * some configurable options * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Debug level for the CRT Controller. * 0 - normal / 1 - useful / 2 - too much */ #define DEBUG_CRTC 0 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined True #define False 0 #define True 1 #endif #define crtc_msg(x...) v_printf("VGAEmu: " x) #if DEBUG_CRTC >= 1 #define crtc_deb(x...) v_printf("VGAEmu: " x) #else #define crtc_deb(x...) #endif #if DEBUG_CRTC >= 2 #define crtc_deb2(x...) v_printf("VGAEmu: " x) #else #define crtc_deb2(x...) #endif #define NEWBITS(a) ((vga.crtc.data[ind] ^ data) & (a)) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include "emu.h" #include "vgaemu.h" #include "video.h" #include "memory.h" /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static unsigned char crtc_ival[16][CRTC_MAX_INDEX + 1] = { {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, 0xff}, {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, 0xff}, {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, 0xff}, {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, 0xff}, {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, 0xff}, {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff} }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * DANG_BEGIN_FUNCTION CRTC_init * * Initializes the CRT Controller. * This is an interface function. * * DANG_END_FUNCTION * */ void CRTC_init() { unsigned i, j = 15; if(vga.VGA_mode >= 0 && vga.VGA_mode <= 7) j = vga.VGA_mode; else if(vga.VGA_mode >= 0x0d && vga.VGA_mode <= 0x13) j = vga.VGA_mode - 5; for(i = 0; i <= CRTC_MAX_INDEX; i++) vga.crtc.data[i] = crtc_ival[j][i]; vga.crtc.index = 0; vga.crtc.readonly = 1; vgaemu_adj_cfg(CFG_CRTC_ADDR_MODE, 1); vgaemu_adj_cfg(CFG_CRTC_WIDTH, 1); vgaemu_adj_cfg(CFG_CRTC_HEIGHT, 1); vgaemu_adj_cfg(CFG_CRTC_LINE_COMPARE, 1); crtc_msg("CRTC_init done\n"); } void CRTC_set_index(unsigned char index) { crtc_deb2( "CRTC_set_index: 0x%02x%s\n", (unsigned) index, index > CRTC_MAX_INDEX ? " (too large)" : "" ); vga.crtc.index = index; } unsigned char CRTC_get_index() { crtc_deb2("CRTC_get_index: 0x%02x\n", (unsigned) vga.crtc.index); return vga.crtc.index; } void CRTC_write_value(unsigned char data) { unsigned u = data, u1, ind = vga.crtc.index; unsigned todo_ind, todo[4]; if(ind > CRTC_MAX_INDEX) { crtc_deb("CRTC_write_value: data (0x%02x) ignored\n", u); return; } crtc_deb2("CRTC_write_value: crtc[0x%02x] = 0x%02x\n", ind, u); if(vga.crtc.readonly) { /* read only regs 00h-07h with the exception of bit4 in 07h */ if (ind <= 6) return; if (ind == 7) data = (vga.crtc.data[ind] & 0xef) | (data & 0x10); } if(vga.crtc.data[ind] == data) return; for(todo_ind = 0; todo_ind < sizeof todo / sizeof *todo; todo_ind++) todo[todo_ind] = 0; todo_ind = 0; switch(ind) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_WIDTH; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x06: if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x07: if(NEWBITS(0x10)) { todo[todo_ind++] = CFG_CRTC_LINE_COMPARE; } if(NEWBITS(0xEF)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x09: if(NEWBITS(0x40)) { todo[todo_ind++] = CFG_CRTC_LINE_COMPARE; } if(NEWBITS(0xBF)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x0c: /* Start Address High */ /* these shifts involving vga.crtc.addr_mode should really be rotations, depending on mode control bit 5 */ vga.display_start = (vga.crtc.data[0x0d] + (u << 8)) << vga.crtc.addr_mode; screen_adr = SCREEN_ADR(0) + vga.display_start/2; crtc_deb("CRTC_write_value: Start Address = 0x%04x, high changed\n", vga.display_start); break; case 0x0d: /* Start Address Low */ vga.display_start = (u + (vga.crtc.data[0x0c] << 8)) << vga.crtc.addr_mode; /* this shift should really be a rotation, depending on mode control bit 5 */ screen_adr = SCREEN_ADR(0) + vga.display_start/2; crtc_deb("CRTC_write_value: Start Address = 0x%04x, low changed\n", vga.display_start); break; case 0x0e: /* Cursor Location High */ vga.crtc.cursor_location = (vga.crtc.data[0x0f] + (u << 8)) << vga.crtc.addr_mode; cursor_row = (vga.crtc.cursor_location - vga.display_start) / vga.scan_len; cursor_col = ((vga.crtc.cursor_location - vga.display_start) % vga.scan_len) / 2; crtc_deb("CRTC_write_value: Cursor Location = 0x%04x\n", vga.crtc.cursor_location); break; case 0x0f: /* Cursor Location Low */ vga.crtc.cursor_location = (u + (vga.crtc.data[0x0e] << 8)) << vga.crtc.addr_mode; cursor_row = (vga.crtc.cursor_location - vga.display_start) / vga.scan_len; cursor_col = ((vga.crtc.cursor_location - vga.display_start) % vga.scan_len) / 2; crtc_deb("CRTC_write_value: Cursor Location = 0x%04x\n", vga.crtc.cursor_location); break; case 0x11: if(NEWBITS(0x80)) { vga.crtc.readonly = (data >= 0x80); } if(NEWBITS(0x7F)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x10: case 0x12: if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x13: /* Number of bytes in a scanline */ if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_ADDR_MODE; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x14: /* Underline Location */ if(NEWBITS(0x40)) { todo[todo_ind++] = CFG_CRTC_ADDR_MODE; } break; case 0x15: case 0x16: if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_HEIGHT; } crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (guessed)\n", ind, u); break; case 0x17: /* Mode Control */ if(NEWBITS(0x40)) { todo[todo_ind++] = CFG_CRTC_ADDR_MODE; } if(NEWBITS(0x80)) { crtc_deb("CRTC_write_value: %svideo access\n", (data & 0x80) ? "" : "no "); u1 = vga.config.video_off; vga.config.video_off = (vga.config.video_off & ~4) + (((data >> 5) & 4) ^ 4); if(u1 != vga.config.video_off) { crtc_deb("CRTC_write_value: video signal turned %s\n", vga.config.video_off ? "off" : "on"); } } break; case 0x18: /* line compare */ if(NEWBITS(0xFF)) { todo[todo_ind++] = CFG_CRTC_LINE_COMPARE; } break; default: crtc_deb("CRTC_write_value: crtc[0x%02x] = 0x%02x (ignored)\n", ind, u); } vga.crtc.data[ind] = data; for(todo_ind = 0; todo_ind < sizeof todo / sizeof *todo; todo_ind++) { if(todo[todo_ind]) vgaemu_adj_cfg(todo[todo_ind], 0); } } unsigned char CRTC_read_value() { unsigned char uc; uc = vga.crtc.index > CRTC_MAX_INDEX ? 0x00 : vga.crtc.data[vga.crtc.index]; crtc_deb2("CRTC_read_value: crtc[0x%02x] = 0x%02x\n", (unsigned) vga.crtc.index, (unsigned) uc); return uc; }