--- /dev/null
+/*\r
+ Skelton for retropc emulator\r
+\r
+ Origin : MAME TMS9928A Core\r
+ Author : Takeda.Toshiya\r
+ Date : 2006.08.18 -\r
+ 2007.07.21 -\r
+\r
+ [ TMS9918A ]\r
+*/\r
+\r
+#include "tms9918a.h"\r
+\r
+#define ADDR_MASK (TMS9918A_VRAM_SIZE - 1)\r
+\r
+static const scrntype palette_pc[16] = {\r
+ RGB_COLOR( 0, 0, 0), RGB_COLOR( 0, 0, 0), RGB_COLOR( 33, 200, 66), RGB_COLOR( 94, 220, 120),\r
+ RGB_COLOR( 84, 85, 237), RGB_COLOR(125, 118, 252), RGB_COLOR(212, 82, 77), RGB_COLOR( 66, 235, 245),\r
+ RGB_COLOR(252, 85, 84), RGB_COLOR(255, 121, 120), RGB_COLOR(212, 193, 84), RGB_COLOR(230, 206, 128),\r
+ RGB_COLOR( 33, 176, 59), RGB_COLOR(201, 91, 186), RGB_COLOR(204, 204, 204), RGB_COLOR(255, 255, 255)\r
+};\r
+\r
+void TMS9918A::initialize()\r
+{\r
+ // register event\r
+ register_vline_event(this);\r
+}\r
+\r
+void TMS9918A::reset()\r
+{\r
+ memset(vram, 0, sizeof(vram));\r
+ memset(regs, 0, sizeof(regs));\r
+ status_reg = read_ahead = first_byte = 0;\r
+ vram_addr = 0;\r
+ intstat = latch = false;\r
+ color_table = pattern_table = name_table = 0;\r
+ sprite_pattern = sprite_attrib = 0;\r
+ color_mask = pattern_mask = 0;\r
+}\r
+\r
+void TMS9918A::write_io8(uint32 addr, uint32 data)\r
+{\r
+ if(addr & 1) {\r
+ // register\r
+ if(latch) {\r
+ if(data & 0x80) {\r
+ switch(data & 7) {\r
+ case 0:\r
+ regs[0] = first_byte & 3;\r
+ if(regs[0] & 2) {\r
+ color_table = ((regs[3] & 0x80) * 64) & ADDR_MASK;\r
+ color_mask = ((regs[3] & 0x7f) * 8) | 7;\r
+ pattern_table = ((regs[4] & 4) * 2048) & ADDR_MASK;\r
+ pattern_mask = ((regs[4] & 3) * 256) | (color_mask & 0xff);\r
+ } else {\r
+ color_table = (regs[3] * 64) & ADDR_MASK;\r
+ pattern_table = (regs[4] * 2048) & ADDR_MASK;\r
+ }\r
+ break;\r
+ case 1:\r
+ regs[1] = first_byte & 0xfb;\r
+ set_intstat((regs[1] & 0x20) && (status_reg & 0x80));\r
+ break;\r
+ case 2:\r
+ regs[2] = first_byte & 0x0f;\r
+ name_table = (regs[2] * 1024) & ADDR_MASK;\r
+ break;\r
+ case 3:\r
+ regs[3] = first_byte;\r
+ if(regs[0] & 2) {\r
+ color_table = ((regs[3] & 0x80) * 64) & ADDR_MASK;\r
+ color_mask = ((regs[3] & 0x7f) * 8) | 7;\r
+ } else {\r
+ color_table = (regs[3] * 64) & ADDR_MASK;\r
+ }\r
+ pattern_mask = ((regs[4] & 3) * 256) | (color_mask & 0xff);\r
+ break;\r
+ case 4:\r
+ regs[4] = first_byte & 7;\r
+ if(regs[0] & 2) {\r
+ pattern_table = ((regs[4] & 4) * 2048) & ADDR_MASK;\r
+ pattern_mask = ((regs[4] & 3) * 256) | 255;\r
+ } else {\r
+ pattern_table = (regs[4] * 2048) & ADDR_MASK;\r
+ }\r
+ break;\r
+ case 5:\r
+ regs[5] = first_byte & 0x7f;\r
+ sprite_attrib = (regs[5] * 128) & ADDR_MASK;\r
+ break;\r
+ case 6:\r
+ regs[6] = first_byte & 7;\r
+ sprite_pattern = (regs[6] * 2048) & ADDR_MASK;\r
+ break;\r
+ case 7:\r
+ regs[7] = first_byte;\r
+ break;\r
+ }\r
+ } else {\r
+ vram_addr = ((data * 256) | first_byte) & ADDR_MASK;\r
+ if(!(data & 0x40)) {\r
+ read_io8(0); // read ahead\r
+ }\r
+ }\r
+ latch = false;\r
+ } else {\r
+ first_byte = data;\r
+ latch = true;\r
+ }\r
+ } else {\r
+ // vram\r
+ vram[vram_addr] = data;\r
+ vram_addr = (vram_addr + 1) & ADDR_MASK;\r
+ read_ahead = data;\r
+ latch = false;\r
+ }\r
+}\r
+\r
+uint32 TMS9918A::read_io8(uint32 addr)\r
+{\r
+ if(addr & 1) {\r
+ // register\r
+ uint8 val = status_reg;\r
+ status_reg = 0x1f;\r
+ set_intstat(false);\r
+ latch = false;\r
+ return val;\r
+ } else {\r
+ // vram\r
+ uint8 val = read_ahead;\r
+ read_ahead = vram[vram_addr];\r
+ vram_addr = (vram_addr + 1) & ADDR_MASK;\r
+ latch = false;\r
+ return val;\r
+ }\r
+}\r
+\r
+#ifdef TMS9918A_SUPER_IMPOSE\r
+void TMS9918A::write_signal(int id, uint32 data, uint32 mask)\r
+{\r
+ if(id == SIG_TMS9918A_SUPER_IMPOSE) {\r
+ now_super_impose = ((data & mask) != 0);\r
+ }\r
+}\r
+#endif\r
+\r
+void TMS9918A::draw_screen()\r
+{\r
+#ifdef TMS9918A_SUPER_IMPOSE\r
+ if(now_super_impose) {\r
+ emu->get_direct_show_buffer();\r
+ }\r
+#endif\r
+ // update screen buffer\r
+#if SCREEN_WIDTH == 512\r
+ for(int y = 0, y2 = 0; y < 192; y++, y2 += 2) {\r
+ scrntype* dest0 = emu->screen_buffer(y2 + 0);\r
+ scrntype* dest1 = emu->screen_buffer(y2 + 1);\r
+ uint8* src = screen[y];\r
+#ifdef TMS9918A_SUPER_IMPOSE\r
+ if(now_super_impose) {\r
+ for(int x = 0, x2 = 0; x < 256; x++, x2 += 2) {\r
+ uint8 c = src[x] & 0x0f;\r
+ if(c != 0) {\r
+ dest0[x2] = dest0[x2 + 1] = dest1[x2] = dest1[x2 + 1] = palette_pc[c];\r
+ }\r
+ }\r
+ } else\r
+#endif\r
+ {\r
+ for(int x = 0, x2 = 0; x < 256; x++, x2 += 2) {\r
+ dest0[x2] = dest0[x2 + 1] = palette_pc[src[x] & 0x0f];\r
+ }\r
+ memcpy(dest1, dest0, 512 * sizeof(scrntype));\r
+ }\r
+ }\r
+#else\r
+ for(int y = 0; y < 192; y++) {\r
+ scrntype* dest = emu->screen_buffer(y);\r
+ uint8* src = screen[y];\r
+#ifdef TMS9918A_SUPER_IMPOSE\r
+ if(now_super_impose) {\r
+ for(int x = 0; x < 256; x++) {\r
+ uint8 c = src[x] & 0x0f;\r
+ if(c != 0) {\r
+ dest[x] = palette_pc[c];\r
+ }\r
+ }\r
+ } else\r
+#endif\r
+ for(int x = 0; x < 256; x++) {\r
+ dest[x] = palette_pc[src[x] & 0x0f];\r
+ }\r
+ }\r
+#endif\r
+}\r
+\r
+void TMS9918A::event_vline(int v, int clock)\r
+{\r
+ if(v == 192) {\r
+ // create virtual screen\r
+ if(regs[1] & 0x40) {\r
+ // draw character plane\r
+ int mode = (regs[0] & 2) | ((regs[1] & 0x10) >> 4) | ((regs[1] & 8) >> 1);\r
+ switch(mode) {\r
+ case 0:\r
+ draw_mode0();\r
+ break;\r
+ case 1:\r
+ draw_mode1();\r
+ break;\r
+ case 2:\r
+ draw_mode2();\r
+ break;\r
+ case 3:\r
+ draw_mode12();\r
+ break;\r
+ case 4:\r
+ draw_mode3();\r
+ break;\r
+ case 6:\r
+ draw_mode23();\r
+ break;\r
+ case 5:\r
+ case 7:\r
+ draw_modebogus();\r
+ break;\r
+ }\r
+ // draw sprite plane\r
+ if((regs[1] & 0x50) == 0x40) {\r
+ draw_sprites();\r
+ }\r
+ } else {\r
+ memset(screen, 0, sizeof(screen));\r
+ }\r
+ \r
+ // do interrupt\r
+ status_reg |= 0x80;\r
+ set_intstat((regs[1] & 0x20) != 0);\r
+ }\r
+}\r
+\r
+void TMS9918A::set_intstat(bool val)\r
+{\r
+ if(val != intstat) {\r
+ write_signals(&outputs_irq, val ? 0xffffffff : 0);\r
+ intstat = val;\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode0()\r
+{\r
+ for(int y = 0, name = 0; y < 24; y++) {\r
+ for(int x = 0; x < 32; x++) {\r
+ uint16 code = vram[name_table + (name++)];\r
+ uint8* pattern_ptr = vram + pattern_table + code * 8;\r
+ uint8 color = vram[color_table + (code >> 3)];\r
+ uint8 fg = (color & 0xf0) ? (color >> 4) : (regs[7] & 0x0f);\r
+ uint8 bg = (color & 0x0f) ? (color & 0x0f) : (regs[7] & 0x0f);\r
+ for(int yy=0; yy < 8; yy++) {\r
+ uint8 pattern = *pattern_ptr++;\r
+ uint8* buffer = screen[y * 8 + yy] + x * 8;\r
+ buffer[0] = (pattern & 0x80) ? fg : bg;\r
+ buffer[1] = (pattern & 0x40) ? fg : bg;\r
+ buffer[2] = (pattern & 0x20) ? fg : bg;\r
+ buffer[3] = (pattern & 0x10) ? fg : bg;\r
+ buffer[4] = (pattern & 0x08) ? fg : bg;\r
+ buffer[5] = (pattern & 0x04) ? fg : bg;\r
+ buffer[6] = (pattern & 0x02) ? fg : bg;\r
+ buffer[7] = (pattern & 0x01) ? fg : bg;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode1()\r
+{\r
+ uint8 fg = regs[7] >> 4;\r
+ uint8 bg = regs[7] & 0x0f;\r
+ memset(screen, bg, sizeof(screen));\r
+ for(int y = 0, name = 0; y < 24; y++) {\r
+ for(int x = 0; x < 40; x++) {\r
+ uint16 code = vram[name_table + (name++)];\r
+ uint8* pattern_ptr = vram + pattern_table + code * 8;\r
+ for(int yy = 0; yy < 8; yy++) {\r
+ uint8 pattern = *pattern_ptr++;\r
+ uint8* buffer = screen[y * 8 + yy] + x * 6 + 8;\r
+ buffer[0] = (pattern & 0x80) ? fg : bg;\r
+ buffer[1] = (pattern & 0x40) ? fg : bg;\r
+ buffer[2] = (pattern & 0x20) ? fg : bg;\r
+ buffer[3] = (pattern & 0x10) ? fg : bg;\r
+ buffer[4] = (pattern & 0x08) ? fg : bg;\r
+ buffer[5] = (pattern & 0x04) ? fg : bg;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode2()\r
+{\r
+ for(int y = 0, name = 0; y < 24; y++) {\r
+ for(int x = 0; x < 32; x++) {\r
+ uint16 code = vram[name_table + (name++)] + (y & 0xf8) * 32;\r
+ uint8* pattern_ptr = vram + pattern_table + (code & pattern_mask) * 8;\r
+ uint8* color_ptr = vram + color_table + (code & color_mask) * 8;\r
+ for(int yy = 0; yy < 8; yy++) {\r
+ uint8 pattern = *pattern_ptr++;\r
+ uint8 color = *color_ptr++;\r
+ uint8 fg = (color & 0xf0) ? (color >> 4) : (regs[7] & 0x0f);\r
+ uint8 bg = (color & 0x0f) ? (color & 0x0f) : (regs[7] & 0x0f);\r
+ uint8* buffer = screen[y * 8 + yy] + x * 8;\r
+ buffer[0] = (pattern & 0x80) ? fg : bg;\r
+ buffer[1] = (pattern & 0x40) ? fg : bg;\r
+ buffer[2] = (pattern & 0x20) ? fg : bg;\r
+ buffer[3] = (pattern & 0x10) ? fg : bg;\r
+ buffer[4] = (pattern & 0x08) ? fg : bg;\r
+ buffer[5] = (pattern & 0x04) ? fg : bg;\r
+ buffer[6] = (pattern & 0x02) ? fg : bg;\r
+ buffer[7] = (pattern & 0x01) ? fg : bg;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode12()\r
+{\r
+ uint8 fg = regs[7] >> 4;\r
+ uint8 bg = regs[7] & 0x0f;\r
+ memset(screen, bg, sizeof(screen));\r
+ for(int y = 0, name = 0; y < 24; y++) {\r
+ for(int x = 0; x < 40; x++) {\r
+ uint16 code = vram[name_table + (name++)] + (y & 0xf8) * 32;\r
+ uint8* pattern_ptr = vram + pattern_table + (code & pattern_mask) * 8;\r
+ for(int yy = 0; yy < 8; yy++) {\r
+ uint8 pattern = *pattern_ptr++;\r
+ uint8* buffer = screen[y * 8 + yy] + x * 6 + 8;\r
+ buffer[0] = (pattern & 0x80) ? fg : bg;\r
+ buffer[1] = (pattern & 0x40) ? fg : bg;\r
+ buffer[2] = (pattern & 0x20) ? fg : bg;\r
+ buffer[3] = (pattern & 0x10) ? fg : bg;\r
+ buffer[4] = (pattern & 0x08) ? fg : bg;\r
+ buffer[5] = (pattern & 0x04) ? fg : bg;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode3()\r
+{\r
+ for(int y = 0, name = 0; y < 24; y++) {\r
+ for(int x = 0; x < 32; x++) {\r
+ uint16 code = vram[name_table + (name++)];\r
+ uint8* pattern_ptr = vram + pattern_table + code * 8 + (y & 3) * 2;\r
+ for(int yy = 0; yy < 2; yy++) {\r
+ uint8 color = *pattern_ptr++;\r
+ uint8 fg = (color & 0xf0) ? (color >> 4) : (regs[7] & 0x0f);\r
+ uint8 bg = (color & 0x0f) ? (color & 0x0f) : (regs[7] & 0x0f);\r
+ for(int yyy = 0; yyy < 4; yyy++) {\r
+ uint8* buffer = screen[y * 8 + yy * 4 + yyy] + x * 8;\r
+ buffer[0] = buffer[1] = buffer[2] = buffer[3] = fg;\r
+ buffer[4] = buffer[5] = buffer[6] = buffer[7] = bg;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_mode23()\r
+{\r
+ for(int y = 0, name = 0; y < 24;y++) {\r
+ for(int x = 0; x < 32; x++) {\r
+ uint16 code = vram[name_table + (name++)];\r
+ uint8* pattern_ptr = vram + pattern_table + ((code + (y & 3) * 2 + (y & 0xf8) * 32) & pattern_mask) * 8;\r
+ for(int yy = 0; yy < 2; yy++) {\r
+ uint8 color = *pattern_ptr++;\r
+ uint8 fg = (color & 0xf0) ? (color >> 4) : (regs[7] & 0x0f);\r
+ uint8 bg = (color & 0x0f) ? (color & 0x0f) : (regs[7] & 0x0f);\r
+ for(int yyy = 0; yyy < 4; yyy++) {\r
+ uint8* buffer = screen[y * 8 + yy * 4 + yyy] + x * 8;\r
+ buffer[0] = buffer[1] = buffer[2] = buffer[3] = fg;\r
+ buffer[4] = buffer[5] = buffer[6] = buffer[7] = bg;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_modebogus()\r
+{\r
+ uint8 fg = regs[7] >> 4;\r
+ uint8 bg = regs[7] & 0x0f;\r
+ for(int y = 0; y < 192; y++) {\r
+ uint8* buffer = screen[y];\r
+ int x = 0;\r
+ for(int i = 0; i < 8; i++) {\r
+ buffer[x++] = bg;\r
+ }\r
+ for(int i = 0; i < 40; i++) {\r
+ for(int j = 0; j < 4; j++) {\r
+ buffer[x++] = fg;\r
+ }\r
+ for(int j = 0; j < 2; j++) {\r
+ buffer[x++] = bg;\r
+ }\r
+ }\r
+ for(int i = 0; i < 8; i++) {\r
+ buffer[x++] = bg;\r
+ }\r
+ }\r
+}\r
+\r
+void TMS9918A::draw_sprites()\r
+{\r
+ uint8* attrib_ptr = vram + sprite_attrib;\r
+ int size = (regs[1] & 2) ? 16 : 8;\r
+ bool large = ((regs[1] & 1) != 0);\r
+ uint8 limit[192], collision[192][256];\r
+ int illegal_sprite = 0, illegal_sprite_line = 255, p;\r
+ memset(limit, 4, sizeof(limit));\r
+ memset(collision, 0, sizeof(collision));\r
+ status_reg = 0x80;\r
+ \r
+ for(p = 0; p < 32; p++) {\r
+ int y = *attrib_ptr++;\r
+ if(y == 208) {\r
+ break;\r
+ }\r
+ if(y > 208) {\r
+ y = -(~y & 0xff);\r
+ } else {\r
+ y++;\r
+ }\r
+ int x = *attrib_ptr++;\r
+ uint8* pattern_ptr = vram + sprite_pattern + ((size == 16) ? (*attrib_ptr & 0xfc) : *attrib_ptr) * 8;\r
+ attrib_ptr++;\r
+ uint8 c = *attrib_ptr & 0x0f;\r
+ if(*attrib_ptr & 0x80) {\r
+ x -= 32;\r
+ }\r
+ attrib_ptr++;\r
+ \r
+ if(!large) {\r
+ // draw sprite (not enlarged)\r
+ for(int yy = y; yy < y + size; yy++) {\r
+ if(yy < 0 || 191 < yy) {\r
+ continue;\r
+ }\r
+ if(limit[yy] == 0) {\r
+ // illegal sprite line\r
+ if(yy < illegal_sprite_line) {\r
+ illegal_sprite_line = yy;\r
+ illegal_sprite = p;\r
+ } else if(illegal_sprite_line == yy) {\r
+ if(illegal_sprite > p) {\r
+ illegal_sprite = p;\r
+ }\r
+ }\r
+#ifdef TMS9918A_LIMIT_SPRITES\r
+ continue;\r
+#endif\r
+ } else {\r
+ limit[yy]--;\r
+ }\r
+ uint16 line = pattern_ptr[yy - y] * 256 + pattern_ptr[yy - y + 16];\r
+ for(int xx = x; xx < x + size; xx++) {\r
+ if(line & 0x8000) {\r
+ if(0 <= xx && xx < 256) {\r
+ if(collision[yy][xx]) {\r
+ status_reg |= 0x20;\r
+ } else {\r
+ collision[yy][xx] = 1;\r
+ }\r
+ if(c && !(collision[yy][xx] & 2)) {\r
+ collision[yy][xx] |= 2;\r
+ screen[yy][xx] = c;\r
+ }\r
+ }\r
+ }\r
+ line *= 2;\r
+ }\r
+ }\r
+ } else {\r
+ // draw enlarged sprite\r
+ for(int i = 0; i < size; i++) {\r
+ int yy = y + i * 2;\r
+ uint16 line2 = pattern_ptr[i] * 256 + pattern_ptr[i + 16];\r
+ for(int j = 0; j < 2; j++) {\r
+ if(0 <= yy && yy <= 191) {\r
+ if(limit[yy] == 0) {\r
+ // illegal sprite line\r
+ if(yy < illegal_sprite_line) {\r
+ illegal_sprite_line = yy;\r
+ illegal_sprite = p;\r
+ } else if(illegal_sprite_line == yy) {\r
+ if(illegal_sprite > p) {\r
+ illegal_sprite = p;\r
+ }\r
+ }\r
+#ifdef TMS9918A_LIMIT_SPRITES\r
+ continue;\r
+#endif\r
+ } else {\r
+ limit[yy]--;\r
+ }\r
+ uint16 line = line2;\r
+ for(int xx = x; xx < x + size * 2; xx += 2) {\r
+ if(line & 0x8000) {\r
+ if(0 <= xx && xx < 256) {\r
+ if(collision[yy][xx]) {\r
+ status_reg |= 0x20;\r
+ } else {\r
+ collision[yy][xx] = 1;\r
+ }\r
+ if(c && !(collision[yy][xx] & 2)) {\r
+ collision[yy][xx] |= 2;\r
+ screen[yy][xx] = c;\r
+ }\r
+ }\r
+ if(0 <= xx + 1 && xx + 1 < 256) {\r
+ if(collision[yy][xx + 1]) {\r
+ status_reg |= 0x20;\r
+ } else {\r
+ collision[yy][xx + 1] = 1;\r
+ }\r
+ if(c && !(collision[yy][xx + 1] & 2)) {\r
+ collision[yy][xx + 1] |= 2;\r
+ screen[yy][xx + 1] = c;\r
+ }\r
+ }\r
+ }\r
+ line *= 2;\r
+ }\r
+ }\r
+ yy++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if(illegal_sprite_line == 255) {\r
+ status_reg |= (p > 31) ? 31 : p;\r
+ } else {\r
+ status_reg |= 0x40 + illegal_sprite;\r
+ }\r
+}\r
+\r