summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/video/seibuspi.cpp
blob: 56906b2b770e3d11cdce5201d24ea6ff45760e6d (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                                      
                                                                               

                      
 

                                           
                                                                               
 
                
                              
                             
                   

























                                                                             
                                                                                                   
 
                                                                                                   



                                                                      
                                                                                   



                                
                           










                                                                                     
                                                                                           





                                        
                                   





















                                                                                                          
                                               



                                                         
                                                       













                                                                                           
                                                     



                                                         
                                                             













                                                                                           
                                                     



                                                         
                                                             








                                                             
 
 
                                                                               
 
                                        
 
                               
         
                                                 
                                                 
                                                 
         

            


                                                     
         
 
                                                      


                                                           

 
                                                
 
                                                             
 
                            

                              
                                                                
                                     
                                    
 
                                                    
                            
 
                                           
                                               

 
 
                                               
 



                              
                                        



                                          

                                               
                                          

                                               
                                          
                                               
 
 
                                                  
 
                                          





                                      

 




                                           
                                                  
 

                                          
 



                                                   
 
 
                                                                               
 



                                                   
 
                       



                                                                                                                          
                                                                                                                                           


                                                                                                                           
 
                                            
 


                                         
                                                 
                                             
                 





                                                                   
 





                                                                            
 


                                         
                                                 







                                                                    
 


                                   
                                                                                          





                                         
                                                 




                                                                    
                 
                        
         
 

                                     
         
                                                                                          





                                          
                                                 
                                                                 
                 


                                                                    
                 
                        


         

                                                   
 
                                                      
 
                       
                                                                                                                                                                    


                                                                                                                          
 
                                                
         
                                                                        


                                                 

                                                                                                                                                                 
                 


         
 
                                                  
 
                       
                                                                                                       



                                                                                                      
                                                                                           

 


                                                                               
                                                                                                                                                                                                            
 

                                   
 



                                 
 
                                                       


                       
                                                       



                       



                   












                                
                                


                          
                                                               


                    
                                                   
                 
                                    
         
                                
         
                                    


                 
                                


                          
                                                                


                    
                                                   
                 
                                    
         
                                
         
                                    

         
                                                              
                                                 

               
                                      
         


                                                            
                                              

                         
                                              
                 
                                                 
                                                                    
                         
                                                  
                                                                               
                                                              
                                                                                                   
                                    
                                                                   
                         
                                    



                 
                                                                                                                     
 
                                               
                                                                      
                                                                
 











                                                                   

                       
                                                            
         
                  












                                                                                                
                  
                                                                  
                                  
                                 
 

                                                                       
 
                                                                 
                                 
                                            
 
                                                           
                                 
                                       
                                                                 
                                 
                                       
                                                            
 





                                                                   
 
                           
                 


                                           
                           
                 



                                             
                                                
                 
                                                         
                         
                                                                                                                                                                                         

                                                                           
                                                                  
                                                                                                                                                                                                       






                                           
                                                                                                                                                      
 



                                            
 

                                                     

                                               
 
                                                              
         
                            

                              
                                                                 

                 



                                                                                
                 
                                                                                                                
                         
                                                                     
                                                       
                                                                                                  
                                    
                                                                    
                         
                               




                 
                                                                                                                  
 
                                                                  
                               
         


                                                                 


            


                                         

         

                                            
                               
                                         
            
                                                                                                                   
 
                                                             
 

                                                                              
                                                                                                                   
 

                                                                                
                                                                     
 
                                
                                                                                                                   
 

                                                                                
                                                                     
 
                                                             
 
                                
                                                                                                                   
 
                                                             
 
                                
                                                                                  
 

                 
 
                                                                                                                      
 
                                            

                                 



                                                             
 

                 
 
 

                                                                               




                                                                                                         
 

                      
                                                

 
                                                        
 




                                                                                   
                                 
 
                                                









                                                                                                         
                                 
 
                                                     









                                                                                                         

                                 
 
                                                    


 
                                  
 




                                
                               





                           

                            
                                                            











                                                  
 


                                                                            
 

                                                                                                  



                                                                                                                                                                           

                                              
                                              


                                              
                                    





















                                                                    
 


                               
                                         





                                                              
                                          





                                

                               
 



                                    
 
                                

                                                                            
 

                                                                                                  
                                                              
 










                                             
                                     
 


                                             



                                          
 


                                                                                              
 
// license:BSD-3-Clause
// copyright-holders:Ville Linde, hap, Nicola Salmoria
/******************************************************************************

    Seibu SPI hardware

    Functions to emulate the video hardware

******************************************************************************/

#include "emu.h"
#include "includes/seibuspi.h"
#include "machine/seibuspi.h"
#include "screen.h"


/**************************************************************************

Tile encryption
---------------

The tile graphics encryption uses the same algorithm in all games. This is
similar to, but simpler than, that used by the SEI252, RISE10 and RISE11
custom chips.

- Take 24 bits of gfx data (used to decrypt 4 pixels at 6 bpp) and perform
  a bit permutation on them (the permutation is the same in all games).
- Take the low 12 bits of the tile code and add a 24-bit number (KEY1) to it.
- Add the two 24-bit numbers resulting from the above steps, but with a
  catch: while performing the sum, some bits generate carry as usual, other
  bits don't, depending on a 24-bit key (KEY2). Note that the carry generated
  by bit 23 (if enabled) wraps around to bit 0.
- XOR the result with a 24-bit number (KEY3).

The decryption is actually programmable; the games write the key to the
custom CRTC on startup!! (writes to 000414)

**************************************************************************/


static uint32_t decrypt_tile(uint32_t val, int tileno, uint32_t key1, uint32_t key2, uint32_t key3)
{
	val = bitswap<24>(val, 18,19,9,5, 10,17,16,20, 21,22,6,11, 15,14,4,23, 0,1,7,8, 13,12,3,2);

	return partial_carry_sum24( val, tileno + key1, key2 ) ^ key3;
}

static void decrypt_text(uint8_t *rom, uint32_t key1, uint32_t key2, uint32_t key3)
{
	int i;
	for(i=0; i<0x10000; i++)
	{
		uint32_t w;

		w = (rom[(i*3) + 0] << 16) | (rom[(i*3) + 1] << 8) | (rom[(i*3) +2]);

		w = decrypt_tile(w, i >> 4, key1, key2, key3);

		rom[(i*3) + 0] = (w >> 16) & 0xff;
		rom[(i*3) + 1] = (w >> 8) & 0xff;
		rom[(i*3) + 2] = w & 0xff;
	}
}

static void decrypt_bg(uint8_t *rom, int size, uint32_t key1, uint32_t key2, uint32_t key3)
{
	int i,j;
	for(j=0; j<size; j+=0xc0000)
	{
		for(i=0; i<0x40000; i++)
		{
			uint32_t w;

			w = (rom[j + (i*3) + 0] << 16) | (rom[j + (i*3) + 1] << 8) | (rom[j + (i*3) + 2]);

			w = decrypt_tile(w, i >> 6, key1, key2, key3);

			rom[j + (i*3) + 0] = (w >> 16) & 0xff;
			rom[j + (i*3) + 1] = (w >> 8) & 0xff;
			rom[j + (i*3) + 2] = w & 0xff;
		}
	}
}

/******************************************************************************************
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 00000000 & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 0000DF5B & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 000078CF & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 00001377 & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 00002538 & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 00004535 & 0000FFFF
cpu #0 (PC=0033B2EB): unmapped program memory dword write to 00000414 = 06DC0000 & FFFF0000
******************************************************************************************/

void seibuspi_state::text_decrypt(uint8_t *rom)
{
	decrypt_text( rom, 0x5a3845, 0x77cf5b, 0x1378df);
}

void seibuspi_state::bg_decrypt(uint8_t *rom, int size)
{
	decrypt_bg( rom, size, 0x5a3845, 0x77cf5b, 0x1378df);
}

/******************************************************************************************
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 00000001 & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 0000DCF8 & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 00007AE2 & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 0000154D & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 00001731 & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 0000466B & 0000FFFF
cpu #0 (PC=002A097D): unmapped program memory dword write to 00000414 = 3EDC0000 & FFFF0000
******************************************************************************************/

void seibuspi_state::rdft2_text_decrypt(uint8_t *rom)
{
	decrypt_text( rom, 0x823146, 0x4de2f8, 0x157adc);
}

void seibuspi_state::rdft2_bg_decrypt(uint8_t *rom, int size)
{
	decrypt_bg( rom, size, 0x823146, 0x4de2f8, 0x157adc);
}

/******************************************************************************************
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 00000001 & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 00006630 & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 0000B685 & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 0000CCFE & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 000032A7 & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 0000547C & 0000FFFF
cpu #0 (PC=002C40F9): unmapped program memory dword write to 00000414 = 3EDC0000 & FFFF0000
******************************************************************************************/

void seibuspi_state::rfjet_text_decrypt(uint8_t *rom)
{
	decrypt_text( rom, 0xaea754, 0xfe8530, 0xccb666);
}

void seibuspi_state::rfjet_bg_decrypt(uint8_t *rom, int size)
{
	decrypt_bg( rom, size, 0xaea754, 0xfe8530, 0xccb666);
}

WRITE16_MEMBER(seibuspi_state::tile_decrypt_key_w)
{
	if (data != 0 && data != 1)
		logerror("Decryption key: %04X\n", data);
}


/*****************************************************************************/

void seibuspi_state::set_layer_offsets()
{
	if (m_rowscroll_enable)
	{
		m_fore_layer_offset = 0x1000 / 4;
		m_midl_layer_offset = 0x2000 / 4;
		m_text_layer_offset = 0x3000 / 4;
	}
	else
	{
		m_fore_layer_offset = 0x1000 / 4 / 2;
		m_midl_layer_offset = 0x2000 / 4 / 2;
		m_text_layer_offset = 0x3000 / 4 / 2;
	}

	m_fore_layer_d13 = m_layer_bank << 2 & 0x2000;
	m_back_layer_d14 = m_rf2_layer_bank << 14 & 0x4000;
	m_midl_layer_d14 = m_rf2_layer_bank << 13 & 0x4000;
	m_fore_layer_d14 = m_rf2_layer_bank << 12 & 0x4000;
}

WRITE16_MEMBER(seibuspi_state::spi_layer_bank_w)
{
	//logerror("Writing %04X to layer register\n", data);

	// r000f000 0010100a
	// r: rowscroll enable
	// f: fore layer d13
	// a: ? (0 in ejanhs and rdft22kc, 1 in all other games)
	uint16_t prev = m_layer_bank;
	COMBINE_DATA(&m_layer_bank);

	m_rowscroll_enable = m_layer_bank >> 15 & 1;
	set_layer_offsets();

	if ((prev ^ m_layer_bank) & 0x0800)
		m_fore_layer->mark_all_dirty();
}


WRITE8_MEMBER(seibuspi_state::rf2_layer_bank_w)
{
	// 00000fmb
	// f: fore layer d14
	// m: middle layer d14
	// b: back layer d14
	uint8_t prev = m_rf2_layer_bank;
	m_rf2_layer_bank = data;
	set_layer_offsets();

	if ((prev ^ m_rf2_layer_bank) & 1)
		m_back_layer->mark_all_dirty();

	if ((prev ^ m_rf2_layer_bank) & 2)
		m_midl_layer->mark_all_dirty();

	if ((prev ^ m_rf2_layer_bank) & 4)
		m_fore_layer->mark_all_dirty();
}

WRITE16_MEMBER(seibuspi_state::spi_layer_enable_w)
{
	// 00000000 000stfmb (0=on, 1=off)
	// s: sprite layer
	// t: text layer
	// f: fore layer
	// m: middle layer
	// b: back layer
	COMBINE_DATA(&m_layer_enable);
}

WRITE16_MEMBER(seibuspi_state::scroll_w)
{
	COMBINE_DATA(&m_scrollram[offset]);
}

WRITE32_MEMBER(seibuspi_state::video_dma_length_w)
{
	COMBINE_DATA(&m_video_dma_length);
}

WRITE32_MEMBER(seibuspi_state::video_dma_address_w)
{
	COMBINE_DATA(&m_video_dma_address);
}


/*****************************************************************************/

WRITE32_MEMBER(seibuspi_state::tilemap_dma_start_w)
{
	if (!m_tilemap_ram)
		return;

	// safety check
	int dma_length_user = m_rowscroll_enable ? 0x4000 : 0x2800;
	int dma_length_real = (m_video_dma_length + 1) * 2; // ideally we should be using this, let's check if we have to:
	if (m_video_dma_length != 0 && dma_length_user != dma_length_real)
		popmessage("Tile LEN %X %X, contact MAMEdev", dma_length_user, dma_length_real); // shouldn't happen
	else if (!DWORD_ALIGNED(m_video_dma_address) || (m_video_dma_length & 3) != 3 || (m_video_dma_address + dma_length_user) > 0x40000)
		popmessage("Tile DMA %X %X, contact MAMEdev", m_video_dma_address, m_video_dma_length); // shouldn't happen
	if (m_video_dma_address < 0x800)
		logerror("tilemap_dma_start_w in I/O area: %X\n", m_video_dma_address);

	int index = m_video_dma_address / 4;

	/* back layer */
	for (int i = 0; i < 0x800/4; i++)
	{
		uint32_t tile = m_mainram[index];
		if (m_tilemap_ram[i] != tile)
		{
			m_tilemap_ram[i] = tile;
			m_back_layer->mark_tile_dirty((i * 2));
			m_back_layer->mark_tile_dirty((i * 2) + 1);
		}
		index++;
	}

	/* back layer row scroll */
	if (m_rowscroll_enable)
	{
		memcpy(&m_tilemap_ram[0x800/4], &m_mainram[index], 0x800/4);
		index += 0x800/4;
	}

	/* fore layer */
	for (int i = 0; i < 0x800/4; i++)
	{
		uint32_t tile = m_mainram[index];
		if (m_tilemap_ram[i+m_fore_layer_offset] != tile)
		{
			m_tilemap_ram[i+m_fore_layer_offset] = tile;
			m_fore_layer->mark_tile_dirty((i * 2));
			m_fore_layer->mark_tile_dirty((i * 2) + 1);
		}
		index++;
	}

	/* fore layer row scroll */
	if (m_rowscroll_enable)
	{
		memcpy(&m_tilemap_ram[0x1800/4], &m_mainram[index], 0x800/4); // 0x2800/4?
		index += 0x800/4;
	}

	/* middle layer */
	for (int i = 0; i < 0x800/4; i++)
	{
		uint32_t tile = m_mainram[index];
		if (m_tilemap_ram[i+m_midl_layer_offset] != tile)
		{
			m_tilemap_ram[i+m_midl_layer_offset] = tile;
			m_midl_layer->mark_tile_dirty((i * 2));
			m_midl_layer->mark_tile_dirty((i * 2) + 1);
		}
		index++;
	}

	/* middle layer row scroll */
	if (m_rowscroll_enable)
	{
		memcpy(&m_tilemap_ram[0x2800/4], &m_mainram[index], 0x800/4); // 0x1800/4?
		index += 0x800/4;
	}

	/* text layer */
	for (int i = 0; i < 0x1000/4; i++)
	{
		uint32_t tile = m_mainram[index];
		if (m_tilemap_ram[i+m_text_layer_offset] != tile)
		{
			m_tilemap_ram[i+m_text_layer_offset] = tile;
			m_text_layer->mark_tile_dirty((i * 2));
			m_text_layer->mark_tile_dirty((i * 2) + 1);
		}
		index++;
	}
}


WRITE32_MEMBER(seibuspi_state::palette_dma_start_w)
{
	int dma_length = (m_video_dma_length + 1) * 2;

	// safety check
	if (!DWORD_ALIGNED(m_video_dma_address) || (m_video_dma_length & 3) != 3 || dma_length > m_palette_ram_size || (m_video_dma_address + dma_length) > 0x40000)
		popmessage("Pal DMA %X %X, contact MAMEdev", m_video_dma_address, m_video_dma_length); // shouldn't happen
	if (m_video_dma_address < 0x800)
		logerror("palette_dma_start_w in I/O area: %X\n", m_video_dma_address);

	for (int i = 0; i < dma_length / 4; i++)
	{
		uint32_t color = m_mainram[m_video_dma_address / 4 + i];
		if (m_palette_ram[i] != color)
		{
			m_palette_ram[i] = color;
			m_palette->set_pen_color((i * 2), pal5bit(m_palette_ram[i] >> 0), pal5bit(m_palette_ram[i] >> 5), pal5bit(m_palette_ram[i] >> 10));
			m_palette->set_pen_color((i * 2) + 1, pal5bit(m_palette_ram[i] >> 16), pal5bit(m_palette_ram[i] >> 21), pal5bit(m_palette_ram[i] >> 26));
		}
	}
}


WRITE16_MEMBER(seibuspi_state::sprite_dma_start_w)
{
	// safety check
	if (!DWORD_ALIGNED(m_video_dma_address) || (m_video_dma_address + m_sprite_ram_size) > 0x40000)
		popmessage("Sprite DMA %X, contact MAMEdev", m_video_dma_address); // shouldn't happen
	if (m_video_dma_address < 0x800)
		logerror("sprite_dma_start_w in I/O area: %X\n", m_video_dma_address);

	memcpy(m_sprite_ram.get(), &m_mainram[m_video_dma_address / 4], m_sprite_ram_size);
}


/*****************************************************************************/

void seibuspi_state::drawgfx_blend(bitmap_rgb32 &bitmap, const rectangle &cliprect, gfx_element *gfx, uint32_t code, uint32_t color, int flipx, int flipy, int sx, int sy, bitmap_ind8 &primap, int primask)
{
	int width = gfx->width();
	int height = gfx->height();

	int x1 = sx;
	int x2 = sx + width - 1;
	int y1 = sy;
	int y2 = sy + height - 1;

	if (x1 > cliprect.max_x || x2 < cliprect.min_x)
	{
		return;
	}
	if (y1 > cliprect.max_y || y2 < cliprect.min_y)
	{
		return;
	}

	int px = 0;
	int py = 0;
	int xd = 1;
	int yd = 1;

	if (flipx)
	{
		xd = -xd;
		px = width - 1;
	}
	if (flipy)
	{
		yd = -yd;
		py = height - 1;
	}

	// clip x
	if (x1 < cliprect.min_x)
	{
		if (flipx)
		{
			px = width - (cliprect.min_x - x1) - 1;
		}
		else
		{
			px = (cliprect.min_x - x1);
		}
		x1 = cliprect.min_x;
	}
	if (x2 > cliprect.max_x)
	{
		x2 = cliprect.max_x;
	}

	// clip y
	if (y1 < cliprect.min_y)
	{
		if (flipy)
		{
			py = height - (cliprect.min_y - y1) - 1;
		}
		else
		{
			py = (cliprect.min_y - y1);
		}
		y1 = cliprect.min_y;
	}
	if (y2 > cliprect.max_y)
	{
		y2 = cliprect.max_y;
	}

	const pen_t *pens = &m_palette->pen(gfx->colorbase());
	const uint8_t *src = gfx->get_data(code);

	// draw
	for (int y = y1; y <= y2; y++)
	{
		uint32_t *dest = &bitmap.pix32(y);
		uint8_t *pri = &primap.pix8(y);
		uint8_t trans_pen = (1 << m_sprite_bpp) - 1;
		int src_i = (py * width) + px;
		py += yd;

		for (int x = x1; x <= x2; x++)
		{
			uint8_t pen = src[src_i];
			if (!(pri[x] & primask) && pen != trans_pen)
			{
				pri[x] |= primask;
				int global_pen = pen + (color << m_sprite_bpp);
				if (m_alpha_table[global_pen])
					dest[x] = alpha_blend_r32(dest[x], pens[global_pen], 0x7f);
				else
					dest[x] = pens[global_pen];
			}
			src_i += xd;
		}
	}
}

void seibuspi_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, bitmap_ind8 &primap, int priority)
{
	gfx_element *gfx = m_gfxdecode->gfx(2);
	const int has_tile_high = (gfx->elements() > 0x10000) ? 1 : 0;
	const int colormask = (m_sprite_bpp == 6) ? 0x3f : 0x1f;

	static const int sprite_xtable[2][8] =
	{
		{ 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
		{ 7*16, 6*16, 5*16, 4*16, 3*16, 2*16, 1*16, 0*16 }
	};
	static const int sprite_ytable[2][8] =
	{
		{ 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16 },
		{ 7*16, 6*16, 5*16, 4*16, 3*16, 2*16, 1*16, 0*16 }
	};

	if (m_layer_enable & 0x10)
		return;

	for (int a = 0; a < (m_sprite_ram_size / 4); a += 2)
	{
		/*
		    Word 0
		    xxxxxxxx xxxxxxxx -------- --------  tile_num low
		    -------- -------- x------- --------  flip_y
		    -------- -------- -xxx---- --------  height
		    -------- -------- ----x--- --------  flip_x
		    -------- -------- -----xxx --------  width
		    -------- -------- -------- xx------  priority
		    -------- -------- -------- --xxxxxx  color (highest bit not used on SYS386F)

		    Word 1, unmarked bits have no function
		    -------x xxxxxxxx -------- --------  ypos
		    -------- -------- ---x---- --------  tile_num high (only on RISE10/11 chip)
		    -------- -------- ------xx xxxxxxxx  xpos
		*/
		int tile_num = m_sprite_ram[a + 0] >> 16 & 0xffff;
		if (tile_num == 0)
			continue;

		if (has_tile_high)
			tile_num |= m_sprite_ram[a + 1] << 4 & 0x10000;

		if (priority != (m_sprite_ram[a + 0] >> 6 & 0x3))
			continue;
		int primask = 1 << priority;

		int16_t xpos = m_sprite_ram[a + 1] & 0x3ff;
		if (xpos & 0x200)
			xpos |= 0xfc00;
		int16_t ypos = m_sprite_ram[a + 1] >> 16 & 0x1ff;
		if (ypos & 0x100)
			ypos |= 0xfe00;
		int color = m_sprite_ram[a + 0] & colormask;

		int width = (m_sprite_ram[a + 0] >> 8 & 0x7) + 1;
		int height = (m_sprite_ram[a + 0] >> 12 & 0x7) + 1;
		int flip_x = m_sprite_ram[a + 0] >> 11 & 0x1;
		int flip_y = m_sprite_ram[a + 0] >> 15 & 0x1;
		int x1 = 0;
		int y1 = 0;

		if (flip_x)
		{
			x1 = 8 - width;
			width = width + x1;
		}
		if (flip_y)
		{
			y1 = 8 - height;
			height = height + y1;
		}

		for (int x = x1; x < width; x++)
		{
			for (int y = y1; y < height; y++)
			{
				drawgfx_blend(bitmap, cliprect, gfx, tile_num, color, flip_x, flip_y, xpos + sprite_xtable[flip_x][x], ypos + sprite_ytable[flip_y][y], primap, primask);

				/* xpos seems to wrap-around to 0 at 512 */
				if ((xpos + (16 * x) + 16) >= 512)
					drawgfx_blend(bitmap, cliprect, gfx, tile_num, color, flip_x, flip_y, xpos - 512 + sprite_xtable[flip_x][x], ypos + sprite_ytable[flip_y][y], primap, primask);

				tile_num++;
			}
		}
	}
}

void seibuspi_state::combine_tilemap(bitmap_rgb32 &bitmap, const rectangle &cliprect, tilemap_t *tile, int sx, int sy, int opaque, int16_t *rowscroll)
{
	uint16_t *src;
	uint32_t *dest;
	uint8_t *flags;
	uint32_t xscroll_mask, yscroll_mask;

	bitmap_ind16 &pen_bitmap = tile->pixmap();
	bitmap_ind8 &flags_bitmap = tile->flagsmap();
	xscroll_mask = pen_bitmap.width() - 1;
	yscroll_mask = pen_bitmap.height() - 1;

	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
	{
		int rx = sx;
		if (rowscroll)
		{
			rx += rowscroll[(y + sy) & yscroll_mask];
		}

		dest = &bitmap.pix32(y);
		src = &pen_bitmap.pix16((y + sy) & yscroll_mask);
		flags = &flags_bitmap.pix8((y + sy) & yscroll_mask);
		for (int x = cliprect.min_x + rx; x <= cliprect.max_x + rx; x++)
		{
			if (opaque || (flags[x & xscroll_mask] & (TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1)))
			{
				uint16_t pen = src[x & xscroll_mask];
				if (m_alpha_table[pen])
					*dest = alpha_blend_r32(*dest, m_palette->pen(pen), 0x7f);
				else
					*dest = m_palette->pen(pen);
			}
			dest++;
		}
	}
}


uint32_t seibuspi_state::screen_update_spi(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	int16_t *back_rowscroll, *midl_rowscroll, *fore_rowscroll;
	if (m_rowscroll_enable)
	{
		back_rowscroll = (int16_t*)&m_tilemap_ram[0x200];
		midl_rowscroll = (int16_t*)&m_tilemap_ram[0x600];
		fore_rowscroll = (int16_t*)&m_tilemap_ram[0xa00];
	}
	else
	{
		back_rowscroll = nullptr;
		midl_rowscroll = nullptr;
		fore_rowscroll = nullptr;
	}

	screen.priority().fill(0, cliprect);

	if (m_layer_enable & 1)
		bitmap.fill(0, cliprect);
	else
		combine_tilemap(bitmap, cliprect, m_back_layer, m_scrollram[0], m_scrollram[1], 1, back_rowscroll);

	draw_sprites(bitmap, cliprect, screen.priority(), 0);

	// if fore layer is enabled, draw priority 0 sprites behind back layer
	if ((m_layer_enable & 0x15) == 0)
		combine_tilemap(bitmap, cliprect, m_back_layer, m_scrollram[0], m_scrollram[1], 0, back_rowscroll);

	// if fore layer is enabled, draw priority 1 sprites behind middle layer
	if (~m_layer_enable & 4)
		draw_sprites(bitmap, cliprect, screen.priority(), 1);

	if (~m_layer_enable & 2)
		combine_tilemap(bitmap, cliprect, m_midl_layer, m_scrollram[2], m_scrollram[3], 0, midl_rowscroll);

	// if fore layer is disabled, draw priority 1 sprites above middle layer
	if (m_layer_enable & 4)
		draw_sprites(bitmap, cliprect, screen.priority(), 1);

	draw_sprites(bitmap, cliprect, screen.priority(), 2);

	if (~m_layer_enable & 4)
		combine_tilemap(bitmap, cliprect, m_fore_layer, m_scrollram[4], m_scrollram[5], 0, fore_rowscroll);

	draw_sprites(bitmap, cliprect, screen.priority(), 3);

	if (~m_layer_enable & 8)
		combine_tilemap(bitmap, cliprect, m_text_layer, 0, 0, 0, nullptr);

	return 0;
}

uint32_t seibuspi_state::screen_update_sys386f(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	screen.priority().fill(0, cliprect);
	bitmap.fill(0, cliprect);

	draw_sprites(bitmap, cliprect, screen.priority(), 0);
	draw_sprites(bitmap, cliprect, screen.priority(), 1);
	draw_sprites(bitmap, cliprect, screen.priority(), 2);
	draw_sprites(bitmap, cliprect, screen.priority(), 3);

	return 0;
}


/*****************************************************************************/

TILE_GET_INFO_MEMBER(seibuspi_state::get_text_tile_info)
{
	int offs = tile_index / 2;
	int tile = (m_tilemap_ram[offs + m_text_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
	int color = (tile >> 12) & 0xf;

	tile &= 0xfff;

	SET_TILE_INFO_MEMBER(0, tile, color, 0);
}

TILE_GET_INFO_MEMBER(seibuspi_state::get_back_tile_info)
{
	int offs = tile_index / 2;
	int tile = (m_tilemap_ram[offs] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
	int color = (tile >> 13) & 0x7;

	tile &= 0x1fff;
	tile |= m_back_layer_d14;

	SET_TILE_INFO_MEMBER(1, tile, color, 0);
}

TILE_GET_INFO_MEMBER(seibuspi_state::get_midl_tile_info)
{
	int offs = tile_index / 2;
	int tile = (m_tilemap_ram[offs + m_midl_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
	int color = (tile >> 13) & 0x7;

	tile &= 0x1fff;
	tile |= 0x2000;
	tile |= m_midl_layer_d14;

	SET_TILE_INFO_MEMBER(1, tile, color + 16, 0);
}

TILE_GET_INFO_MEMBER(seibuspi_state::get_fore_tile_info)
{
	int offs = tile_index / 2;
	int tile = (m_tilemap_ram[offs + m_fore_layer_offset] >> ((tile_index & 0x1) ? 16 : 0)) & 0xffff;
	int color = (tile >> 13) & 0x7;

	tile &= 0x1fff;
	tile |= m_bg_fore_layer_position;
	tile |= m_fore_layer_d13;
	tile |= m_fore_layer_d14;

	SET_TILE_INFO_MEMBER(1, tile, color + 8, 0);
}


void seibuspi_state::video_start()
{
	m_video_dma_length = 0;
	m_video_dma_address = 0;
	m_layer_enable = 0;
	m_layer_bank = 0;
	m_rf2_layer_bank = 0;
	m_rowscroll_enable = 0;
	m_scrollram[0] = 0;
	m_scrollram[1] = 0;
	m_scrollram[2] = 0;
	m_scrollram[3] = 0;
	m_scrollram[4] = 0;
	m_scrollram[5] = 0;
	set_layer_offsets();

	uint32_t region_length = memregion("gfx2")->bytes();

	if (region_length <= 0x300000)
		m_bg_fore_layer_position = 0x2000;
	else if (region_length <= 0x600000)
		m_bg_fore_layer_position = 0x4000;
	else
		m_bg_fore_layer_position = 0x8000;

	m_tilemap_ram_size = 0x4000;
	m_palette_ram_size = 0x3000;
	m_sprite_ram_size = 0x1000;
	m_sprite_bpp = 6;

	m_tilemap_ram = make_unique_clear<uint32_t[]>(m_tilemap_ram_size/4);
	m_palette_ram = make_unique_clear<uint32_t[]>(m_palette_ram_size/4);
	m_sprite_ram = make_unique_clear<uint32_t[]>(m_sprite_ram_size/4);

	m_palette->basemem().set(&m_palette_ram[0], m_palette_ram_size, 32, ENDIANNESS_LITTLE, 2);

	m_text_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(seibuspi_state::get_text_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64,32);
	m_back_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(seibuspi_state::get_back_tile_info),this), TILEMAP_SCAN_COLS, 16,16,32,32);
	m_midl_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(seibuspi_state::get_midl_tile_info),this), TILEMAP_SCAN_COLS, 16,16,32,32);
	m_fore_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(seibuspi_state::get_fore_tile_info),this), TILEMAP_SCAN_COLS, 16,16,32,32);

	m_text_layer->set_transparent_pen(31);
	m_back_layer->set_transparent_pen(63);
	m_midl_layer->set_transparent_pen(63);
	m_fore_layer->set_transparent_pen(63);

	// TODO : Differs per games?
	// alpha blending (preliminary)
	memset(m_alpha_table, 0, 0x2000);

	// sprites(0000-0fff):
	//memset(m_alpha_table + 0x700, 1, 0x10); // breaks rdft
	memset(m_alpha_table + 0x730, 1, 0x10);
	memset(m_alpha_table + 0x780, 1, 0x20);
	//memset(m_alpha_table + 0x7c0, 1, 0x40); // breaks batlball
	//memset(m_alpha_table + 0xf00, 1, 0x40); // breaks rdft
	memset(m_alpha_table + 0xfc0, 1, 0x40);

	// back layer(1000-11ff): nope
	// fore layer(1200-13ff):
	memset(m_alpha_table + 0x1200 + 0x160, 1, 0x20);
	memset(m_alpha_table + 0x1200 + 0x1b0, 1, 0x10);
	memset(m_alpha_table + 0x1200 + 0x1f0, 1, 0x10);
	// midl layer(1400-15ff)
	memset(m_alpha_table + 0x1400 + 0x1b0, 1, 0x10);
	memset(m_alpha_table + 0x1400 + 0x1f0, 1, 0x10);
	// text layer(1600-17ff)
	memset(m_alpha_table + 0x1600 + 0x170, 1, 0x10);
	memset(m_alpha_table + 0x1600 + 0x1f0, 1, 0x10);

	register_video_state();
}

