OSDN Git Service

[INITIAL] Import 20141226 version of http://homepage3.nifty.com/takeda-toshiya/common...
[csp-qt/common_source_project-fm7.git] / source / src / vm / tms9918a.cpp
diff --git a/source/src/vm/tms9918a.cpp b/source/src/vm/tms9918a.cpp
new file mode 100644 (file)
index 0000000..2795497
--- /dev/null
@@ -0,0 +1,545 @@
+/*\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