summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/video
diff options
context:
space:
mode:
author Wilbert Pol <wilbert@jdg.info>2011-07-30 18:55:47 +0000
committer Wilbert Pol <wilbert@jdg.info>2011-07-30 18:55:47 +0000
commit3a6623a37c4dfd57c583c3b7f49240300f9bcbe5 (patch)
tree48f5b111be1b0f5f55285bd34019a1d625cd06d7 /src/emu/video
parent71bfd34f3aec96aa5fdd1a4ba2fb0475bda7e4b8 (diff)
tms9928a.c: Converted to a C++ device. [Wilbert Pol]
Diffstat (limited to 'src/emu/video')
-rw-r--r--src/emu/video/tms9928a.c1174
-rw-r--r--src/emu/video/tms9928a.h234
2 files changed, 691 insertions, 717 deletions
diff --git a/src/emu/video/tms9928a.c b/src/emu/video/tms9928a.c
index c52589d7096..4b9bba35dd8 100644
--- a/src/emu/video/tms9928a.c
+++ b/src/emu/video/tms9928a.c
@@ -13,9 +13,6 @@
** Improved over the years by MESS and MAME teams.
**
** Todo:
-** - Convert implementation to modern device.
-** - The screen image is rendered in `one go'. Modifications during
-** screen build up are not shown.
** - Colours are incorrect. [fixed by R Nabet ?]
** - Sprites 8-31 are ghosted/cloned in mode 3 when using less than
** three pattern tables. Exact behaviour is not known.
@@ -23,6 +20,17 @@
#include "emu.h"
#include "tms9928a.h"
+#include "machine/devhelpr.h"
+
+
+const device_type TMS9928A = &device_creator<tms9928a_device>;
+const device_type TMS9918 = &device_creator<tms9918_device>;
+const device_type TMS9918A = &device_creator<tms9918a_device>;
+const device_type TMS9118 = &device_creator<tms9118_device>;
+const device_type TMS9128 = &device_creator<tms9128_device>;
+const device_type TMS9929 = &device_creator<tms9929_device>;
+const device_type TMS9929A = &device_creator<tms9929a_device>;
+const device_type TMS9129 = &device_creator<tms9129_device>;
/*
@@ -53,7 +61,7 @@
E Gray 0.80 0.47 0.47 0.80 0.80 0.80 204 204 204
F White 1.00 0.47 0.47 1.00 1.00 1.00 255 255 255
*/
-static const rgb_t TMS9928A_palette[16] =
+static const rgb_t tms9928a_palette[16] =
{
RGB_BLACK,
RGB_BLACK,
@@ -73,732 +81,578 @@ static const rgb_t TMS9928A_palette[16] =
RGB_WHITE
};
-/*
-** Forward declarations of internal functions.
-*/
-static void draw_mode0 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_mode1 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_mode2 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_mode12 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_mode3 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_mode23 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_modebogus (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void draw_sprites (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect);
-static void change_register (running_machine &machine, int reg, UINT8 data);
-
-static void (*const ModeHandlers[])(device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) = {
- draw_mode0, draw_mode1, draw_mode2, draw_mode12,
- draw_mode3, draw_modebogus, draw_mode23,
- draw_modebogus
-};
-
-#define IMAGE_SIZE (256*192) /* size of rendered image */
-
-#define LEFT_BORDER 15 /* a bit less for 9918a??? */
-#define RIGHT_BORDER 15 /* 13 for 9929a */
-#define TOP_BORDER_60HZ 27
-#define BOTTOM_BORDER_60HZ 24
-#define TOP_BORDER_50HZ 51 /* unknown (102 for top+bottom?) */
-#define BOTTOM_BORDER_50HZ 51 /* unknown (102 for top+bottom?) */
-#define TOP_BORDER tms.top_border
-#define BOTTOM_BORDER tms.bottom_border
-
-#define TMS_50HZ ((tms.model == TMS9929) || (tms.model == TMS9929A))
-#define TMS_REVA ((tms.model == TMS99x8A) || (tms.model == TMS9929A))
-#define TMS_MODE ( (TMS_REVA ? (tms.Regs[0] & 2) : 0) | \
- ((tms.Regs[1] & 0x10)>>4) | ((tms.Regs[1] & 8)>>1))
-
-typedef struct {
- /* TMS9928A internal settings */
- UINT8 ReadAhead,Regs[8],StatusReg,FifthSprite,latch,INT;
- INT32 Addr;
- int colour,pattern,nametbl,spriteattribute,spritepattern;
- int colourmask,patternmask;
- void (*INTCallback)(running_machine &, int);
- /* memory */
- UINT8 *vMem, *dBackMem;
- bitmap_t *tmpbmp;
- int vramsize, model;
- /* emulation settings */
- int LimitSprites; /* max 4 sprites on a row, like original TMS9918A */
- int top_border, bottom_border;
- rectangle visarea;
-} TMS9928A;
-
-static TMS9928A tms;
/*
** initialize the palette
*/
-static PALETTE_INIT( tms9928a )
+PALETTE_INIT( tms9928a )
{
- palette_set_colors(machine, 0, TMS9928A_palette, TMS9928A_PALETTE_SIZE);
+ palette_set_colors(machine, 0, tms9928a_palette, TMS9928A_PALETTE_SIZE);
}
-/*
-** The init, reset and shutdown functions
-*/
-void TMS9928A_reset () {
- int i;
-
- for (i=0;i<8;i++) tms.Regs[i] = 0;
- tms.StatusReg = 0; tms.FifthSprite = 0;
- tms.nametbl = tms.pattern = tms.colour = 0;
- tms.spritepattern = tms.spriteattribute = 0;
- tms.colourmask = tms.patternmask = 0;
- tms.Addr = tms.ReadAhead = tms.INT = 0;
- tms.latch = 0;
+tms9928a_device::tms9928a_device( const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_50hz, bool is_reva )
+ : device_t( mconfig, type, name, tag, owner, clock )
+{
+ m_50hz = is_50hz;
+ m_reva = is_reva;
}
-static void TMS9928A_start (running_machine &machine, const TMS9928a_interface *intf)
+
+tms9928a_device::tms9928a_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock )
+ : device_t( mconfig, TMS9928A, "tms9928a", tag, owner, clock )
{
- assert_always(((intf->vram == 0x1000) || (intf->vram == 0x2000) || (intf->vram == 0x4000)), "4, 8 or 16 kB vram please");
-
- tms.model = intf->model;
-
- tms.top_border = TMS_50HZ ? TOP_BORDER_50HZ : TOP_BORDER_60HZ;
- tms.bottom_border = TMS_50HZ ? BOTTOM_BORDER_50HZ : BOTTOM_BORDER_60HZ;
-
- tms.INTCallback = intf->int_callback;
-
- /* determine the visible area */
- tms.visarea.min_x = LEFT_BORDER - MIN(intf->borderx, LEFT_BORDER);
- tms.visarea.max_x = LEFT_BORDER + 32*8 - 1 + MIN(intf->borderx, RIGHT_BORDER);
- tms.visarea.min_y = tms.top_border - MIN(intf->bordery, tms.top_border);
- tms.visarea.max_y = tms.top_border + 24*8 - 1 + MIN(intf->bordery, tms.bottom_border);
-
- /* configure the screen if we weren't overridden */
- if (machine.primary_screen->width() == LEFT_BORDER+32*8+RIGHT_BORDER &&
- machine.primary_screen->height() == TOP_BORDER_60HZ+24*8+BOTTOM_BORDER_60HZ)
- machine.primary_screen->configure(LEFT_BORDER + 32*8 + RIGHT_BORDER, tms.top_border + 24*8 + tms.bottom_border, tms.visarea, machine.primary_screen->frame_period().attoseconds);
-
- /* Video RAM */
- tms.vramsize = intf->vram;
- tms.vMem = auto_alloc_array_clear(machine, UINT8, intf->vram);
-
- /* Sprite back buffer */
- tms.dBackMem = auto_alloc_array(machine, UINT8, IMAGE_SIZE);
-
- /* back bitmap */
- tms.tmpbmp = auto_bitmap_alloc (machine, 256, 192, machine.primary_screen->format());
-
- TMS9928A_reset ();
- tms.LimitSprites = 1;
-
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[0]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[1]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[2]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[3]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[4]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[5]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[6]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Regs[7]);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.StatusReg);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.FifthSprite);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.ReadAhead);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.latch);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.Addr);
- state_save_register_item(machine, "tms9928a", NULL, 0, tms.INT);
- state_save_register_item_pointer(machine, "tms9928a", NULL, 0, tms.vMem, intf->vram);
+ m_50hz = false;
+ m_reva = true;
}
-void TMS9928A_post_load (running_machine &machine) {
- int i;
+READ8_MEMBER( tms9928a_device::vram_read )
+{
+ UINT8 data = m_ReadAhead;
- /* all registers need to be re-written, so tables are recalculated */
- for (i=0;i<8;i++)
- change_register (machine, i, tms.Regs[i]);
+ m_ReadAhead = m_vMem[ m_Addr ];
+ m_Addr = (m_Addr + 1) & (m_vram_size - 1);
+ m_latch = 0;
- /* make sure the interrupt request is set properly */
- if (tms.INTCallback) tms.INTCallback (machine, tms.INT);
+ return data;
}
-/*
-** The I/O functions.
-*/
-READ8_HANDLER (TMS9928A_vram_r) {
- UINT8 ret = tms.ReadAhead;
- tms.ReadAhead = tms.vMem[tms.Addr];
- tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
- tms.latch = 0;
- return ret;
+WRITE8_MEMBER( tms9928a_device::vram_write )
+{
+ m_vMem[ m_Addr ] = data;
+ m_Addr = (m_Addr + 1) & (m_vram_size - 1);
+ m_ReadAhead = data;
+ m_latch = 0;
}
-WRITE8_HANDLER (TMS9928A_vram_w) {
- tms.vMem[tms.Addr] = data;
- tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
- tms.ReadAhead = data;
- tms.latch = 0;
+
+READ8_MEMBER( tms9928a_device::register_read )
+{
+ UINT8 data = m_StatusReg;
+
+ m_StatusReg = m_FifthSprite;
+ if (m_INT) {
+ m_INT = 0;
+ if ( !m_irq_changed.isnull() )
+ m_irq_changed( m_INT );
+ }
+ m_latch = 0;
+
+ return data;
}
-READ8_HANDLER (TMS9928A_register_r) {
- UINT8 ret = tms.StatusReg;
- tms.StatusReg = tms.FifthSprite;
- if (tms.INT) {
- tms.INT = 0;
- if (tms.INTCallback) tms.INTCallback (space->machine(), tms.INT);
- }
- tms.latch = 0;
- return ret;
+
+void tms9928a_device::change_register(UINT8 reg, UINT8 val) {
+ static const UINT8 Mask[8] =
+ { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
+ static const char *const modes[] =
+ {
+ "Mode 0 (GRAPHIC 1)", "Mode 1 (TEXT 1)", "Mode 2 (GRAPHIC 2)",
+ "Mode 1+2 (TEXT 1 variation)", "Mode 3 (MULTICOLOR)",
+ "Mode 1+3 (BOGUS)", "Mode 2+3 (MULTICOLOR variation)",
+ "Mode 1+2+3 (BOGUS)"
+ };
+ UINT8 b;
+
+ val &= Mask[reg];
+ m_Regs[reg] = val;
+
+ logerror("TMS9928A('%s'): Reg %d = %02xh\n", tag(), reg, (int)val);
+
+ switch (reg)
+ {
+ case 0:
+ /* re-calculate masks and pattern generator & colour */
+ if (val & 2)
+ {
+ m_colour = ((m_Regs[3] & 0x80) * 64) & (m_vram_size - 1);
+ m_colourmask = (m_Regs[3] & 0x7f) * 8 | 7;
+ m_pattern = ((m_Regs[4] & 4) * 2048) & (m_vram_size - 1);
+ m_patternmask = ( (m_Regs[4] & 3) << 8 ) | (m_colourmask & 0xff);
+ }
+ else
+ {
+ m_colour = (m_Regs[3] * 64) & (m_vram_size - 1);
+ m_pattern = (m_Regs[4] * 2048) & (m_vram_size - 1);
+ }
+ m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1));
+ logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]);
+ break;
+ case 1:
+ /* check for changes in the INT line */
+ b = (val & 0x20) && (m_StatusReg & 0x80) ;
+ if (b != m_INT)
+ {
+ m_INT = b;
+ if ( !m_irq_changed.isnull() )
+ m_irq_changed( m_INT );
+ }
+ m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1));
+ logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]);
+ break;
+ case 2:
+ m_nametbl = (val * 1024) & (m_vram_size - 1);
+ break;
+ case 3:
+ if (m_Regs[0] & 2)
+ {
+ m_colour = ((val & 0x80) * 64) & (m_vram_size - 1);
+ m_colourmask = ( (val & 0x7f) * 8 ) | 7;
+ }
+ else
+ {
+ m_colour = (val * 64) & (m_vram_size - 1);
+ }
+ m_patternmask = ( (m_Regs[4] & 3) * 256 ) | (m_colourmask & 255);
+ break;
+ case 4:
+ if (m_Regs[0] & 2)
+ {
+ m_pattern = ((val & 4) * 2048) & (m_vram_size - 1);
+ m_patternmask = ( (val & 3) * 256 ) | 255;
+ }
+ else
+ {
+ m_pattern = (val * 2048) & (m_vram_size - 1);
+ }
+ break;
+ case 5:
+ m_spriteattribute = (val * 128) & (m_vram_size - 1);
+ break;
+ case 6:
+ m_spritepattern = (val * 2048) & (m_vram_size - 1);
+ break;
+ case 7:
+ /* The backdrop is updated at TMS9928A_refresh() */
+ break;
+ }
}
-WRITE8_HANDLER (TMS9928A_register_w) {
- int reg;
- if (tms.latch) {
+WRITE8_MEMBER( tms9928a_device::register_write )
+{
+ if (m_latch) {
/* set high part of read/write address */
- tms.Addr = ((UINT16)data << 8 | (tms.Addr & 0xff)) & (tms.vramsize - 1);
+ m_Addr = ((data << 8) | (m_Addr & 0xff)) & (m_vram_size - 1);
if (data & 0x80) {
/* register write */
- reg = data & 7;
- change_register (space->machine(), reg, tms.Addr & 0xff);
+ change_register (data & 7, m_Addr & 0xff);
} else {
if ( !(data & 0x40) ) {
/* read ahead */
- TMS9928A_vram_r (space,0);
+ vram_read(space, 0);
}
}
- tms.latch = 0;
+ m_latch = 0;
} else {
/* set low part of read/write address */
- tms.Addr = ((tms.Addr & 0xff00) | data) & (tms.vramsize - 1);
- tms.latch = 1;
+ m_Addr = ((m_Addr & 0xff00) | data) & (m_vram_size - 1);
+ m_latch = 1;
}
}
-static void change_register (running_machine &machine, int reg, UINT8 val) {
- static const UINT8 Mask[8] =
- { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
- static const char *const modes[] = {
- "Mode 0 (GRAPHIC 1)", "Mode 1 (TEXT 1)", "Mode 2 (GRAPHIC 2)",
- "Mode 1+2 (TEXT 1 variation)", "Mode 3 (MULTICOLOR)",
- "Mode 1+3 (BOGUS)", "Mode 2+3 (MULTICOLOR variation)",
- "Mode 1+2+3 (BOGUS)"
- };
- UINT8 b;
-
- val &= Mask[reg];
- tms.Regs[reg] = val;
-
- logerror("TMS9928A: Reg %d = %02xh\n", reg, (int)val);
- switch (reg) {
- case 0:
- /* re-calculate masks and pattern generator & colour */
- if (val & 2) {
- tms.colour = ((tms.Regs[3] & 0x80) * 64) & (tms.vramsize - 1);
- tms.colourmask = (tms.Regs[3] & 0x7f) * 8 | 7;
- tms.pattern = ((tms.Regs[4] & 4) * 2048) & (tms.vramsize - 1);
- tms.patternmask = (tms.Regs[4] & 3) * 256 |
- (tms.colourmask & 255);
- } else {
- tms.colour = (tms.Regs[3] * 64) & (tms.vramsize - 1);
- tms.pattern = (tms.Regs[4] * 2048) & (tms.vramsize - 1);
- }
- logerror("TMS9928A: %s\n", modes[TMS_MODE]);
- break;
- case 1:
- /* check for changes in the INT line */
- b = (val & 0x20) && (tms.StatusReg & 0x80) ;
- if (b != tms.INT) {
- tms.INT = b;
- if (tms.INTCallback) tms.INTCallback (machine, tms.INT);
- }
- logerror("TMS9928A: %s\n", modes[TMS_MODE]);
- break;
- case 2:
- tms.nametbl = (val * 1024) & (tms.vramsize - 1);
- break;
- case 3:
- if (tms.Regs[0] & 2) {
- tms.colour = ((val & 0x80) * 64) & (tms.vramsize - 1);
- tms.colourmask = (val & 0x7f) * 8 | 7;
- } else {
- tms.colour = (val * 64) & (tms.vramsize - 1);
- }
- tms.patternmask = (tms.Regs[4] & 3) * 256 | (tms.colourmask & 255);
- break;
- case 4:
- if (tms.Regs[0] & 2) {
- tms.pattern = ((val & 4) * 2048) & (tms.vramsize - 1);
- tms.patternmask = (val & 3) * 256 | 255;
- } else {
- tms.pattern = (val * 2048) & (tms.vramsize - 1);
- }
- break;
- case 5:
- tms.spriteattribute = (val * 128) & (tms.vramsize - 1);
- break;
- case 6:
- tms.spritepattern = (val * 2048) & (tms.vramsize - 1);
- break;
- case 7:
- /* The backdrop is updated at TMS9928A_refresh() */
- break;
- }
-}
-/*
-** Interface functions
-*/
+void tms9928a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int vpos = m_screen->vpos();
+ UINT16 BackColour = m_Regs[7] & 15;
+ UINT16 *p = BITMAP_ADDR16( m_tmpbmp, vpos, 0 );
-void TMS9928A_set_spriteslimit (int limit) {
- tms.LimitSprites = limit;
-}
+ if (!BackColour)
+ BackColour=1;
-/*
-** Updates the screen (the dMem memory area).
-*/
-SCREEN_UPDATE( tms9928a )
-{
- INT32 BackColour = tms.Regs[7] & 15;
- rgb_t oldcolor = palette_get_color(screen->machine(), 0);
+ if ( vpos == 0 )
+ {
+ rgb_t oldcolor = palette_get_color(machine(), 0);
- if (!BackColour) BackColour=1;
- /* note we preserve the alpha here; this is so that it can be controlled independently */
- /* see cliffhgr.c for an example */
- palette_set_color(screen->machine(), 0, (TMS9928A_palette[BackColour] & MAKE_ARGB(0,255,255,255)) | (oldcolor & MAKE_ARGB(255,0,0,0)));
+ /* note we preserve the alpha here; this is so that it can be controlled independently */
+ /* see cliffhgr.c for an example */
+ palette_set_color(machine(), 0, (tms9928a_palette[BackColour] & MAKE_ARGB(0,255,255,255)) | (oldcolor & MAKE_ARGB(255,0,0,0)));
+ }
- if (! (tms.Regs[1] & 0x40))
- bitmap_fill(bitmap, cliprect, screen->machine().pens[BackColour]);
- else
+ int y = vpos - m_top_border;
+
+ if ( y < 0 || y >= 192 || ! (m_Regs[1] & 0x40) )
{
- (*ModeHandlers[TMS_MODE])(screen, tms.tmpbmp, cliprect);
+ /* Draw backdrop colour */
+ for ( int i = 0; i < TMS9928A_TOTAL_HORZ; i++ )
+ p[i] = BackColour;
- copybitmap(bitmap, tms.tmpbmp, 0, 0, LEFT_BORDER, TOP_BORDER, cliprect);
+ /* Check for end of active display */
+ if ( y == 192 )
{
- rectangle rt;
-
- /* set borders */
- rt.min_x = 0; rt.max_x = LEFT_BORDER+256+RIGHT_BORDER-1;
- rt.min_y = 0; rt.max_y = TOP_BORDER-1;
- bitmap_fill (bitmap, &rt, BackColour);
- rt.min_y = TOP_BORDER+192; rt.max_y = TOP_BORDER+192+BOTTOM_BORDER-1;
- bitmap_fill (bitmap, &rt, BackColour);
-
- rt.min_y = TOP_BORDER; rt.max_y = TOP_BORDER+192-1;
- rt.min_x = 0; rt.max_x = LEFT_BORDER-1;
- bitmap_fill (bitmap, &rt, BackColour);
- rt.min_x = LEFT_BORDER+256; rt.max_x = LEFT_BORDER+256+RIGHT_BORDER-1;
- bitmap_fill (bitmap, &rt, BackColour);
+ UINT8 b;
+
+ m_StatusReg |= 0x80;
+ b = (m_Regs[1] & 0x20) != 0;
+ if (b != m_INT) {
+ m_INT = b;
+ if ( !m_irq_changed.isnull() )
+ m_irq_changed( m_INT );
+ }
}
- draw_sprites(screen, bitmap, cliprect);
}
+ else
+ {
+ /* Draw regular line */
- return 0;
-}
-
-int TMS9928A_interrupt(running_machine &machine) {
- int b;
-
- /* when skipping frames, calculate sprite collision */
- if (machine.video().skip_this_frame()) {
- draw_sprites (machine.primary_screen, NULL, NULL);
- }
+ /* Left border */
+ for ( int i = 0; i < TMS9928A_HORZ_DISPLAY_START; i++ )
+ p[i] = BackColour;
- tms.StatusReg |= 0x80;
- b = (tms.Regs[1] & 0x20) != 0;
- if (b != tms.INT) {
- tms.INT = b;
- if (tms.INTCallback) tms.INTCallback (machine, tms.INT);
- }
+ /* Active display */
- return b;
-}
+ switch( m_mode )
+ {
+ case 0: /* MODE 0 */
+ // if (vpos==100 ) popmessage("TMS9928A MODE 0");
+ {
+ UINT16 addr = m_nametbl + ( ( y & 0xF8 ) << 2 );
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
+ {
+ UINT8 charcode = m_vMem[ addr ];
+ UINT8 pattern = m_vMem[ m_pattern + ( charcode << 3 ) + ( y & 7 ) ];
+ UINT8 colour = m_vMem[ m_colour + ( charcode >> 3 ) ];
+ UINT16 fg = colour >> 4;
+ UINT16 bg = colour & 15;
+
+ for ( int i = 0; i < 8; pattern <<= 1, i++ )
+ p[x+i] = ( pattern & 0x80 ) ? fg : bg;
+ }
+ }
+ break;
+
+ case 1: /* MODE 1 */
+ //if (vpos==100 ) popmessage("TMS9928A MODE 1");
+ {
+ UINT16 addr = m_nametbl + ( ( y >> 3 ) * 40 );
+ UINT16 fg = m_Regs[7] >> 4;
+ UINT16 bg = m_Regs[7] & 15;
+
+ /* Extra 8 pixels left border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 8; x++ )
+ p[x] = bg;
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 8; x < TMS9928A_HORZ_DISPLAY_START + 248; x+= 6, addr++ )
+ {
+ UINT16 charcode = m_vMem[ addr ];
+ UINT8 pattern = m_vMem[ m_pattern + ( charcode << 3 ) + ( y & 7 ) ];
+
+ for ( int i = 0; i < 6; pattern <<= 1, i++ )
+ p[x+i] = ( pattern & 0x80 ) ? fg : bg;
+ }
+
+ /* Extra 8 pixels right border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 248; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
+ p[x] = bg;
+ }
+ break;
+
+ case 2: /* MODE 2 */
+ //if (vpos==100 ) popmessage("TMS9928A MODE 2");
+ {
+ UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 );
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
+ {
+ UINT16 charcode = m_vMem[ addr ] + ( ( y >> 6 ) << 8 );
+ UINT8 pattern = m_vMem[ m_pattern + ( ( charcode & m_patternmask ) << 3 ) + ( y & 7 ) ];
+ UINT8 colour = m_vMem[ m_colour + ( ( charcode & m_colourmask ) << 3 ) + ( y & 7 ) ];
+ UINT16 fg = colour >> 4;
+ UINT16 bg = colour & 15;
+
+ for ( int i = 0; i < 8; pattern <<= 1, i++ )
+ p[x+i] = ( pattern & 0x80 ) ? fg : bg;
+ }
+ }
+ break;
+
+ case 3: /* MODE 1+2 */
+ //if (vpos==100) popmessage("TMS9928A MODE1+2");
+ {
+ UINT16 addr = m_nametbl + ( ( y >> 3 ) * 40 );
+ UINT16 fg = m_Regs[7] >> 4;
+ UINT16 bg = m_Regs[7] & 15;
+
+ /* Extra 8 pixels left border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 8; x++ )
+ p[x] = bg;
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 8; x < TMS9928A_HORZ_DISPLAY_START + 248; x+= 6, addr++ )
+ {
+ UINT16 charcode = ( m_vMem[ addr ] + ( ( y >> 6 ) << 8 ) ) & m_patternmask;
+ UINT8 pattern = m_vMem[ m_pattern + ( charcode << 3 ) + ( y & 7 ) ];
+
+ for ( int i = 0; i < 6; pattern <<= 1, i++ )
+ p[x+i] = ( pattern & 0x80 ) ? fg : bg;
+ }
+
+ /* Extra 8 pixels right border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 248; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
+ p[x] = bg;
+ }
+ break;
+
+ case 4: /* MODE 3 */
+ //if (vpos==100 ) popmessage("TMS9928A MODE 3");
+ {
+ UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 );
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
+ {
+ UINT8 charcode = m_vMem[ addr ];
+ UINT8 colour = m_vMem[ m_pattern + ( charcode << 3 ) + ( ( y >> 2 ) & 7 ) ];
+ UINT16 fg = colour >> 4;
+ UINT16 bg = colour & 15;
+
+ p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
+ p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
+ }
+ }
+ break;
+
+ case 5: case 7: /* MODE bogus */
+ //if (vpos==100 ) popmessage("TMS9928A MODE bogus");
+ {
+ UINT16 fg = m_Regs[7] >> 4;
+ UINT16 bg = m_Regs[7] & 15;
+
+ /* Extra 8 pixels left border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 8; x++ )
+ p[x] = bg;
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 8; x < TMS9928A_HORZ_DISPLAY_START + 248; x+= 6 )
+ {
+ p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
+ p[x+4] = p[x+5] = bg;
+ }
+
+ /* Extra 8 pixels right border */
+ for ( int x = TMS9928A_HORZ_DISPLAY_START + 248; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ )
+ p[x] = bg;
+ }
+ break;
+
+ case 6: /* MODE 2+3 */
+ //if (vpos==100 ) popmessage("TMS9928A MODE 2+3");
+ {
+ UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 );
+
+ for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ )
+ {
+ UINT8 charcode = m_vMem[ addr ];
+ UINT8 colour = m_vMem[ m_pattern + ( ( ( charcode + ( ( y >> 2 ) & 7 ) + ( ( y >> 6 ) << 8 ) ) & m_patternmask ) << 3 ) ];
+ UINT16 fg = colour >> 4;
+ UINT16 bg = colour & 15;
+
+ p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg;
+ p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg;
+ }
+ }
+ break;
+ }
-static void draw_mode1 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int pattern,x,y,yy,xx,name,charcode;
- UINT8 fg,bg,*patternptr;
- rectangle rt;
- const pen_t *pens;
-
- pens = screen->machine().pens;
- fg = pens[tms.Regs[7] / 16];
- bg = pens[tms.Regs[7] & 15];
-
- /* colours at sides must be reset */
- rt.min_y = 0; rt.max_y = 191;
- rt.min_x = 0; rt.max_x = 7;
- bitmap_fill (bitmap, &rt, bg);
- rt.min_y = 0; rt.max_y = 191;
- rt.min_x = 248; rt.max_x = 255;
- bitmap_fill (bitmap, &rt, bg);
-
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<40;x++) {
- charcode = tms.vMem[tms.nametbl+name];
- name++;
- patternptr = tms.vMem + tms.pattern + (charcode*8);
- for (yy=0;yy<8;yy++) {
- pattern = *patternptr++;
- for (xx=0;xx<6;xx++) {
- *BITMAP_ADDR16(bitmap, y*8+yy, 8+x*6+xx) = (pattern & 0x80) ? fg : bg;
- pattern *= 2;
- }
- }
- }
- }
-}
+ /* Draw sprites */
+ if ( ( m_Regs[1] & 0x50 ) != 0x40 )
+ {
+ /* sprites are disabled */
+ m_FifthSprite = 31;
+ }
+ else
+ {
+ UINT8 sprite_size = ( m_Regs[1] & 0x02 ) ? 16 : 8;
+ UINT8 sprite_mag = m_Regs[1] & 0x01;
+ UINT8 sprite_height = sprite_size * ( sprite_mag + 1 );
+ UINT8 spr_drawn[32+256+32] = { 0 };
+ UINT8 num_sprites = 0;
+
+ for ( UINT16 sprattr = 0; sprattr < 128; sprattr += 4 )
+ {
+ int spr_y = m_vMem[ m_spriteattribute + sprattr + 0 ];
+
+ /* Stop processing sprites */
+ if ( spr_y == 208 )
+ break;
+
+ if ( spr_y > 0xE0 )
+ spr_y -= 256;
+
+ /* vert pos 255 is displayed on the first line of the screen */
+ spr_y++;
+
+ /* is sprite enabled on this line? */
+ if ( spr_y <= y && y < spr_y + sprite_height )
+ {
+ int spr_x = m_vMem[ m_spriteattribute + sprattr + 1 ];
+ UINT8 sprcode = m_vMem[ m_spriteattribute + sprattr + 2 ];
+ UINT8 sprcol = m_vMem[ m_spriteattribute + sprattr + 3 ];
+ UINT16 pataddr = m_spritepattern + ( ( sprite_size == 16 ) ? sprcode & ~0x03 : sprcode ) * 8;
+
+ num_sprites++;
+
+ /* Fifth sprite encountered? */
+ if( num_sprites == 5 )
+ {
+ m_FifthSprite = sprattr / 4;
+
+ if (~m_StatusReg & 0x40)
+ {
+ m_StatusReg |= m_FifthSprite;
+ if (~m_StatusReg & 0x80) m_StatusReg |= 0x40;
+ }
+ }
+
+ if ( sprite_mag )
+ pataddr += ( ( ( y - spr_y ) & 0x1F ) >> 1 );
+ else
+ pataddr += ( ( y - spr_y ) & 0x0F );
+
+ UINT8 pattern = m_vMem[ pataddr ];
+
+ if ( sprcol & 0x80 )
+ spr_x -= 32;
+
+ sprcol &= 0x0f;
+
+ for ( int s = 0; s < sprite_size; s += 8 )
+ {
+ for ( int i = 0; i < 8; pattern <<= 1, i++ )
+ {
+ int colission_index = spr_x + ( sprite_mag ? i * 2 : i ) + 32;
+
+ for ( int z = 0; z <= sprite_mag; colission_index++, z++ )
+ {
+ /* Check for colission */
+ if ( spr_drawn[ colission_index ] )
+ m_StatusReg |= 0x20;
+ spr_drawn[ colission_index ] |= 0x01;
+
+ /* Check if pixel should be drawn */
+ if ( ( pattern & 0x80 ) && sprcol && num_sprites < 5 )
+ {
+ if ( colission_index >= 32 && colission_index < 32 + 256 )
+ {
+ /* Has another sprite already drawn here? */
+ if ( ! ( spr_drawn[ colission_index ] & 0x02 ) )
+ {
+ spr_drawn[ colission_index ] |= 0x02;
+ p[ TMS9928A_HORZ_DISPLAY_START + colission_index - 32 ] = sprcol;
+ }
+ }
+ }
+ }
+ }
+
+ pattern = m_vMem[ pataddr + 16 ];
+ spr_x += sprite_mag ? 16 : 8;
+ }
+ }
+ }
+ }
-static void draw_mode12 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int pattern,x,y,yy,xx,name,charcode;
- UINT8 fg,bg,*patternptr;
- const pen_t *pens;
- rectangle rt;
-
- pens = screen->machine().pens;
- fg = pens[tms.Regs[7] / 16];
- bg = pens[tms.Regs[7] & 15];
-
- /* colours at sides must be reset */
- rt.min_y = 0; rt.max_y = 191;
- rt.min_x = 0; rt.max_x = 7;
- bitmap_fill (bitmap, &rt, bg);
- rt.min_y = 0; rt.max_y = 191;
- rt.min_x = 248; rt.max_x = 255;
- bitmap_fill (bitmap, &rt, bg);
-
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<40;x++) {
- charcode = (tms.vMem[tms.nametbl+name]+(y/8)*256)&tms.patternmask;
- name++;
- patternptr = tms.vMem + tms.pattern + (charcode*8);
- for (yy=0;yy<8;yy++) {
- pattern = *patternptr++;
- for (xx=0;xx<6;xx++) {
- *BITMAP_ADDR16(bitmap, y*8+yy, 8+x*6+xx) = (pattern & 0x80) ? fg : bg;
- pattern *= 2;
- }
- }
- }
- }
-}
+ /* Right border */
+ for ( int i = TMS9928A_HORZ_DISPLAY_START + 256; i < TMS9928A_TOTAL_HORZ; i++ )
+ p[i] = BackColour;
+ }
-static void draw_mode0 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int pattern,x,y,yy,xx,name,charcode,colour;
- UINT8 fg,bg,*patternptr;
- const pen_t *pens;
-
- pens = screen->machine().pens;
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<32;x++) {
- charcode = tms.vMem[tms.nametbl+name];
- name++;
- patternptr = tms.vMem + tms.pattern + charcode*8;
- colour = tms.vMem[tms.colour+charcode/8];
- fg = pens[colour / 16];
- bg = pens[colour & 15];
- for (yy=0;yy<8;yy++) {
- pattern=*patternptr++;
- for (xx=0;xx<8;xx++) {
- *BITMAP_ADDR16(bitmap, y*8+yy, x*8+xx) = (pattern & 0x80) ? fg : bg;
- pattern *= 2;
- }
- }
- }
- }
+ /* Schedule next callback */
+ m_line_timer->adjust( m_screen->time_until_pos( ( vpos + 1 ) % m_screen->height() , 0 ) );
}
-static void draw_mode2 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int colour,name,x,y,yy,pattern,xx,charcode;
- UINT8 fg,bg;
- const pen_t *pens;
- UINT8 *colourptr,*patternptr;
-
- pens = screen->machine().pens;
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<32;x++) {
- charcode = tms.vMem[tms.nametbl+name]+(y/8)*256;
- name++;
- colour = (charcode&tms.colourmask);
- pattern = (charcode&tms.patternmask);
- patternptr = tms.vMem+tms.pattern+colour*8;
- colourptr = tms.vMem+tms.colour+pattern*8;
- for (yy=0;yy<8;yy++) {
- pattern = *patternptr++;
- colour = *colourptr++;
- fg = pens[colour / 16];
- bg = pens[colour & 15];
- for (xx=0;xx<8;xx++) {
- *BITMAP_ADDR16(bitmap, y*8+yy, x*8+xx) = (pattern & 0x80) ? fg : bg;
- pattern *= 2;
- }
- }
- }
- }
-}
-static void draw_mode3 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int x,y,yy,yyy,name,charcode;
- UINT8 fg,bg,*patternptr;
- const pen_t *pens;
-
- pens = screen->machine().pens;
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<32;x++) {
- charcode = tms.vMem[tms.nametbl+name];
- name++;
- patternptr = tms.vMem+tms.pattern+charcode*8+(y&3)*2;
- for (yy=0;yy<2;yy++) {
- fg = pens[(*patternptr / 16)];
- bg = pens[((*patternptr++) & 15)];
- for (yyy=0;yyy<4;yyy++) {
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+0) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+1) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+2) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+3) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+4) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+5) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+6) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+7) = bg;
- }
- }
- }
- }
+void tms9928a_device::update( bitmap_t *bitmap, const rectangle *cliprect )
+{
+ copybitmap( bitmap, m_tmpbmp, 0, 0, 0, 0, cliprect );
}
-static void draw_mode23 (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- int x,y,yy,yyy,name,charcode;
- UINT8 fg,bg,*patternptr;
- const pen_t *pens;
-
- pens = screen->machine().pens;
- name = 0;
- for (y=0;y<24;y++) {
- for (x=0;x<32;x++) {
- charcode = tms.vMem[tms.nametbl+name];
- name++;
- patternptr = tms.vMem + tms.pattern +
- ((charcode+(y&3)*2+(y/8)*256)&tms.patternmask)*8;
- for (yy=0;yy<2;yy++) {
- fg = pens[(*patternptr / 16)];
- bg = pens[((*patternptr++) & 15)];
- for (yyy=0;yyy<4;yyy++) {
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+0) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+1) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+2) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+3) = fg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+4) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+5) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+6) = bg;
- *BITMAP_ADDR16(bitmap, y*8+yy*4+yyy, x*8+7) = bg;
- }
- }
- }
- }
-}
-static void draw_modebogus (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- UINT8 fg,bg;
- int x,y,n,xx;
- const pen_t *pens;
-
- pens = screen->machine().pens;
- fg = pens[tms.Regs[7] / 16];
- bg = pens[tms.Regs[7] & 15];
-
- for (y=0;y<192;y++) {
- xx=0;
- n=8; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
- for (x=0;x<40;x++) {
- n=4; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = fg;
- n=2; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
- }
- n=8; while (n--) *BITMAP_ADDR16(bitmap, y, xx++) = bg;
- }
-}
+void tms9928a_device::device_config_complete()
+{
+ const tms9928a_interface *intf = reinterpret_cast<const tms9928a_interface *>(static_config());
-/*
-** This function renders the sprites. Sprite collision is calculated in
-** in a back buffer (tms.dBackMem), because sprite collision detection
-** is rather complicated (transparent sprites also cause the sprite
-** collision bit to be set, and ``illegal'' sprites do not count
-** (they're not displayed)).
-**
-** This code should be optimized. One day.
-*/
-static void draw_sprites (device_t *screen, bitmap_t *bitmap, const rectangle *cliprect) {
- UINT8 *attributeptr,*patternptr,c;
- int p,x,y,size,i,j,large,yy,xx,limit[192],
- illegalsprite,illegalspriteline;
- UINT16 line,line2;
- const pen_t *pens;
-
- if ((tms.Regs[1] & 0x50) != 0x40) {
- /* sprites are disabled */
- tms.FifthSprite = 31;
- return;
- }
-
- pens = screen->machine().pens;
- attributeptr = tms.vMem + tms.spriteattribute;
- size = (tms.Regs[1] & 2) ? 16 : 8;
- large = (int)(tms.Regs[1] & 1);
-
- for (x=0;x<192;x++) limit[x] = 4;
- tms.StatusReg &= ~0x20; /* reset collision */
- illegalspriteline = 255;
- illegalsprite = 0;
-
- memset (tms.dBackMem, 0, IMAGE_SIZE);
- for (p=0;p<32;p++) {
- y = *attributeptr++;
- if (y == 208) break;
- if (y > 208) {
- y=-(~y&255);
- } else {
- y++;
- }
- x = *attributeptr++;
- patternptr = tms.vMem + tms.spritepattern +
- ((size == 16) ? *attributeptr & 0xfc : *attributeptr) * 8;
- attributeptr++;
- c = (*attributeptr & 0x0f);
- if (*attributeptr & 0x80) x -= 32;
- attributeptr++;
-
- if (!large) {
- /* draw sprite (not enlarged) */
- for (yy=y;yy<(y+size);yy++) {
- if ( (yy < 0) || (yy > 191) ) continue;
- if (limit[yy] == 0) {
- /* illegal sprite line */
- if (yy < illegalspriteline) {
- illegalspriteline = yy;
- illegalsprite = p;
- } else if (illegalspriteline == yy) {
- if (illegalsprite > p) {
- illegalsprite = p;
- }
- }
- if (tms.LimitSprites) continue;
- } else limit[yy]--;
- line = 256*patternptr[yy-y] + patternptr[yy-y+16];
- for (xx=x;xx<(x+size);xx++) {
- if (line & 0x8000) {
- if ((xx >= 0) && (xx < 256)) {
- if (tms.dBackMem[yy*256+xx]) {
- tms.StatusReg |= 0x20;
- } else {
- tms.dBackMem[yy*256+xx] = 0x01;
- }
- if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
- {
- tms.dBackMem[yy*256+xx] |= 0x02;
- if (bitmap)
- *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx) = pens[c];
- }
- }
- }
- line *= 2;
- }
- }
- } else {
- /* draw enlarged sprite */
- for (i=0;i<size;i++) {
- yy=y+i*2;
- line2 = 256*patternptr[i] + patternptr[i+16];
- for (j=0;j<2;j++) {
- if ( (yy >= 0) && (yy <= 191) ) {
- if (limit[yy] == 0) {
- /* illegal sprite line */
- if (yy < illegalspriteline) {
- illegalspriteline = yy;
- illegalsprite = p;
- } else if (illegalspriteline == yy) {
- if (illegalsprite > p) {
- illegalsprite = p;
- }
- }
- if (tms.LimitSprites) continue;
- } else limit[yy]--;
- line = line2;
- for (xx=x;xx<(x+size*2);xx+=2) {
- if (line & 0x8000) {
- if ((xx >=0) && (xx < 256)) {
- if (tms.dBackMem[yy*256+xx]) {
- tms.StatusReg |= 0x20;
- } else {
- tms.dBackMem[yy*256+xx] = 0x01;
- }
- if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
- {
- tms.dBackMem[yy*256+xx] |= 0x02;
- if (bitmap)
- *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx) = pens[c];
- }
- }
- if (((xx+1) >=0) && ((xx+1) < 256)) {
- if (tms.dBackMem[yy*256+xx+1]) {
- tms.StatusReg |= 0x20;
- } else {
- tms.dBackMem[yy*256+xx+1] = 0x01;
- }
- if (c && ! (tms.dBackMem[yy*256+xx+1] & 0x02))
- {
- tms.dBackMem[yy*256+xx+1] |= 0x02;
- if (bitmap)
- *BITMAP_ADDR16(bitmap, TOP_BORDER+yy, LEFT_BORDER+xx+1) = pens[c];
- }
- }
- }
- line *= 2;
- }
- }
- yy++;
- }
- }
- }
- }
-
- /* The sprite number is only updated if the overflow bit is clear,
- ** and the overflow bit will only be set if bit 6 and 7 are both clear. */
- if (illegalspriteline == 255) tms.FifthSprite = (p > 31) ? 31 : p;
- else tms.FifthSprite = illegalsprite;
- if (~tms.StatusReg & 0x40) {
- tms.StatusReg |= tms.FifthSprite;
- if (~tms.StatusReg & 0x80) tms.StatusReg |= 0x40;
- }
+ if ( intf != NULL )
+ {
+ *static_cast<tms9928a_interface *>(this) = *intf;
+ }
+ else
+ {
+ m_vram_size = 0;
+ memset(&m_out_int_line, 0, sizeof(m_out_int_line));
+ }
}
-static TMS9928a_interface sIntf;
-
-void TMS9928A_configure (const TMS9928a_interface *intf)
+void tms9928a_device::device_start()
{
- sIntf = *intf;
+ assert_always(((m_vram_size == 0x1000) || (m_vram_size == 0x2000) || (m_vram_size == 0x4000)), "4, 8 or 16 kB vram please");
+
+ m_screen = machine().device<screen_device>( m_screen_tag );
+ assert( m_screen != NULL );
+
+ m_top_border = m_50hz ? TMS9928A_VERT_DISPLAY_START_PAL : TMS9928A_VERT_DISPLAY_START_NTSC;
+
+ m_irq_changed.resolve( m_out_int_line, *this );
+
+ /* Video RAM */
+ m_vMem = auto_alloc_array_clear(machine(), UINT8, m_vram_size);
+
+ /* back bitmap */
+ m_tmpbmp = auto_bitmap_alloc(machine(), TMS9928A_TOTAL_HORZ, TMS9928A_TOTAL_VERT_PAL, m_screen->format());
+
+ m_line_timer = timer_alloc(TIMER_LINE);
+
+ m_LimitSprites = 1;
+
+ save_item(NAME(m_Regs[0]));
+ save_item(NAME(m_Regs[1]));
+ save_item(NAME(m_Regs[2]));
+ save_item(NAME(m_Regs[3]));
+ save_item(NAME(m_Regs[4]));
+ save_item(NAME(m_Regs[5]));
+ save_item(NAME(m_Regs[6]));
+ save_item(NAME(m_Regs[7]));
+ save_item(NAME(m_StatusReg));
+ save_item(NAME(m_FifthSprite));
+ save_item(NAME(m_ReadAhead));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_Addr));
+ save_item(NAME(m_INT));
+ save_pointer(NAME(m_vMem), m_vram_size);
+ save_item(NAME(m_colour));
+ save_item(NAME(m_colourmask));
+ save_item(NAME(m_pattern));
+ save_item(NAME(m_patternmask));
+ save_item(NAME(m_nametbl));
+ save_item(NAME(m_spriteattribute));
+ save_item(NAME(m_spritepattern));
+ save_item(NAME(m_mode));
}
-VIDEO_START( tms9928a )
+void tms9928a_device::device_reset()
{
- assert(sIntf.model != TMS_INVALID_MODEL);
- TMS9928A_start(machine, &sIntf);
+ for ( int i = 0; i < 8; i++ )
+ m_Regs[i] = 0;
+
+ m_StatusReg = 0;
+ m_FifthSprite = 31;
+ m_nametbl = 0;
+ m_pattern = 0;
+ m_colour = 0;
+ m_spritepattern = 0;
+ m_spriteattribute = 0;
+ m_colourmask = 0;
+ m_patternmask = 0;
+ m_Addr = 0;
+ m_ReadAhead = 0;
+ m_INT = 0;
+ m_latch = 0;
+ m_mode = 0;
+
+ m_line_timer->adjust( m_screen->time_until_pos( 0, 0 ) );
}
-
-MACHINE_CONFIG_FRAGMENT( tms9928a )
-
- /* video hardware */
- MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK)
-
- MCFG_SCREEN_ADD("screen", RASTER)
- MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
- MCFG_SCREEN_SIZE(LEFT_BORDER+32*8+RIGHT_BORDER, TOP_BORDER_60HZ+24*8+BOTTOM_BORDER_60HZ)
- MCFG_SCREEN_VISIBLE_AREA(LEFT_BORDER-12, LEFT_BORDER+32*8+12-1, TOP_BORDER_60HZ-9, TOP_BORDER_60HZ+24*8+9-1)
- MCFG_SCREEN_UPDATE(tms9928a)
-
- MCFG_PALETTE_LENGTH(TMS9928A_PALETTE_SIZE)
- MCFG_PALETTE_INIT(tms9928a)
-
- MCFG_VIDEO_START(tms9928a)
-MACHINE_CONFIG_END
-
diff --git a/src/emu/video/tms9928a.h b/src/emu/video/tms9928a.h
index e29b161b410..002cbdbda30 100644
--- a/src/emu/video/tms9928a.h
+++ b/src/emu/video/tms9928a.h
@@ -23,73 +23,193 @@
*/
+#ifndef __TMS9928A_H__
+#define __TMS9928A_H__
+
+#include "emu.h"
+#include "machine//devhelpr.h"
+
+
#define TMS9928A_PALETTE_SIZE 16
-/*
-** The different models
-*/
-typedef enum
+
+/* Some defines used in defining the screens */
+#define TMS9928A_TOTAL_HORZ 342
+#define TMS9928A_TOTAL_VERT_NTSC 262
+#define TMS9928A_TOTAL_VERT_PAL 313
+
+#define TMS9928A_HORZ_DISPLAY_START (2 + 14 + 8 + 13)
+#define TMS9928A_VERT_DISPLAY_START_PAL (13 + 51)
+#define TMS9928A_VERT_DISPLAY_START_NTSC (13 + 27)
+
+
+#define TMS9928A_INTERFACE(name) \
+ const tms9928a_interface (name) =
+
+
+#define MCFG_TMS9928A_ADD(_tag, _variant, _config) \
+ MCFG_DEVICE_ADD(_tag, _variant, XTAL_10_738635MHz / 2 ) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_PALETTE_LENGTH(TMS9928A_PALETTE_SIZE) \
+ MCFG_PALETTE_INIT(tms9928a) \
+
+
+#define MCFG_TMS9928A_SCREEN_ADD_NTSC(_screen_tag) \
+ MCFG_SCREEN_ADD( _screen_tag, RASTER ) \
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) \
+ MCFG_SCREEN_RAW_PARAMS( XTAL_10_738635MHz / 2, TMS9928A_TOTAL_HORZ, TMS9928A_HORZ_DISPLAY_START-12, TMS9928A_HORZ_DISPLAY_START + 256 + 12, \
+ TMS9928A_TOTAL_VERT_NTSC, TMS9928A_VERT_DISPLAY_START_NTSC - 12, TMS9928A_VERT_DISPLAY_START_NTSC + 192 + 12 )
+
+
+#define MCFG_TMS9928A_SCREEN_ADD_PAL(_screen_tag) \
+ MCFG_SCREEN_ADD(_screen_tag, RASTER ) \
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) \
+ MCFG_SCREEN_RAW_PARAMS( XTAL_10_738635MHz / 2, TMS9928A_TOTAL_HORZ, TMS9928A_HORZ_DISPLAY_START-12, TMS9928A_HORZ_DISPLAY_START + 256 + 12, \
+ TMS9928A_TOTAL_VERT_PAL, TMS9928A_VERT_DISPLAY_START_PAL - 12, TMS9928A_VERT_DISPLAY_START_PAL + 192 + 12 )
+
+
+extern const device_type TMS9918;
+extern const device_type TMS9918A;
+extern const device_type TMS9118;
+extern const device_type TMS9928A;
+extern const device_type TMS9128;
+extern const device_type TMS9929;
+extern const device_type TMS9929A;
+extern const device_type TMS9129;
+
+
+typedef struct _tms9928a_interface tms9928a_interface;
+struct _tms9928a_interface
{
- TMS_INVALID_MODEL,
- TMS99x8,
- TMS9929,
- TMS99x8A,
- TMS9929A
-} tms9928a_model;
+ const char *m_screen_tag;
+ int m_vram_size; /* 4K, 8K, or 16K. This should be replaced by fetching data from an address space? */
+ devcb_write_line m_out_int_line; /* Callback is called whenever the state of the INT output changes */
+};
-/*
-** MachineDriver video declarations for the TMS9928A chip
-*/
-typedef struct TMS9928a_interface
+
+PALETTE_INIT( tms9928a );
+
+
+class tms9928a_device : public device_t,
+ public tms9928a_interface
{
- tms9928a_model model; /* model: tms9929(a) runs at 50Hz instead of 60Hz */
- int vram; /* VRAM size in bytes (4k, 8k or 16k) */
- int borderx, bordery; /* number of border pixels to show in each direction */
- void (*int_callback)(running_machine &, int); /* callback which is called whenever the state
- ** of the INT output of the TMS9918A changes (may be NULL)*/
-} TMS9928a_interface;
+public:
+ // construction/destruction
+ tms9928a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ tms9928a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_50hz = false, bool is_reva = true);
+
+ DECLARE_READ8_MEMBER( vram_read );
+ DECLARE_WRITE8_MEMBER( vram_write );
+ DECLARE_READ8_MEMBER( register_read );
+ DECLARE_WRITE8_MEMBER( register_write );
+
+ /* update the screen */
+ void update( bitmap_t *bitmap, const rectangle *cliprect );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ // device_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_0) ? &m_space_config : NULL; }
+
+private:
+ void change_register(UINT8 reg, UINT8 val);
+
+ static const device_timer_id TIMER_LINE = 0;
+
+ screen_device *m_screen;
+
+ /* TMS9928A internal settings */
+ UINT8 m_ReadAhead;
+ UINT8 m_Regs[8];
+ UINT8 m_StatusReg;
+ UINT8 m_FifthSprite;
+ UINT8 m_latch;
+ UINT8 m_INT;
+ UINT16 m_Addr;
+ UINT16 m_colour;
+ UINT16 m_pattern;
+ UINT16 m_nametbl;
+ UINT16 m_spriteattribute;
+ UINT16 m_spritepattern;
+ int m_colourmask;
+ int m_patternmask;
+ devcb_resolved_write_line m_irq_changed;
+ bool m_50hz;
+ bool m_reva;
+
+ /* memory */
+ const address_space_config m_space_config;
+
+ UINT8 *m_vMem;
+ bitmap_t *m_tmpbmp;
+ emu_timer *m_line_timer;
+ UINT8 m_mode;
+
+ /* emulation settings */
+ int m_LimitSprites; /* max 4 sprites on a row, like original TMS9918A */
+ int m_top_border;
+};
+
+
+class tms9918_device : public tms9928a_device
+{
+public:
+ tms9918_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9918, "tms9918", tag, owner, clock, false, false ) { }
+};
-/*
-** configuration function
-*/
-extern void TMS9928A_configure (const TMS9928a_interface *intf);
-/*
-** reset function
-*/
-extern void TMS9928A_reset (void);
+class tms9918a_device : public tms9928a_device
+{
+public:
+ tms9918a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9918A, "tms9918a", tag, owner, clock, false, true ) { }
+};
-/*
-** The I/O functions
-*/
-extern READ8_HANDLER (TMS9928A_vram_r);
-extern WRITE8_HANDLER (TMS9928A_vram_w);
-extern READ8_HANDLER (TMS9928A_register_r);
-extern WRITE8_HANDLER (TMS9928A_register_w);
-/*
-** Call this function to render the screen.
-*/
-extern VIDEO_START( tms9928a );
-extern SCREEN_UPDATE( tms9928a );
+class tms9118_device : public tms9928a_device
+{
+public:
+ tms9118_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9118, "tms9118", tag, owner, clock, false, false ) { }
+};
-/*
-** This next function must be called 50 (tms9929a) or 60 (tms99x8a) times per second,
-** to generate the necessary interrupts
-*/
-int TMS9928A_interrupt (running_machine &machine);
-/*
-** Set display of illegal sprites on or off
-*/
-void TMS9928A_set_spriteslimit (int);
+class tms9128_device : public tms9928a_device
+{
+public:
+ tms9128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9128, "tms9128", tag, owner, clock, false, false ) { }
+};
-/*
-** After loading a state, call this function
-*/
-void TMS9928A_post_load (running_machine &machine);
-/*
-** MachineDriver video declarations for the TMS9928A chip
-*/
-MACHINE_CONFIG_EXTERN( tms9928a );
+class tms9929_device : public tms9928a_device
+{
+public:
+ tms9929_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9929, "tms9929", tag, owner, clock, false, true ) { }
+};
+
+
+class tms9929a_device : public tms9928a_device
+{
+public:
+ tms9929a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9929A, "tms9929a", tag, owner, clock, true, true ) { }
+};
+
+
+class tms9129_device : public tms9928a_device
+{
+public:
+ tms9129_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : tms9928a_device( mconfig, TMS9129, "tms9129", tag, owner, clock, true, false ) { }
+};
+
+
+#endif