VIDEO_START_MEMBER(seibuspi_state,ejanhs)
{
	video_start();

	memset(m_alpha_table, 0, 0x2000); // no alpha blending
}

VIDEO_START_MEMBER(seibuspi_state,sys386f)
{
	m_video_dma_length = 0;
	m_video_dma_address = 0;
	m_layer_enable = 0;
	m_layer_bank = 0;
	m_rf2_layer_bank = 0;
	m_rowscroll_enable = 0;
	set_layer_offsets();

	m_tilemap_ram_size = 0;
	m_palette_ram_size = 0x4000;
	m_sprite_ram_size = 0x2000;
	m_sprite_bpp = 8;

	m_tilemap_ram = nullptr;
	m_palette_ram = make_unique_clear<uint32_t[]>(m_palette_ram_size/4);
	m_sprite_ram = make_unique_clear<uint32_t[]>(m_sprite_ram_size/4);

	m_palette->basemem().set(&m_palette_ram[0], m_palette_ram_size, 32, ENDIANNESS_LITTLE, 2);

	memset(m_alpha_table, 0, 0x2000); // no alpha blending

	register_video_state();
}

void seibuspi_state::register_video_state()
{
	save_item(NAME(m_video_dma_length));
	save_item(NAME(m_video_dma_address));
	save_item(NAME(m_layer_enable));
	save_item(NAME(m_layer_bank));
	save_item(NAME(m_rf2_layer_bank));
	save_item(NAME(m_rowscroll_enable));
	save_item(NAME(m_scrollram));

	save_item(NAME(m_midl_layer_offset));
	save_item(NAME(m_fore_layer_offset));
	save_item(NAME(m_text_layer_offset));
	save_item(NAME(m_fore_layer_d13));
	save_item(NAME(m_back_layer_d14));
	save_item(NAME(m_midl_layer_d14));
	save_item(NAME(m_fore_layer_d14));

	if (m_tilemap_ram != nullptr) save_pointer(NAME(m_tilemap_ram), m_tilemap_ram_size/4);
	save_pointer(NAME(m_palette_ram), m_palette_ram_size/4);
	save_pointer(NAME(m_sprite_ram), m_sprite_ram_size/4);
}