text: /*  Namco System NA1/2 Video Hardware */
  
  /*
  TODO:
  - dynamic screen resolution (changes between emeralda test mode and normal game)
  - non-shadow pixels for sprites flagged to enable shadows have bad colors
  */
  
  #include "driver.h"
  #include "namcona1.h"
  
  #define NAMCONA1_NUM_TILEMAPS 4
  
  /* public variables */
  UINT16 *namcona1_vreg;
  UINT16 *namcona1_scroll;
  UINT16 *namcona1_workram;
  //UINT16 *namcona1_sparevram;
  //UINT16 *namcona1_pixmap;
  
  /* private variables */
  static UINT16 *shaperam;
  static UINT16 *cgram;
  static tilemap *roz_tilemap;
  static int roz_palette;
  static tilemap *bg_tilemap[NAMCONA1_NUM_TILEMAPS];
  static int tilemap_palette_bank[NAMCONA1_NUM_TILEMAPS];
  static int palette_is_dirty;
  
  static void tilemap_get_info(
  	running_machine *machine,
  	tile_data *tileinfo,
  	int tile_index,
  	const UINT16 *tilemap_videoram,
  	int tilemap_color,
  	int use_4bpp_gfx )
  {
  	UINT16 *source;
  	static UINT8 mask_data[8];
  
  	int data = tilemap_videoram[tile_index];
  	int tile = data&0xfff;
  	int gfx;
  
  	if( use_4bpp_gfx )
  	{
  		gfx = 1;
  		tilemap_color *= 0x10;
  		tilemap_color += (data & 0x7000)>>12;
  	}
  	else
  	{
  		gfx = 0;
  	}
  
  	if( data & 0x8000 )
  	{
  		SET_TILE_INFO( gfx,tile,tilemap_color,TILE_FORCE_LAYER0 );
  	}
  	else
  	{
  		SET_TILE_INFO( gfx,tile,tilemap_color,0 );
  		if (ENDIANNESS_NATIVE == ENDIANNESS_BIG)
  			tileinfo->mask_data = (UINT8 *)(shaperam+4*tile);
  		else
  		{
  			source = shaperam+4*tile;
  			mask_data[0] = source[0]>>8;
  			mask_data[1] = source[0]&0xff;
  			mask_data[2] = source[1]>>8;
  			mask_data[3] = source[1]&0xff;
  			mask_data[4] = source[2]>>8;
  			mask_data[5] = source[2]&0xff;
  			mask_data[6] = source[3]>>8;
  			mask_data[7] = source[3]&0xff;
  			tileinfo->mask_data = mask_data;
  		}
  	}
  } /* tilemap_get_info */
  
  static TILE_GET_INFO( tilemap_get_info0 ){ tilemap_get_info(machine,tileinfo,tile_index,0*0x1000+videoram16,tilemap_palette_bank[0],namcona1_vreg[0xbc/2]&1); }
  static TILE_GET_INFO( tilemap_get_info1 ){ tilemap_get_info(machine,tileinfo,tile_index,1*0x1000+videoram16,tilemap_palette_bank[1],namcona1_vreg[0xbc/2]&2); }
  static TILE_GET_INFO( tilemap_get_info2 ){ tilemap_get_info(machine,tileinfo,tile_index,2*0x1000+videoram16,tilemap_palette_bank[2],namcona1_vreg[0xbc/2]&4); }
  static TILE_GET_INFO( tilemap_get_info3 ){ tilemap_get_info(machine,tileinfo,tile_index,3*0x1000+videoram16,tilemap_palette_bank[3],namcona1_vreg[0xbc/2]&8); }
  
  static TILE_GET_INFO( roz_get_info )
  {
  	/* each logical tile is constructed from 4*4 normal tiles */
  	int tilemap_color = roz_palette;
  	int use_4bpp_gfx = namcona1_vreg[0xbc/2]&16; /* ? */
  	int c = tile_index%0x40;
  	int r = tile_index/0x40;
  	int data = videoram16[0x8000/2+(r/4)*0x40+c/4]&0xfbf; /* mask out bit 0x40 - patch for Emeraldia Japan */
  	int tile = (data+(c%4)+(r%4)*0x40)&0xfff;
  	int gfx = use_4bpp_gfx;
  	if( use_4bpp_gfx )
  	{
  		tilemap_color *= 0x10;
  		tilemap_color += (data & 0x7000)>>12;
  	}
  	if( data & 0x8000 )
  	{
  		SET_TILE_INFO( gfx,tile,tilemap_color,TILE_FORCE_LAYER0 );
  	}
  	else
  	{
  		UINT8 *mask_data = (UINT8 *)(shaperam+4*tile);
  
  		if (ENDIANNESS_NATIVE == ENDIANNESS_LITTLE)
  		{
  			UINT16 *source = (UINT16 *)mask_data;
  			static UINT8 conv_data[9];
  			conv_data[0] = source[0]>>8;
  			conv_data[1] = source[0]&0xff;
  			conv_data[2] = source[1]>>8;
  			conv_data[3] = source[1]&0xff;
  			conv_data[4] = source[2]>>8;
  			conv_data[5] = source[2]&0xff;
  			conv_data[6] = source[3]>>8;
  			conv_data[7] = source[3]&0xff;
  			mask_data = conv_data;
  		}
  		SET_TILE_INFO( gfx,tile,tilemap_color,0 );
  		tileinfo->mask_data = mask_data;
  	}
  } /* roz_get_info */
  
  /*************************************************************************/
  
  WRITE16_HANDLER( namcona1_videoram_w )
  {
  	COMBINE_DATA( &videoram16[offset] );
  	if( offset<0x8000/2 )
  	{
  		tilemap_mark_tile_dirty( bg_tilemap[offset/0x1000], offset&0xfff );
  	}
  	else if( offset<0xa000/2 )
  	{
  		tilemap_mark_all_tiles_dirty( roz_tilemap );
  	}
  } /* namcona1_videoram_w */
  
  READ16_HANDLER( namcona1_videoram_r )
  {
  	return videoram16[offset];
  } /* namcona1_videoram_r */
  
  /*************************************************************************/
  
  static void
  UpdatePalette(running_machine *machine, int offset )
  {
  	UINT16 data = paletteram16[offset]; /* -RRRRRGG GGGBBBBB */
  	/**
       * sprites can be configured to use an alternate interpretation of palette ram
       * (used in-game in Emeraldia)
       *
       * RRRGGGBB RRRGGGBB
       */
  	int r = (((data&0x00e0)>>5)+((data&0xe000)>>13)*2)*0xff/(0x7*3);
  	int g = (((data&0x001c)>>2)+((data&0x1c00)>>10)*2)*0xff/(0x7*3);
  	int b = (((data&0x0003)>>0)+((data&0x0300)>>8)*2)*0xff/(0x3*3);
  	palette_set_color_rgb( machine, offset+0x1000, r, g, b);
  
  	palette_set_color_rgb( machine, offset, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data >> 0));
  } /* namcona1_paletteram_w */
  
  READ16_HANDLER( namcona1_paletteram_r )
  {
  	return paletteram16[offset];
  } /* namcona1_paletteram_r */
  
  WRITE16_HANDLER( namcona1_paletteram_w )
  {
  	COMBINE_DATA( &paletteram16[offset] );
  	if( namcona1_vreg[0x8e/2] )
  	{ /* graphics enabled; update palette immediately */
  		UpdatePalette(space->machine, offset );
  	}
  	else
  	{
  		palette_is_dirty = 1;
  	}
  }
  
  /*************************************************************************/
  
  #define XOR(a) BYTE_XOR_BE(a)
  
  static const gfx_layout shape_layout =
  {
  	8,8,
  	0x1000,
  	1,
  	{ 0 },
  	{ 0,1,2,3,4,5,6,7 },
  	{ 8*XOR(0),8*XOR(1),8*XOR(2),8*XOR(3),8*XOR(4),8*XOR(5),8*XOR(6),8*XOR(7) },
  	8*8
  }; /* shape_layout */
  
  static const gfx_layout cg_layout_8bpp =
  {
  	8,8,
  	0x1000,
  	8, /* 8BPP */
  	{ 0,1,2,3,4,5,6,7 },
  	{ 8*XOR(0),8*XOR(1),8*XOR(2),8*XOR(3),8*XOR(4),8*XOR(5),8*XOR(6),8*XOR(7) },
  	{ 64*0,64*1,64*2,64*3,64*4,64*5,64*6,64*7 },
  	64*8
  }; /* cg_layout_8bpp */
  
  static const gfx_layout cg_layout_4bpp =
  {
  	8,8,
  	0x1000,
  	4, /* 4BPP */
  	{ 4,5,6,7 },
  	{ 8*XOR(0),8*XOR(1),8*XOR(2),8*XOR(3),8*XOR(4),8*XOR(5),8*XOR(6),8*XOR(7) },
  	{ 64*0,64*1,64*2,64*3,64*4,64*5,64*6,64*7 },
  	64*8
  }; /* cg_layout_4bpp */
  
  READ16_HANDLER( namcona1_gfxram_r )
  {
  	UINT16 type = namcona1_vreg[0x0c/2];
  	if( type == 0x03 )
  	{
  		if( offset<0x4000 )
  		{
  			return shaperam[offset];
  		}
  	}
  	else if( type == 0x02 )
  	{
  		return cgram[offset];
  	}
  	return 0x0000;
  } /* namcona1_gfxram_r */
  
  WRITE16_HANDLER( namcona1_gfxram_w )
  {
  	UINT16 type = namcona1_vreg[0x0c/2];
  	UINT16 old_word;
  
  	if( type == 0x03 )
  	{
  		if( offset<0x4000 )
  		{
  			old_word = shaperam[offset];
  			COMBINE_DATA( &shaperam[offset] );
  			if( shaperam[offset]!=old_word )
  				gfx_element_mark_dirty(space->machine->gfx[2], offset/4);
  		}
  	}
  	else if( type == 0x02 )
  	{
  		old_word = cgram[offset];
  		COMBINE_DATA( &cgram[offset] );
  		if( cgram[offset]!=old_word )
  		{
  			gfx_element_mark_dirty(space->machine->gfx[0], offset/0x20);
  			gfx_element_mark_dirty(space->machine->gfx[1], offset/0x20);
  		}
  	}
  } /* namcona1_gfxram_w */
  
  static void UpdateGfx(running_machine *machine)
  {
  } /* UpdateGfx */
  
  VIDEO_START( namcona1 )
  {
  	static const tile_get_info_func get_info[4] = { tilemap_get_info0, tilemap_get_info1, tilemap_get_info2, tilemap_get_info3 };
  	int i;
  
  	roz_tilemap = tilemap_create( machine, roz_get_info, tilemap_scan_rows, 8,8,64,64 );
  	roz_palette = -1;
  
  	for( i=0; i<NAMCONA1_NUM_TILEMAPS; i++ )
  	{
  		bg_tilemap[i] = tilemap_create( machine, get_info[i], tilemap_scan_rows, 8,8,64,64 );
  		tilemap_palette_bank[i] = -1;
  	}
  
  	shaperam		     = auto_alloc_array(machine, UINT16, 0x2000*4/2 );
  	cgram			     = auto_alloc_array(machine, UINT16, 0x1000*0x40/2 );
  
  	machine->gfx[0] = gfx_element_alloc( machine, &cg_layout_8bpp, (UINT8 *)cgram, machine->config->total_colors/256, 0 );
  	machine->gfx[1] = gfx_element_alloc( machine, &cg_layout_4bpp, (UINT8 *)cgram, machine->config->total_colors/16, 0 );
  	machine->gfx[2] = gfx_element_alloc( machine, &shape_layout, (UINT8 *)shaperam, machine->config->total_colors/2, 0 );
  
  } /* namcona1_vh_start */
  
  /*************************************************************************/
  
  static void pdraw_tile(running_machine *machine,
  		bitmap_t *dest_bmp,
  		const rectangle *clip,
  		UINT32 code,
  		int color,
  		int sx, int sy,
  		int flipx, int flipy,
  		int priority,
  		int bShadow,
  		int bOpaque,
  		int gfx_region )
  {
  	const gfx_element *gfx = machine->gfx[gfx_region];
  	const gfx_element *mask = machine->gfx[2];
  
  	int pal_base = gfx->color_base + gfx->color_granularity * (color % gfx->total_colors);
  	const UINT8 *source_base = gfx_element_get_data(gfx, (code % gfx->total_elements));
  	const UINT8 *mask_base = gfx_element_get_data(mask, (code % mask->total_elements));
  
  	int sprite_screen_height = ((1<<16)*gfx->height+0x8000)>>16;
  	int sprite_screen_width  = ((1<<16)*gfx->width+0x8000)>>16;
  
  	if (sprite_screen_width && sprite_screen_height)
  	{
  		/* compute sprite increment per screen pixel */
  		int dx = (gfx->width<<16)/sprite_screen_width;
  		int dy = (gfx->height<<16)/sprite_screen_height;
  
  		int ex = sx+sprite_screen_width;
  		int ey = sy+sprite_screen_height;
  
  		int x_index_base;
  		int y_index;
  
  		if( flipx )
  		{
  			x_index_base = (sprite_screen_width-1)*dx;
  			dx = -dx;
  		}
  		else
  		{
  			x_index_base = 0;
  		}
  
  		if( flipy )
  		{
  			y_index = (sprite_screen_height-1)*dy;
  			dy = -dy;
  		}
  		else
  		{
  			y_index = 0;
  		}
  
  		if( clip )
  		{
  			if( sx < clip->min_x)
  			{ /* clip left */
  				int pixels = clip->min_x-sx;
  				sx += pixels;
  				x_index_base += pixels*dx;
  			}
  			if( sy < clip->min_y )
  			{ /* clip top */
  				int pixels = clip->min_y-sy;
  				sy += pixels;
  				y_index += pixels*dy;
  			}
  			/* NS 980211 - fixed incorrect clipping */
  			if( ex > clip->max_x+1 )
  			{ /* clip right */
  				int pixels = ex-clip->max_x-1;
  				ex -= pixels;
  			}
  			if( ey > clip->max_y+1 )
  			{ /* clip bottom */
  				int pixels = ey-clip->max_y-1;
  				ey -= pixels;
  			}
  		}
  
  		if( ex>sx )
  		{ /* skip if inner loop doesn't draw anything */
  			int y;
  
  			for( y=sy; y<ey; y++ )
  			{
  				const UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo;
  				const UINT8 *mask_addr = mask_base + (y_index>>16) * mask->line_modulo;
  				UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0);
  				UINT8 *pri = BITMAP_ADDR8(machine->priority_bitmap, y, 0);
  
  				int x, x_index = x_index_base;
  				for( x=sx; x<ex; x++ )
  				{
  					if( bOpaque )
  					{
  						if (pri[x] <= priority)
  						{
  							int c = source[x_index>>16];
  							dest[x] = pal_base + c;
  						}
  
  						pri[x] = 0xff;
  					}
  					else
  					{
  						/* sprite pixel is opaque */
  						if( mask_addr[x_index>>16] != 0 )
  						{
  							if (pri[x] <= priority)
  							{
  								int c = source[x_index>>16];
  
  								/* render a shadow only if the sprites color is $F (8bpp) or $FF (4bpp) */
  								if( bShadow )
  								{
  									if( (gfx_region == 0 && color == 0x0f) ||
  									    (gfx_region == 1 && color == 0xff) )
  									{
  										pen_t *palette_shadow_table = machine->shadow_table;
  										dest[x] = palette_shadow_table[dest[x]];
  									}
  									else
  									{
  										dest[x] = pal_base + c + 0x1000;
  									}
  								}
  								else
  								{
  									dest[x] = pal_base + c;
  								}
  							}
  							pri[x] = 0xff;
  						}
  					}
  
  					x_index += dx;
  				}
  
  				y_index += dy;
  			}
  		}
  	}
  } /* pdraw_tile */
  
  static void draw_sprites(running_machine *machine, bitmap_t *bitmap, const rectangle *cliprect)
  {
  	int which;
  	const UINT16 *source = spriteram16;
  	UINT16 sprite_control;
  	UINT16 ypos,tile,color,xpos;
  	int priority;
  	int width,height;
  	int flipy,flipx;
  	int row,col;
  	int sx,sy;
  
  	sprite_control = namcona1_vreg[0x22/2];
  	if( sprite_control&1 ) source += 0x400; /* alternate spriteram bank */
  
  	for( which=0; which<0x100; which++ )
  	{ /* max 256 sprites */
  		int bpp4,palbase;
  		ypos	= source[0];	/* FHHH---Y YYYYYYYY    flipy, height, ypos */
  		tile	= source[1];	/* O???TTTT TTTTTTTT    opaque tile */
  		color	= source[2];	/* FSWWOOOO CCCCBPPP    flipx, shadow, width, color offset for 4bpp, color, 4bbp - 8bpp mode, pri*/
  		xpos	= source[3];	/* -------X XXXXXXXX    xpos */
  
  		priority = color&0x7;
  		width = ((color>>12)&0x3)+1;
  		height = ((ypos>>12)&0x7)+1;
  		flipy = ypos&0x8000;
  		flipx = color&0x8000;
  
  		if( color&8 )
  		{
  			palbase = ((color>>4)&0xf) * 0x10 + ((color & 0xf00) >> 8);
  			bpp4 = 1;
  		}
  		else
  		{
  			palbase = (color>>4)&0xf;
  			bpp4 = 0;
  		}
  
  		for( row=0; row<height; row++ )
  		{
  			sy = (ypos&0x1ff)-30+32;
  			if( flipy )
  			{
  				sy += (height-1-row)*8;
  			}
  			else
  			{
  				sy += row*8;
  			}
  			sy = ((sy+8)&0x1ff)-8;
  
  			for( col=0; col<width; col++ )
  			{
  				sx = (xpos&0x1ff)-10;
  				if( flipx )
  				{
  					sx += (width-1-col)*8;
  				}
  				else
  				{
  					sx+=col*8;
  				}
  				sx = ((sx+16)&0x1ff)-8;
  
  				pdraw_tile(machine,
  					bitmap,
  					cliprect,
  					(tile & 0xfff) + row*64+col,
  					palbase,
  					sx,sy,flipx,flipy,
  					priority,
  					color & 0x4000, /* shadow */
  					tile & 0x8000, /* opaque */
  					bpp4 );
  
  			} /* next col */
  		} /* next row */
  		source += 4;
  	}
  } /* draw_sprites */
  
  static void draw_pixel_line( UINT16 *pDest, UINT8 *pPri, UINT16 *pSource, const pen_t *paldata )
  {
  	int x;
  	for( x=0; x<38*8; x+=2 )
  	{
  		UINT16 data = *pSource++;
  		pPri[x+0] = 0xff;
  		pPri[x+1] = 0xff;
  		pDest[x+0] = paldata[data>>8];
  		pDest[x+1] = paldata[data&0xff];
  	} /* next x */
  } /* draw_pixel_line */
  
  static void draw_background(running_machine *machine, bitmap_t *bitmap, const rectangle *cliprect, int which, int primask )
  {
  	/*          scrollx lineselect
       *  tmap0   ffe000  ffe200
       *  tmap1   ffe400  ffe600
       *  tmap2   ffe800  ffea00
       *  tmap3   ffec00  ffee00
       */
  	int xadjust = 0x3a - which*2;
  	const UINT16 *scroll = namcona1_scroll+0x200*which;
  	int line;
  	UINT16 xdata, ydata;
  	int scrollx, scrolly;
  	rectangle clip;
  	const pen_t *paldata;
  	gfx_element *pGfx;
  
  	pGfx = machine->gfx[0];
  	paldata = &machine->pens[pGfx->color_base + pGfx->color_granularity * tilemap_palette_bank[which]];
  
  	/* draw one scanline at a time */
  	clip.min_x = cliprect->min_x;
  	clip.max_x = cliprect->max_x;
  	scrollx = 0;
  	scrolly = 0;
  	for( line=0; line<256; line++ )
  	{
  		clip.min_y = line;
  		clip.max_y = line;
  		xdata = scroll[line];
  		if( xdata )
  		{
  			/* screenwise linescroll */
  			scrollx = xadjust+xdata;
  		}
  		ydata = scroll[line+0x100];
  		if( ydata&0x4000 )
  		{
  			/* line select: dword offset from 0xff000 or tilemap source line */
  			scrolly = (ydata - line)&0x1ff;
  		}
  
  		if (line >= cliprect->min_y && line <= cliprect->max_y)
  		{
  			if( xdata == 0xc001 )
  			{
  				/* This is a simplification, but produces the correct behavior for the only game that uses this
                   * feature, Numan Athletics.
                   */
  				draw_pixel_line(
  					BITMAP_ADDR16(bitmap, line, 0),
  					BITMAP_ADDR8(machine->priority_bitmap, line, 0),
  					videoram16 + ydata + 25,
  					paldata );
  			}
  			else
  			{
  				if(which == NAMCONA1_NUM_TILEMAPS )
  				{
  					int incxx = ((INT16)namcona1_vreg[0xc0/2])<<8;
  					int incxy = ((INT16)namcona1_vreg[0xc2/2])<<8;
  					int incyx = ((INT16)namcona1_vreg[0xc4/2])<<8;
  					int incyy = ((INT16)namcona1_vreg[0xc6/2])<<8;
  					INT16 xoffset = namcona1_vreg[0xc8/2];
  					INT16 yoffset = namcona1_vreg[0xca/2];
  					int dx = 46; /* horizontal adjust */
  					int dy = -8; /* vertical adjust */
  					UINT32 startx = (xoffset<<12)+incxx*dx+incyx*dy;
  					UINT32 starty = (yoffset<<12)+incxy*dx+incyy*dy;
  					tilemap_draw_roz_primask(bitmap, &clip, roz_tilemap,
  						startx, starty, incxx, incxy, incyx, incyy, 0, 0, primask, 0);
  				}
  				else
  				{
  					tilemap_set_scrollx( bg_tilemap[which], 0, scrollx );
  					tilemap_set_scrolly( bg_tilemap[which], 0, scrolly );
  					tilemap_draw_primask( bitmap, &clip, bg_tilemap[which], 0, primask, 0 );
  				}
  			}
  		}
  	}
  } /* draw_background */
  
  VIDEO_UPDATE( namcona1 )
  {
  	int which;
  	int priority;
  
  	/* int flipscreen = namcona1_vreg[0x98/2]; (TBA) */
  
  	if( namcona1_vreg[0x8e/2] )
  	{ /* gfx enabled */
  		if( palette_is_dirty )
  		{
  			/* palette updates are delayed when graphics are disabled */
  			for( which=0; which<0x1000; which++ )
  			{
  				UpdatePalette(screen->machine, which );
  			}
  			palette_is_dirty = 0;
  		}
  		UpdateGfx(screen->machine);
  		for( which=0; which<NAMCONA1_NUM_TILEMAPS; which++ )
  		{
  			int tilemap_color = namcona1_vreg[0xb0/2+(which&3)]&0xf;
  			if( tilemap_color!=tilemap_palette_bank[which] )
  			{
  				tilemap_mark_all_tiles_dirty( bg_tilemap[which] );
  				tilemap_palette_bank[which] = tilemap_color;
  			}
  		} /* next tilemap */
  
  		{ /* ROZ tilemap */
  			int color = namcona1_vreg[0xba/2]&0xf;
  			if( color != roz_palette )
  			{
  				tilemap_mark_all_tiles_dirty( roz_tilemap );
  				roz_palette = color;
  			}
  		}
  
  		bitmap_fill( screen->machine->priority_bitmap,cliprect ,0);
  
  		bitmap_fill( bitmap, cliprect , 0xff); /* background color? */
  
  		for( priority = 0; priority<8; priority++ )
  		{
  			for( which=4; which>=0; which-- )
  			{
  				int pri;
  				if( which==4 )
  				{
  					pri = namcona1_vreg[0xa0/2+5]&0x7;
  				}
  				else
  				{
  					pri = namcona1_vreg[0xa0/2+which]&0x7;
  				}
  				if( pri == priority )
  				{
  					draw_background(screen->machine,bitmap,cliprect,which,priority);
  				}
  			} /* next tilemap */
  		} /* next priority level */
  
  		draw_sprites(screen->machine,bitmap,cliprect);
  	} /* gfx enabled */
  	return 0;
  }
  
  /*
  roz bad in emeraldaj - blit param?
  
  $efff20: sprite control: 0x3a,0x3e,0x3f
              bit 0x01 selects spriteram bank
  
                 0    2    4    6    8    a    c    e
  $efff00:    src0 src1 src2 dst0 dst1 dst2 BANK [src
  $efff10:    src] [dst dst] #BYT BLIT eINT 001f 0001
  $efff20:    003f 003f IACK ---- ---- ---- ---- ----
  ...
  $efff80:    0050 0170 0020 0100 0170 POS? 0000 GFXE
  $efff90:    0000 0001 0002 0003 FLIP ---- ---- ----
  $efffa0:    PRI  PRI  PRI  PRI  ???? PRI  00c0 ----     priority (0..7)
  $efffb0:    CLR  CLR  CLR  CLR  0001 CLR  BPP  ----     color (0..f), bpp flag per layer
  $efffc0:    RZXX RZXY RZYX RZYY RZX0 RZY0 0044 ----     ROZ
  
  
  Emeralda:   0048 0177 0020 0100 0000 00f0 0000 0001     in-game
              0050 0170 0020 0100 0000 00f0 0000 0001     self test
  
  NumanAth:   0050 0170 0020 0100 0170 00d8 0000 0001     in-game
  
  
  */
  