1 // FinalBurn Neo Sega System C/C2 driver module
2 // Based on MAME driver by David Haywood and Aaron Giles
3 
4 // System C/C2 vdp note:
5 // System C mixes the raw data from the sprite & other layers externally
6 // Because of this the sprite:sprite masking (x == 0) feature, internal to the
7 // 315-5313 vdp, is not used.  When properly implemented and coming from the
8 // rgb output (using internal VDP mixer), The beach and Metal Factory levels
9 // will have sprites with incorrect masking due to the game hiding sprites
10 // with x == 0.
11 
12 #include "tiles_generic.h"
13 #include "m68000_intf.h"
14 #include "burn_ym2612.h"
15 #include "upd7759.h"
16 #include "sn76496.h"
17 #include "burn_pal.h"
18 #include "burn_gun.h" // for dial (BurnTrackball)
19 
20 static UINT8 *AllMem;
21 static UINT8 *AllRam;
22 static UINT8 *RamEnd;
23 static UINT8 *MemEnd;
24 static UINT8 *Drv68KROM;
25 static UINT8 *DrvSndROM;
26 static UINT8 *Drv68KRAM;
27 static UINT8 *DrvPalRAM;
28 
29 static UINT32 *DrvPalette;
30 static UINT8 DrvRecalc;
31 
32 static INT32 nExtraCycles[1];
33 
34 static INT32 sound_rom_length = 0;
35 static UINT8 (*protection_read_cb)(UINT8);
36 
37 static INT32 prot_write_buf = 0;
38 static INT32 prot_read_buf = 0;
39 
40 static INT32 enable_display = 0;
41 
42 static INT32 alt_palette_mode = 0;
43 static INT32 palette_bank = 0;
44 static INT32 bg_palbase = 0;
45 static INT32 sp_palbase = 0;
46 
47 static UINT8 output_latch[8];
48 static UINT8 dir = 0;
49 static UINT8 dir_override = 0;
50 static UINT8 iocnt = 0;
51 
52 static INT32 sound_bank = 0;
53 
54 static INT32 irq6_line;
55 static INT32 irq4_counter;
56 static UINT16 SegaC2BgPalLookup[4];
57 static UINT16 SegaC2SpPalLookup[4];
58 
59 static UINT8 DrvInputs[8];
60 static UINT8 DrvDips[4];
61 static UINT8 DrvJoy1[8];
62 static UINT8 DrvJoy2[8];
63 static UINT8 DrvJoy3[8];
64 static UINT8 DrvReset;
65 
66 static INT16 Analog[2];
67 
68 static INT32 is_wwmarine = 0;
69 static INT32 is_tfrceacb = 0;
70 static INT32 is_ribbit = 0;
71 
72 static INT32 has_dial = 0;
73 
74 struct PicoVideo {
75 	UINT8 reg[0x20];
76 	UINT32 command;		// 32-bit Command
77 	UINT8 pending;		// 1 if waiting for second half of 32-bit command
78 	UINT8 type;			// Command type (v/c/vsram read/write)
79 	UINT16 addr;		// Read/Write address
80 	UINT8 addr_u;       // bit16 of .addr (for 128k)
81 	INT32 status;		// Status bits
82 	UINT8 pending_ints;	// pending interrupts: ??VH????
83 	INT8 lwrite_cnt;    // VDP write count during active display line
84 	UINT16 v_counter;   // V-counter
85 	INT32 h_mask;
86 	INT32 field;		// for interlace mode 2.  -dink
87 	INT32 rotate;
88 	INT32 debug_p;		// debug port
89 	INT32 rendstatus;	// status of vdp renderer
90 };
91 
92 #define LF_PLANE_1 (1 << 0)
93 #define LF_SH      (1 << 1) // must be = 2
94 #define LF_FORCE   (1 << 2)
95 
96 #define SPRL_HAVE_HI     0x80 // have hi priority sprites
97 #define SPRL_HAVE_LO     0x40 // *lo*
98 #define SPRL_MAY_HAVE_OP 0x20 // may have operator sprites on the line
99 #define SPRL_LO_ABOVE_HI 0x10 // low priority sprites may be on top of hi
100 
101 #define PVD_KILL_A    (1 << 0)
102 #define PVD_KILL_B    (1 << 1)
103 #define PVD_KILL_S_LO (1 << 2)
104 #define PVD_KILL_S_HI (1 << 3)
105 #define PVD_KILL_32X  (1 << 4)
106 #define PVD_FORCE_A   (1 << 5)
107 #define PVD_FORCE_B   (1 << 6)
108 #define PVD_FORCE_S   (1 << 7)
109 
110 #define PDRAW_SPRITES_MOVED (1<<0) // (asm)
111 #define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority
112 #define PDRAW_INTERLACE     (1<<3)
113 #define PDRAW_DIRTY_SPRITES (1<<4) // (asm)
114 #define PDRAW_SONIC_MODE    (1<<5) // mid-frame palette changes for 8bit renderer
115 #define PDRAW_PLANE_HI_PRIO (1<<6) // have layer with all hi prio tiles (mk3)
116 #define PDRAW_SHHI_DONE     (1<<7) // layer sh/hi already processed
117 #define PDRAW_32_COLS       (1<<8) // 32 column mode
118 
119 #define MAX_LINE_SPRITES 29
120 
121 static UINT8 HighLnSpr[240][3 + MAX_LINE_SPRITES]; // sprite_count, ^flags, tile_count, [spritep]...
122 
123 struct TileStrip
124 {
125 	INT32 nametab; // Position in VRAM of name table (for this tile line)
126 	INT32 line;    // Line number in pixels 0x000-0x3ff within the virtual tilemap
127 	INT32 hscroll; // Horizontal scroll value in pixels for the line
128 	INT32 xmask;   // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap
129 	INT32 *hc;     // cache for high tile codes and their positions
130 	INT32 cells;   // cells (tiles) to draw (32 col mode doesn't need to update whole 320)
131 };
132 
133 static UINT16 *RamPal;
134 static UINT16 *RamVid;
135 static UINT16 *RamSVid;
136 static struct PicoVideo *RamVReg;
137 
138 static UINT16 *HighCol;
139 static UINT16 *HighColFull;
140 
141 static INT32 *HighCacheA;
142 static INT32 *HighCacheB;
143 static INT32 *HighPreSpr;
144 
145 static INT32 Scanline = 0;
146 static INT32 line_base_cycles;
147 
148 static INT32 Hardware = 0x00; // japan-ntsc
149 static INT32 dma_xfers = 0; // vdp dma
150 static INT32 BlankedLine = 0;
151 static INT32 interlacemode2 = 0;
152 
153 #define SekCyclesLine()         ( (SekTotalCycles() - line_base_cycles) )
154 
155 static struct BurnInputInfo SegaC2_3ButtonInputList[] = {
156 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
157 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
158 	{"P1 Up",			BIT_DIGITAL,	DrvJoy1 + 5,	"p1 up"		},
159 	{"P1 Down",			BIT_DIGITAL,	DrvJoy1 + 4,	"p1 down"	},
160 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
161 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
162 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
163 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
164 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 fire 3"	},
165 
166 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
167 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
168 	{"P2 Up",			BIT_DIGITAL,	DrvJoy2 + 5,	"p2 up"		},
169 	{"P2 Down",			BIT_DIGITAL,	DrvJoy2 + 4,	"p2 down"	},
170 	{"P2 Left",			BIT_DIGITAL,	DrvJoy2 + 7,	"p2 left"	},
171 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 right"	},
172 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 fire 1"	},
173 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy2 + 1,	"p2 fire 2"	},
174 	{"P2 Button 3",		BIT_DIGITAL,	DrvJoy2 + 2,	"p2 fire 3"	},
175 
176 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
177 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
178 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
179 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
180 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
181 };
182 
183 STDINPUTINFO(SegaC2_3Button)
184 
185 static struct BurnInputInfo SegaC2_2ButtonInputList[] = {
186 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
187 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
188 	{"P1 Up",			BIT_DIGITAL,	DrvJoy1 + 5,	"p1 up"		},
189 	{"P1 Down",			BIT_DIGITAL,	DrvJoy1 + 4,	"p1 down"	},
190 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
191 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
192 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
193 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
194 
195 
196 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
197 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
198 	{"P2 Up",			BIT_DIGITAL,	DrvJoy2 + 5,	"p2 up"		},
199 	{"P2 Down",			BIT_DIGITAL,	DrvJoy2 + 4,	"p2 down"	},
200 	{"P2 Left",			BIT_DIGITAL,	DrvJoy2 + 7,	"p2 left"	},
201 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 right"	},
202 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 fire 1"	},
203 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy2 + 1,	"p2 fire 2"	},
204 
205 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
206 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
207 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
208 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
209 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
210 };
211 
212 STDINPUTINFO(SegaC2_2Button)
213 
214 static struct BurnInputInfo SegaC2_1ButtonInputList[] = {
215 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
216 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
217 	{"P1 Up",			BIT_DIGITAL,	DrvJoy1 + 5,	"p1 up"		},
218 	{"P1 Down",			BIT_DIGITAL,	DrvJoy1 + 4,	"p1 down"	},
219 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
220 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
221 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
222 
223 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
224 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
225 	{"P2 Up",			BIT_DIGITAL,	DrvJoy2 + 5,	"p2 up"		},
226 	{"P2 Down",			BIT_DIGITAL,	DrvJoy2 + 4,	"p2 down"	},
227 	{"P2 Left",			BIT_DIGITAL,	DrvJoy2 + 7,	"p2 left"	},
228 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 right"	},
229 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 fire 1"	},
230 
231 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
232 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
233 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
234 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
235 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
236 };
237 
238 STDINPUTINFO(SegaC2_1Button)
239 
240 static struct BurnInputInfo RibbitInputList[] = { // Look Ma! No buttons!
241 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
242 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
243 	{"P1 Up",			BIT_DIGITAL,	DrvJoy1 + 5,	"p1 up"		},
244 	{"P1 Down",			BIT_DIGITAL,	DrvJoy1 + 4,	"p1 down"	},
245 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
246 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
247 
248 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
249 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
250 	{"P2 Up",			BIT_DIGITAL,	DrvJoy2 + 5,	"p2 up"		},
251 	{"P2 Down",			BIT_DIGITAL,	DrvJoy2 + 4,	"p2 down"	},
252 	{"P2 Left",			BIT_DIGITAL,	DrvJoy2 + 7,	"p2 left"	},
253 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 right"	},
254 
255 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
256 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
257 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
258 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
259 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
260 };
261 
262 STDINPUTINFO(Ribbit)
263 
264 #define A(a, b, c, d) {a, b, (UINT8*)(c), d}
265 static struct BurnInputInfo TwinsquaInputList[] = {
266 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
267 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
268 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy3 + 6,	"p1 fire 1"	},
269 	A("P1 Dial", 		BIT_ANALOG_REL, &Analog[0],		"p1 x-axis"),
270 
271 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
272 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
273 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy3 + 7,	"p2 fire 1"	},
274 	A("P2 Dial", 		BIT_ANALOG_REL, &Analog[1],		"p2 x-axis"),
275 
276 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
277 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
278 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
279 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
280 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
281 };
282 #undef A
283 STDINPUTINFO(Twinsqua)
284 
285 static struct BurnInputInfo SoniccarInputList[] = {
286 	{"Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
287 	{"Lt Stick Left",	BIT_DIGITAL,	DrvJoy1 + 5,	"p1 left"	},
288 	{"Lt Stick Right",	BIT_DIGITAL,	DrvJoy1 + 4,	"p1 right"	},
289 	{"Rt Stick Left",	BIT_DIGITAL,	DrvJoy1 + 7,	"p2 left"	},
290 	{"Rt Stick Right",	BIT_DIGITAL,	DrvJoy1 + 6,	"p2 right"	},
291 	{"Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
292 	{"Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
293 	{"Button 3",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 fire 3"	},
294 	{"Button 4",		BIT_DIGITAL,	DrvJoy1 + 3,	"p1 fire 4"	},
295 
296 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
297 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
298 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
299 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
300 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
301 };
302 
303 STDINPUTINFO(Soniccar)
304 
305 static struct BurnInputInfo OopartsInputList[] = {
306 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
307 	{"P1 Start",		BIT_DIGITAL,	DrvJoy3 + 4,	"p1 start"	},
308 	{"P1 Up",			BIT_DIGITAL,	DrvJoy1 + 5,	"p1 up"		},
309 	{"P1 Down",			BIT_DIGITAL,	DrvJoy1 + 4,	"p1 down"	},
310 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
311 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
312 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
313 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
314 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy3 + 6,	"p1 fire 3"	},
315 
316 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
317 	{"P2 Start",		BIT_DIGITAL,	DrvJoy3 + 5,	"p2 start"	},
318 	{"P2 Up",			BIT_DIGITAL,	DrvJoy2 + 5,	"p2 up"		},
319 	{"P2 Down",			BIT_DIGITAL,	DrvJoy2 + 4,	"p2 down"	},
320 	{"P2 Left",			BIT_DIGITAL,	DrvJoy2 + 7,	"p2 left"	},
321 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 right"	},
322 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 fire 1"	},
323 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy2 + 1,	"p2 fire 2"	},
324 	{"P2 Button 3",		BIT_DIGITAL,	DrvJoy3 + 7,	"p2 fire 3"	},
325 
326 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
327 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
328 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
329 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
330 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
331 };
332 
333 STDINPUTINFO(Ooparts)
334 
335 static struct BurnInputInfo WwmarineInputList[] = {
336 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
337 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 6,	"p1 left"	},
338 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 7,	"p1 right"	},
339 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
340 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
341 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 fire 3"	},
342 
343 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
344 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
345 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
346 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
347 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
348 };
349 
350 STDINPUTINFO(Wwmarine)
351 
352 static struct BurnInputInfo SonicfgtInputList[] = {
353 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
354 	{"P1 Left",			BIT_DIGITAL,	DrvJoy1 + 7,	"p1 left"	},
355 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 right"	},
356 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
357 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
358 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy1 + 5,	"p1 fire 3"	},
359 
360 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
361 	{"Service Mode",	BIT_DIGITAL,	DrvJoy3 + 2,	"diag"		},
362 	{"Service",			BIT_DIGITAL,	DrvJoy3 + 3,	"service"	},
363 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
364 	{"Dip B",			BIT_DIPSWITCH,	DrvDips + 1,	"dip"		},
365 };
366 
367 STDINPUTINFO(Sonicfgt)
368 
369 
370 
371 #define coinage_dips(_num)										\
372 	{0   , 0xfe, 0   ,   16, "Coin A"						},	\
373 	{_num, 0x01, 0x0f, 0x07, "4 Coins 1 Credits"			},	\
374 	{_num, 0x01, 0x0f, 0x08, "3 Coins 1 Credits"			},	\
375 	{_num, 0x01, 0x0f, 0x09, "2 Coins 1 Credits"			},	\
376 	{_num, 0x01, 0x0f, 0x05, "2 Coins/1 Credit, 5/3, 6/4"	},	\
377 	{_num, 0x01, 0x0f, 0x04, "2 Coins/1 Credit, 4/3"		},	\
378 	{_num, 0x01, 0x0f, 0x0f, "1 Coin  1 Credits"			},	\
379 	{_num, 0x01, 0x0f, 0x03, "1 Coin/1 Credit, 5/6"			},	\
380 	{_num, 0x01, 0x0f, 0x02, "1 Coin/1 Credit, 4/5"			},	\
381 	{_num, 0x01, 0x0f, 0x01, "1 Coin/1 Credit, 2/3"			},	\
382 	{_num, 0x01, 0x0f, 0x06, "2 Coins 3 Credits"			},	\
383 	{_num, 0x01, 0x0f, 0x0e, "1 Coin  2 Credits"			},	\
384 	{_num, 0x01, 0x0f, 0x0d, "1 Coin  3 Credits"			},	\
385 	{_num, 0x01, 0x0f, 0x0c, "1 Coin  4 Credits"			},	\
386 	{_num, 0x01, 0x0f, 0x0b, "1 Coin  5 Credits"			},	\
387 	{_num, 0x01, 0x0f, 0x0a, "1 Coin  6 Credits"			},	\
388 	{_num, 0x01, 0x0f, 0x00, "Free Play (if Coin B too) or 1/1"		},	\
389 																\
390 	{0   , 0xfe, 0   ,   16, "Coin B"						},	\
391 	{_num, 0x01, 0xf0, 0x70, "4 Coins 1 Credits"			},	\
392 	{_num, 0x01, 0xf0, 0x80, "3 Coins 1 Credits"			},	\
393 	{_num, 0x01, 0xf0, 0x90, "2 Coins 1 Credits"			},	\
394 	{_num, 0x01, 0xf0, 0x50, "2 Coins/1 Credit, 5/3, 6/4"	},	\
395 	{_num, 0x01, 0xf0, 0x40, "2 Coins/1 Credit, 4/3"		},	\
396 	{_num, 0x01, 0xf0, 0xf0, "1 Coin  1 Credits"			},	\
397 	{_num, 0x01, 0xf0, 0x30, "1 Coin/1 Credit, 5/6"			},	\
398 	{_num, 0x01, 0xf0, 0x20, "1 Coin/1 Credit, 4/5"			},	\
399 	{_num, 0x01, 0xf0, 0x10, "1 Coin/1 Credit, 2/3"			},	\
400 	{_num, 0x01, 0xf0, 0x60, "2 Coins 3 Credits"			},	\
401 	{_num, 0x01, 0xf0, 0xe0, "1 Coin  2 Credits"			},	\
402 	{_num, 0x01, 0xf0, 0xd0, "1 Coin  3 Credits"			},	\
403 	{_num, 0x01, 0xf0, 0xc0, "1 Coin  4 Credits"			},	\
404 	{_num, 0x01, 0xf0, 0xb0, "1 Coin  5 Credits"			},	\
405 	{_num, 0x01, 0xf0, 0xa0, "1 Coin  6 Credits"			},	\
406 	{_num, 0x01, 0xf0, 0x00, "Free Play (if Coin A too) or 1/1"		},
407 
408 
409 static struct BurnDIPInfo BloxeedcDIPList[]=
410 {
411 	{0x11, 0xff, 0xff, 0xff, NULL							},
412 	{0x12, 0xff, 0xff, 0x77, NULL							},
413 
414 	coinage_dips(0x11)
415 
416 	{0   , 0xfe, 0   ,    4, "Credits to Start (VS)"		},
417 	{0x12, 0x01, 0x01, 0x00, "1"							},
418 	{0x12, 0x01, 0x01, 0x01, "2"							},
419 	{0x12, 0x01, 0x01, 0x00, "2"							},
420 	{0x12, 0x01, 0x01, 0x01, "4"							},
421 
422 	{0   , 0xfe, 0   ,    2, "Credits to Start (Normal)"	},
423 	{0x12, 0x01, 0x02, 0x02, "1"							},
424 	{0x12, 0x01, 0x02, 0x00, "2"							},
425 
426 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
427 	{0x12, 0x01, 0x08, 0x08, "Off"							},
428 	{0x12, 0x01, 0x08, 0x00, "On"							},
429 
430 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
431 	{0x12, 0x01, 0x30, 0x20, "Easy"							},
432 	{0x12, 0x01, 0x30, 0x30, "Normal"						},
433 	{0x12, 0x01, 0x30, 0x10, "Hard"							},
434 	{0x12, 0x01, 0x30, 0x00, "Hardest"						},
435 
436 	{0   , 0xfe, 0   ,    2, "High Speed Mode"				},
437 	{0x12, 0x01, 0x80, 0x00, "Off"							},
438 	{0x12, 0x01, 0x80, 0x80, "On"							},
439 };
440 
441 STDDIPINFO(Bloxeedc)
442 
443 static struct BurnDIPInfo BloxeeduDIPList[]=
444 {
445 	{0x11, 0xff, 0xff, 0xff, NULL							},
446 	{0x12, 0xff, 0xff, 0x77, NULL							},
447 
448 	coinage_dips(0x11)
449 
450 	{0   , 0xfe, 0   ,    4, "Credits to Start (Normal/VS)"	},
451 	{0x12, 0x01, 0x03, 0x01, "1 / 1"						},
452 	{0x12, 0x01, 0x03, 0x03, "1 / 2"						},
453 	{0x12, 0x01, 0x03, 0x02, "1 / 2"						},
454 	{0x12, 0x01, 0x03, 0x00, "2 / 4"						},
455 
456 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
457 	{0x12, 0x01, 0x08, 0x08, "Off"							},
458 	{0x12, 0x01, 0x08, 0x00, "On"							},
459 
460 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
461 	{0x12, 0x01, 0x30, 0x20, "Easy"							},
462 	{0x12, 0x01, 0x30, 0x30, "Normal"						},
463 	{0x12, 0x01, 0x30, 0x10, "Hard"							},
464 	{0x12, 0x01, 0x30, 0x00, "Hardest"						},
465 
466 	{0   , 0xfe, 0   ,    2, "High Speed Mode"				},
467 	{0x12, 0x01, 0x80, 0x00, "Off"							},
468 	{0x12, 0x01, 0x80, 0x80, "On"							},
469 };
470 
471 STDDIPINFO(Bloxeedu)
472 
473 static struct BurnDIPInfo ColumnsDIPList[]=
474 {
475 	{0x11, 0xff, 0xff, 0xff, NULL							},
476 	{0x12, 0xff, 0xff, 0xfd, NULL							},
477 
478 	coinage_dips(0x11)
479 
480 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
481 	{0x12, 0x01, 0x02, 0x02, "Off"							},
482 	{0x12, 0x01, 0x02, 0x00, "On"							},
483 
484 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
485 	{0x12, 0x01, 0x30, 0x00, "Easiest"						},
486 	{0x12, 0x01, 0x30, 0x10, "Easy"							},
487 	{0x12, 0x01, 0x30, 0x30, "Normal"						},
488 	{0x12, 0x01, 0x30, 0x20, "Hard"							},
489 };
490 
491 STDDIPINFO(Columns)
492 
493 static struct BurnDIPInfo Columns2DIPList[]=
494 {
495 	{0x11, 0xff, 0xff, 0xff, NULL							},
496 	{0x12, 0xff, 0xff, 0xfd, NULL							},
497 
498 	coinage_dips(0x11)
499 
500 	{0   , 0xfe, 0   ,    2, "Cabinet"						},
501 	{0x12, 0x01, 0x01, 0x01, "Upright"						},
502 	{0x12, 0x01, 0x01, 0x00, "Cocktail"						},
503 
504 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
505 	{0x12, 0x01, 0x02, 0x02, "Off"							},
506 	{0x12, 0x01, 0x02, 0x00, "On"							},
507 
508 	{0   , 0xfe, 0   ,    4, "VS. Mode Credits/Match"		},
509 	{0x12, 0x01, 0x0c, 0x0c, "1"							},
510 	{0x12, 0x01, 0x0c, 0x08, "2"							},
511 	{0x12, 0x01, 0x0c, 0x04, "3"							},
512 	{0x12, 0x01, 0x0c, 0x00, "4"							},
513 
514 	{0   , 0xfe, 0   ,    4, "Flash Mode Difficulty"		},
515 	{0x12, 0x01, 0x30, 0x20, "Easy"							},
516 	{0x12, 0x01, 0x30, 0x30, "Normal"						},
517 	{0x12, 0x01, 0x30, 0x10, "Hard"							},
518 	{0x12, 0x01, 0x30, 0x00, "Hardest"						},
519 };
520 
521 STDDIPINFO(Columns2)
522 
523 static struct BurnDIPInfo TfrceacDIPList[]=
524 {
525 	{0x15, 0xff, 0xff, 0xff, NULL							},
526 	{0x16, 0xff, 0xff, 0xfd, NULL							},
527 
528 	coinage_dips(0x15)
529 
530 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
531 	{0x16, 0x01, 0x01, 0x01, "1"							},
532 	{0x16, 0x01, 0x01, 0x00, "2"							},
533 
534 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
535 	{0x16, 0x01, 0x02, 0x02, "Off"							},
536 	{0x16, 0x01, 0x02, 0x00, "On"							},
537 
538 	{0   , 0xfe, 0   ,    4, "Lives"						},
539 	{0x16, 0x01, 0x0c, 0x00, "2"							},
540 	{0x16, 0x01, 0x0c, 0x0c, "3"							},
541 	{0x16, 0x01, 0x0c, 0x08, "4"							},
542 	{0x16, 0x01, 0x0c, 0x04, "5"							},
543 
544 	{0   , 0xfe, 0   ,    4, "Bonus Life"					},
545 	{0x16, 0x01, 0x30, 0x10, "10k, 70k, 150k"				},
546 	{0x16, 0x01, 0x30, 0x30, "20k, 100k, 200k"				},
547 	{0x16, 0x01, 0x30, 0x20, "40k, 150k, 300k"				},
548 	{0x16, 0x01, 0x30, 0x00, "None"							},
549 
550 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
551 	{0x16, 0x01, 0xc0, 0x80, "Easy"							},
552 	{0x16, 0x01, 0xc0, 0xc0, "Medium"						},
553 	{0x16, 0x01, 0xc0, 0x40, "Hard"							},
554 	{0x16, 0x01, 0xc0, 0x00, "Hardest"						},
555 };
556 
557 STDDIPINFO(Tfrceac)
558 
559 static struct BurnDIPInfo BorenchDIPList[]=
560 {
561 	{0x13, 0xff, 0xff, 0xff, NULL							},
562 	{0x14, 0xff, 0xff, 0xfd, NULL							},
563 
564 	coinage_dips(0x13)
565 
566 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
567 	{0x14, 0x01, 0x01, 0x01, "1"							},
568 	{0x14, 0x01, 0x01, 0x00, "2"							},
569 
570 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
571 	{0x14, 0x01, 0x02, 0x02, "Off"							},
572 	{0x14, 0x01, 0x02, 0x00, "On"							},
573 
574 	{0   , 0xfe, 0   ,    4, "Lives 1P Mode"				},
575 	{0x14, 0x01, 0x0c, 0x00, "1"							},
576 	{0x14, 0x01, 0x0c, 0x0c, "2"							},
577 	{0x14, 0x01, 0x0c, 0x08, "3"							},
578 	{0x14, 0x01, 0x0c, 0x04, "4"							},
579 
580 	{0   , 0xfe, 0   ,    4, "Lives 2P Mode"				},
581 	{0x14, 0x01, 0x30, 0x00, "2"							},
582 	{0x14, 0x01, 0x30, 0x30, "3"							},
583 	{0x14, 0x01, 0x30, 0x20, "4"							},
584 	{0x14, 0x01, 0x30, 0x10, "5"							},
585 
586 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
587 	{0x14, 0x01, 0xc0, 0x80, "Easy"							},
588 	{0x14, 0x01, 0xc0, 0xc0, "Medium"						},
589 	{0x14, 0x01, 0xc0, 0x40, "Hard"							},
590 	{0x14, 0x01, 0xc0, 0x00, "Hardest"						},
591 };
592 
593 STDDIPINFO(Borench)
594 
595 static struct BurnDIPInfo StkclmnsDIPList[]=
596 {
597 	{0x13, 0xff, 0xff, 0xff, NULL							},
598 	{0x14, 0xff, 0xff, 0xfd, NULL							},
599 
600 	coinage_dips(0x13)
601 
602 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
603 	{0x14, 0x01, 0x03, 0x02, "Easy"							},
604 	{0x14, 0x01, 0x03, 0x03, "Medium"						},
605 	{0x14, 0x01, 0x03, 0x01, "Hard"							},
606 	{0x14, 0x01, 0x03, 0x00, "Hardest"						},
607 
608 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
609 	{0x14, 0x01, 0x02, 0x02, "Off"							},
610 	{0x14, 0x01, 0x02, 0x00, "On"							},
611 
612 	{0   , 0xfe, 0   ,    2, "Match Mode Prices"			},
613 	{0x14, 0x01, 0x0c, 0x08, "1"							},
614 	{0x14, 0x01, 0x0c, 0x09, "2"							},
615 };
616 
617 STDDIPINFO(Stkclmns)
618 
619 static struct BurnDIPInfo RibbitDIPList[]=
620 {
621 	{0x0f, 0xff, 0xff, 0xff, NULL							},
622 	{0x10, 0xff, 0xff, 0xf5, NULL							},
623 
624 	coinage_dips(0xf)
625 
626 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
627 	{0x10, 0x01, 0x01, 0x01, "1"							},
628 	{0x10, 0x01, 0x01, 0x00, "2"							},
629 
630 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
631 	{0x10, 0x01, 0x02, 0x02, "Off"							},
632 	{0x10, 0x01, 0x02, 0x00, "On"							},
633 
634 	{0   , 0xfe, 0   ,    4, "Lives"						},
635 	{0x10, 0x01, 0x0c, 0x08, "1"							},
636 	{0x10, 0x01, 0x0c, 0x0c, "2"							},
637 	{0x10, 0x01, 0x0c, 0x04, "3"							},
638 	{0x10, 0x01, 0x0c, 0x00, "5"							},
639 
640 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
641 	{0x10, 0x01, 0x30, 0x20, "Easy"							},
642 	{0x10, 0x01, 0x30, 0x30, "Normal"						},
643 	{0x10, 0x01, 0x30, 0x10, "Hard"							},
644 	{0x10, 0x01, 0x30, 0x00, "Hardest"						},
645 };
646 
647 STDDIPINFO(Ribbit)
648 
649 static struct BurnDIPInfo RibbitjDIPList[]=
650 {
651 	{0x0f, 0xff, 0xff, 0xff, NULL							},
652 	{0x10, 0xff, 0xff, 0xf5, NULL							},
653 
654 	coinage_dips(0xf)
655 
656 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
657 	{0x10, 0x01, 0x01, 0x01, "1"							},
658 	{0x10, 0x01, 0x01, 0x00, "2"							},
659 
660 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
661 	{0x10, 0x01, 0x02, 0x02, "Off"							},
662 	{0x10, 0x01, 0x02, 0x00, "On"							},
663 
664 	{0   , 0xfe, 0   ,    4, "Lives"						},
665 	{0x10, 0x01, 0x0c, 0x04, "1"							},
666 	{0x10, 0x01, 0x0c, 0x08, "2"							},
667 	{0x10, 0x01, 0x0c, 0x0c, "3"							},
668 	{0x10, 0x01, 0x0c, 0x00, "5"							},
669 
670 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
671 	{0x10, 0x01, 0x30, 0x20, "Easy"							},
672 	{0x10, 0x01, 0x30, 0x30, "Normal"						},
673 	{0x10, 0x01, 0x30, 0x10, "Hard"							},
674 	{0x10, 0x01, 0x30, 0x00, "Hardest"						},
675 };
676 
677 STDDIPINFO(Ribbitj)
678 
679 
680 static struct BurnDIPInfo TwinsquaDIPList[]=
681 {
682 	{0x0b, 0xff, 0xff, 0xff, NULL							},
683 	{0x0c, 0xff, 0xff, 0xfd, NULL							},
684 
685 	coinage_dips(0x0b)
686 
687 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
688 	{0x0c, 0x01, 0x01, 0x01, "1"							},
689 	{0x0c, 0x01, 0x01, 0x00, "2"							},
690 
691 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
692 	{0x0c, 0x01, 0x02, 0x02, "Off"							},
693 	{0x0c, 0x01, 0x02, 0x00, "On"							},
694 
695 	{0   , 0xfe, 0   ,    2, "Buy In"						},
696 	{0x0c, 0x01, 0x04, 0x04, "Off"							},
697 	{0x0c, 0x01, 0x04, 0x00, "On"							},
698 
699 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
700 	{0x0c, 0x01, 0x18, 0x10, "Easy"							},
701 	{0x0c, 0x01, 0x18, 0x18, "Medium"						},
702 	{0x0c, 0x01, 0x18, 0x08, "Hard"							},
703 	{0x0c, 0x01, 0x18, 0x00, "Hardest"						},
704 
705 	{0   , 0xfe, 0   ,    2, "Seat Type"					},
706 	{0x0c, 0x01, 0x20, 0x20, "Normal"						},
707 	{0x0c, 0x01, 0x20, 0x00, "Moving"						},
708 };
709 
710 STDDIPINFO(Twinsqua)
711 
712 static struct BurnDIPInfo SoniccarDIPList[]=
713 {
714 	{0x0c, 0xff, 0xff, 0xff, NULL							},
715 	{0x0d, 0xff, 0xff, 0xff, NULL							},
716 
717 	coinage_dips(0x0c)
718 
719 	{0   , 0xfe, 0   ,    4, "Demo Sound Interval"		},
720 	{0x0d, 0x01, 0x03, 0x00, "Off"							},
721 	{0x0d, 0x01, 0x03, 0x01, "Every 4 Minutes"				},
722 	{0x0d, 0x01, 0x03, 0x02, "Every 2 Minutes"				},
723 	{0x0d, 0x01, 0x03, 0x03, "On"							},
724 
725 	{0   , 0xfe, 0   ,    2, "Lighting Time"				},
726 	{0x0d, 0x01, 0x04, 0x04, "Advertise & Playtime"			},
727 	{0x0d, 0x01, 0x04, 0x00, "Playtime Only"				},
728 
729 	{0   , 0xfe, 0   ,    2, "Light"						},
730 	{0x0d, 0x01, 0x08, 0x00, "Off"							},
731 	{0x0d, 0x01, 0x08, 0x08, "On"							},
732 
733 	{0   , 0xfe, 0   ,    2, "Screen Display"				},
734 	{0x0d, 0x01, 0x10, 0x10, "Insert 100-400 Yen"			},
735 	{0x0d, 0x01, 0x10, 0x00, "Insert Money"					},
736 };
737 
738 STDDIPINFO(Soniccar)
739 
740 static struct BurnDIPInfo SsonicbrDIPList[]=
741 {
742 	{0x11, 0xff, 0xff, 0xff, NULL							},
743 	{0x12, 0xff, 0xff, 0xff, NULL							},
744 
745 	coinage_dips(0x11)
746 
747 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
748 	{0x12, 0x01, 0x01, 0x01, "On"							},
749 	{0x12, 0x01, 0x01, 0x00, "Off"							},
750 
751 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
752 	{0x12, 0x01, 0x06, 0x04, "Easy"							},
753 	{0x12, 0x01, 0x06, 0x06, "Medium"						},
754 	{0x12, 0x01, 0x06, 0x02, "Hard"							},
755 	{0x12, 0x01, 0x06, 0x00, "Hardest"						},
756 };
757 
758 STDDIPINFO(Ssonicbr)
759 
760 static struct BurnDIPInfo OopartsDIPList[]=
761 {
762 	{0x15, 0xff, 0xff, 0xff, NULL							},
763 	{0x16, 0xff, 0xff, 0xfe, NULL							},
764 
765 	coinage_dips(0x15)
766 
767 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
768 	{0x16, 0x01, 0x01, 0x01, "Off"							},
769 	{0x16, 0x01, 0x01, 0x00, "On"							},
770 
771 	{0   , 0xfe, 0   ,    4, "Lives"						},
772 	{0x16, 0x01, 0x06, 0x04, "2"							},
773 	{0x16, 0x01, 0x06, 0x06, "3"							},
774 	{0x16, 0x01, 0x06, 0x02, "4"							},
775 	{0x16, 0x01, 0x06, 0x00, "5"							},
776 
777 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
778 	{0x16, 0x01, 0x18, 0x10, "Easy"							},
779 	{0x16, 0x01, 0x18, 0x18, "Medium"						},
780 	{0x16, 0x01, 0x18, 0x08, "Hard"							},
781 	{0x16, 0x01, 0x18, 0x00, "Hardest"						},
782 
783 	{0   , 0xfe, 0   ,    4, "Region"						},
784 	{0x16, 0x01, 0x60, 0x60, "Japan"						},
785 	{0x16, 0x01, 0x60, 0x40, "USA"							},
786 	{0x16, 0x01, 0x60, 0x20, "Export"						},
787 	{0x16, 0x01, 0x60, 0x00, "Export"						},
788 };
789 
790 STDDIPINFO(Ooparts)
791 
792 static struct BurnDIPInfo PuyoDIPList[]=
793 {
794 	{0x11, 0xff, 0xff, 0xff, NULL							},
795 	{0x12, 0xff, 0xff, 0xfd, NULL							},
796 
797 	coinage_dips(0x11)
798 
799 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
800 	{0x12, 0x01, 0x02, 0x02, "Off"							},
801 	{0x12, 0x01, 0x02, 0x00, "On"							},
802 
803 	{0   , 0xfe, 0   ,    2, "VS. Mode Credits/Match"		},
804 	{0x12, 0x01, 0x04, 0x04, "1"							},
805 	{0x12, 0x01, 0x04, 0x00, "3"							},
806 
807 	{0   , 0xfe, 0   ,    4, "1P Mode Difficulty"			},
808 	{0x12, 0x01, 0x18, 0x10, "Easy"							},
809 	{0x12, 0x01, 0x18, 0x18, "Medium"						},
810 	{0x12, 0x01, 0x18, 0x08, "Hard"							},
811 	{0x12, 0x01, 0x18, 0x00, "Hardest"						},
812 
813 	{0   , 0xfe, 0   ,    2, "Moving Seat"					},
814 	{0x12, 0x01, 0x80, 0x80, "No Use"						},
815 	{0x12, 0x01, 0x80, 0x00, "In Use"						},
816 };
817 
818 STDDIPINFO(Puyo)
819 
820 static struct BurnDIPInfo IchirDIPList[]=
821 {
822 	{0x11, 0xff, 0xff, 0xff, NULL							},
823 	{0x12, 0xff, 0xff, 0xfe, NULL							},
824 
825 	coinage_dips(0x11)
826 
827 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
828 	{0x12, 0x01, 0x01, 0x01, "Off"							},
829 	{0x12, 0x01, 0x01, 0x00, "On"							},
830 
831 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
832 	{0x12, 0x01, 0x06, 0x04, "Easy"							},
833 	{0x12, 0x01, 0x06, 0x06, "Medium"						},
834 	{0x12, 0x01, 0x06, 0x02, "Hard"							},
835 	{0x12, 0x01, 0x06, 0x00, "Hardest"						},
836 };
837 
838 STDDIPINFO(Ichir)
839 
840 static struct BurnDIPInfo WwmarineDIPList[]=
841 {
842 	{0x09, 0xff, 0xff, 0xff, NULL							},
843 	{0x0a, 0xff, 0xff, 0xfc, NULL							},
844 
845 	coinage_dips(0x09)
846 
847 	{0   , 0xfe, 0   ,    4, "Demo Sound Interval"			},
848 	{0x0a, 0x01, 0x03, 0x00, "Off"							},
849 	{0x0a, 0x01, 0x03, 0x01, "Every 3 Demo Cycles"			},
850 	{0x0a, 0x01, 0x03, 0x02, "Every 2 Demo Cycles"			},
851 	{0x0a, 0x01, 0x03, 0x03, "On"							},
852 
853 	{0   , 0xfe, 0   ,    2, "Capsule Mode"					},
854 	{0x0a, 0x01, 0x04, 0x00, "Off"							},
855 	{0x0a, 0x01, 0x04, 0x04, "On"							},
856 
857 	{0   , 0xfe, 0   ,    2, "Credit Mode"					},
858 	{0x0a, 0x01, 0x10, 0x10, "Off"							},
859 	{0x0a, 0x01, 0x10, 0x00, "On"							},
860 };
861 
862 STDDIPINFO(Wwmarine)
863 
864 static struct BurnDIPInfo SonicfgtDIPList[]=
865 {
866 	{0x09, 0xff, 0xff, 0xff, NULL							},
867 	{0x0a, 0xff, 0xff, 0xff, NULL							},
868 
869 	coinage_dips(0x09)
870 
871 	{0   , 0xfe, 0   ,    2, "Credit Mode"					},
872 	{0x0a, 0x01, 0x01, 0x01, "Off"							},
873 	{0x0a, 0x01, 0x01, 0x00, "On"							},
874 };
875 
876 STDDIPINFO(Sonicfgt)
877 
878 static struct BurnDIPInfo PotopotoDIPList[]=
879 {
880 	{0x11, 0xff, 0xff, 0xff, NULL							},
881 	{0x12, 0xff, 0xff, 0xfd, NULL							},
882 
883 	coinage_dips(0x11)
884 
885 	{0   , 0xfe, 0   ,    2, "Credits to Start"				},
886 	{0x12, 0x01, 0x01, 0x01, "1"							},
887 	{0x12, 0x01, 0x01, 0x00, "2"							},
888 
889 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
890 	{0x12, 0x01, 0x02, 0x02, "Off"							},
891 	{0x12, 0x01, 0x02, 0x00, "On"							},
892 
893 	{0   , 0xfe, 0   ,    2, "Coin Chute Type"				},
894 	{0x12, 0x01, 0x04, 0x04, "Common"						},
895 	{0x12, 0x01, 0x04, 0x00, "Individual"					},
896 
897 	{0   , 0xfe, 0   ,    2, "Credits to Continue"			},
898 	{0x12, 0x01, 0x08, 0x08, "1"							},
899 	{0x12, 0x01, 0x08, 0x00, "2"							},
900 
901 	{0   , 0xfe, 0   ,    2, "Buy-In"						},
902 	{0x12, 0x01, 0x10, 0x10, "No"							},
903 	{0x12, 0x01, 0x10, 0x00, "Yes"							},
904 
905 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
906 	{0x12, 0x01, 0x60, 0x40, "Easy"							},
907 	{0x12, 0x01, 0x60, 0x60, "Medium"						},
908 	{0x12, 0x01, 0x60, 0x20, "Hard"							},
909 	{0x12, 0x01, 0x60, 0x00, "Hardest"						},
910 
911 	{0   , 0xfe, 0   ,    2, "Moving Seat"					},
912 	{0x12, 0x01, 0x80, 0x80, "No Use"						},
913 	{0x12, 0x01, 0x80, 0x00, "In Use"						},
914 };
915 
916 STDDIPINFO(Potopoto)
917 
918 static struct BurnDIPInfo Puyopuy2DIPList[]=
919 {
920 	{0x13, 0xff, 0xff, 0xff, NULL							},
921 	{0x14, 0xff, 0xff, 0xfd, NULL							},
922 
923 	coinage_dips(0x13)
924 
925 	{0   , 0xfe, 0   ,    2, "Rannyu Off Button"			},
926 	{0x14, 0x01, 0x01, 0x01, "Use"							},
927 	{0x14, 0x01, 0x01, 0x00, "No Use"						},
928 
929 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
930 	{0x14, 0x01, 0x02, 0x02, "Off"							},
931 	{0x14, 0x01, 0x02, 0x00, "On"							},
932 
933 	{0   , 0xfe, 0   ,    2, "Turn Direction"				},
934 	{0x14, 0x01, 0x04, 0x04, "1:Right  2:Left"				},
935 	{0x14, 0x01, 0x04, 0x00, "1:Left  2:Right"				},
936 
937 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
938 	{0x14, 0x01, 0x18, 0x10, "Easy"							},
939 	{0x14, 0x01, 0x18, 0x18, "Medium"						},
940 	{0x14, 0x01, 0x18, 0x08, "Hard"							},
941 	{0x14, 0x01, 0x18, 0x00, "Hardest"						},
942 
943 	{0   , 0xfe, 0   ,    4, "VS Mode Match/1 Play"			},
944 	{0x14, 0x01, 0x60, 0x60, "1"							},
945 	{0x14, 0x01, 0x60, 0x40, "2"							},
946 	{0x14, 0x01, 0x60, 0x20, "3"							},
947 	{0x14, 0x01, 0x60, 0x00, "4"							},
948 
949 	{0   , 0xfe, 0   ,    2, "Battle Start credit"			},
950 	{0x14, 0x01, 0x80, 0x00, "1"							},
951 	{0x14, 0x01, 0x80, 0x80, "2"							},
952 };
953 
954 STDDIPINFO(Puyopuy2)
955 
956 static struct BurnDIPInfo ZunkyouDIPList[]=
957 {
958 	{0x13, 0xff, 0xff, 0xff, NULL							},
959 	{0x14, 0xff, 0xff, 0xef, NULL							},
960 
961 	coinage_dips(0x13)
962 
963 	{0   , 0xfe, 0   ,    2, "Game Difficulty 1"			},
964 	{0x14, 0x01, 0x01, 0x01, "Medium"						},
965 	{0x14, 0x01, 0x01, 0x00, "Hard"							},
966 
967 	{0   , 0xfe, 0   ,    2, "Game Difficulty 2"			},
968 	{0x14, 0x01, 0x02, 0x02, "Medium"						},
969 	{0x14, 0x01, 0x02, 0x00, "Hard"							},
970 
971 	{0   , 0xfe, 0   ,    4, "Lives"						},
972 	{0x14, 0x01, 0x0c, 0x08, "1"							},
973 	{0x14, 0x01, 0x0c, 0x04, "2"							},
974 	{0x14, 0x01, 0x0c, 0x0c, "3"							},
975 	{0x14, 0x01, 0x0c, 0x00, "5"							},
976 
977 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
978 	{0x14, 0x01, 0x10, 0x10, "Off"							},
979 	{0x14, 0x01, 0x10, 0x00, "On"							},
980 };
981 
982 STDDIPINFO(Zunkyou)
983 
984 static struct BurnDIPInfo HeadonchDIPList[]=
985 {
986 	{0x11, 0xff, 0xff, 0xff, NULL							},
987 	{0x12, 0xff, 0xff, 0xfe, NULL							},
988 
989 	coinage_dips(0x11)
990 
991 	{0   , 0xfe, 0   ,    2, "Demo Sounds"					},
992 	{0x12, 0x01, 0x01, 0x01, "Off"							},
993 	{0x12, 0x01, 0x01, 0x00, "On"							},
994 
995 	{0   , 0xfe, 0   ,    4, "Difficulty"					},
996 	{0x12, 0x01, 0x06, 0x04, "Easy"							},
997 	{0x12, 0x01, 0x06, 0x06, "Medium"						},
998 	{0x12, 0x01, 0x06, 0x02, "Hard"							},
999 	{0x12, 0x01, 0x06, 0x00, "Hardest"						},
1000 
1001 	{0   , 0xfe, 0   ,    4, "Lives"						},
1002 	{0x12, 0x01, 0x18, 0x10, "2"							},
1003 	{0x12, 0x01, 0x18, 0x18, "3"							},
1004 	{0x12, 0x01, 0x18, 0x08, "4"							},
1005 	{0x12, 0x01, 0x18, 0x00, "5"							},
1006 };
1007 
STDDIPINFO(Headonch)1008 STDDIPINFO(Headonch)
1009 
1010 static UINT16 palette_read(UINT16 offset)
1011 {
1012 	offset = (offset >> 1) & 0x1ff;
1013 	UINT16 *ram = (UINT16*)DrvPalRAM;
1014 
1015 	if (alt_palette_mode)
1016 		offset = ((offset << 1) & 0x100) | ((offset << 2) & 0x80) | ((~offset >> 2) & 0x40) | ((offset >> 1) & 0x20) | (offset & 0x1f);
1017 
1018 	return ram[offset + palette_bank * 0x200];
1019 }
1020 
palette_update(UINT16 offset)1021 static void palette_update(UINT16 offset)
1022 {
1023 	UINT16 *ram = (UINT16*)DrvPalRAM;
1024 
1025 	INT32 data = ram[offset];
1026 
1027 	INT32 r = ((data << 1) & 0x1e) | ((data >> 12) & 0x01);
1028 	INT32 g = ((data >> 3) & 0x1e) | ((data >> 13) & 0x01);
1029 	INT32 b = ((data >> 7) & 0x1e) | ((data >> 14) & 0x01);
1030 	DrvPalette[offset + 0x0000] = BurnHighCol(pal5bit(r), pal5bit(g), pal5bit(b), 0);
1031 
1032 	INT32 tmpr = r >> 1;
1033 	INT32 tmpg = g >> 1;
1034 	INT32 tmpb = b >> 1;
1035 
1036 	DrvPalette[offset + 0x0800] = BurnHighCol(pal5bit(tmpr), pal5bit(tmpg), pal5bit(tmpb), 0);
1037 	DrvPalette[offset + 0x1800] = BurnHighCol(pal5bit(tmpr), pal5bit(tmpg), pal5bit(tmpb), 0); // shadow + hilight = shadow?
1038 
1039 	tmpr = tmpr | 0x10;
1040 	tmpg = tmpg | 0x10;
1041 	tmpb = tmpb | 0x10;
1042 
1043 	DrvPalette[offset + 0x1000] = BurnHighCol(pal5bit(tmpr), pal5bit(tmpg), pal5bit(tmpb), 0);
1044 }
1045 
palette_write(UINT16 offset,UINT16 data,UINT16 mem_mask)1046 static void palette_write(UINT16 offset, UINT16 data, UINT16 mem_mask)
1047 {
1048 	offset = (offset >> 1) & 0x1ff;
1049 
1050 	if (alt_palette_mode)
1051 		offset = ((offset << 1) & 0x100) | ((offset << 2) & 0x80) | ((~offset >> 2) & 0x40) | ((offset >> 1) & 0x20) | (offset & 0x1f);
1052 	offset += palette_bank * 0x200;
1053 
1054 	UINT16 *ram = (UINT16*)DrvPalRAM;
1055 
1056 	ram[offset] = (ram[offset] & ~mem_mask) | (data & mem_mask);
1057 
1058 	palette_update(offset);
1059 }
1060 
recompute_palette_tables()1061 static void recompute_palette_tables()
1062 {
1063 	for (INT32 i = 0; i < 4; i++)
1064 	{
1065 		INT32 bgpal = 0x000 + bg_palbase * 0x40 + i * 0x10;
1066 		INT32 sppal = 0x100 + sp_palbase * 0x40 + i * 0x10;
1067 
1068 		if (!alt_palette_mode)
1069 		{
1070 			SegaC2BgPalLookup[i] = 0x200 * palette_bank + bgpal;
1071 			SegaC2SpPalLookup[i] = 0x200 * palette_bank + sppal;
1072 		}
1073 		else
1074 		{
1075 			SegaC2BgPalLookup[i] = 0x200 * palette_bank + ((bgpal << 1) & 0x180) + ((~bgpal >> 2) & 0x40) + (bgpal & 0x30);
1076 			SegaC2SpPalLookup[i] = 0x200 * palette_bank + ((~sppal << 2) & 0x100) + ((sppal << 2) & 0x80) + ((~sppal >> 2) & 0x40) + ((sppal >> 2) & 0x20) + (sppal & 0x10);
1077 		}
1078 	}
1079 }
1080 
protection_write(UINT8 data)1081 static void protection_write(UINT8 data)
1082 {
1083 	if (is_tfrceacb) return;
1084 
1085 	INT32 new_sp_palbase = (data >> 2) & 3;
1086 	INT32 new_bg_palbase = data & 3;
1087 	INT32 table_index = (prot_write_buf << 4) | prot_read_buf;
1088 
1089 	prot_write_buf = data & 0x0f;
1090 	prot_read_buf = protection_read_cb(table_index);
1091 
1092 	if (new_sp_palbase != sp_palbase || new_bg_palbase != bg_palbase)
1093 	{
1094 		sp_palbase = new_sp_palbase;
1095 		bg_palbase = new_bg_palbase;
1096 		//bprintf(0, _T("sp %x  bg %x  palbases.  (scanline: %d\tframe: %d)\n"), sp_palbase, bg_palbase, Scanline, nCurrentFrame);
1097 		recompute_palette_tables();
1098 	}
1099 }
1100 
io_porth_write(UINT8 data)1101 static void io_porth_write(UINT8 data)
1102 {
1103 	INT32 newbank = data & 3;
1104 	if (newbank != palette_bank)
1105 	{
1106 		//bprintf(0, _T("palette bank: %x  (scanline: %d\tframe: %d)\n"), newbank, Scanline, nCurrentFrame);
1107 		palette_bank = newbank;
1108 		recompute_palette_tables();
1109 	}
1110 	if (sound_rom_length)
1111 	{
1112 		sound_bank = (data >> 2) & (((sound_rom_length) / 0x20000) - 1);
1113 		memcpy (DrvSndROM + 0x80000, DrvSndROM + (sound_bank * 0x20000), 0x20000);
1114 	}
1115 }
1116 
sega_315_5296_read(UINT8 offset)1117 static UINT8 sega_315_5296_read(UINT8 offset)
1118 {
1119 	if (offset <= 7) {
1120 		if (dir & dir_override & (1 << offset)) {
1121 			return output_latch[offset];
1122 		}
1123 
1124 		if (offset == 2) {
1125 			if (sound_rom_length == 0) return 0xff;
1126 			return UPD7759BusyRead(0) ? 0xff : 0xbf;
1127 		}
1128 
1129 		return DrvInputs[offset];
1130 	}
1131 	if (offset <= 0x0b)
1132 	{
1133 		char *s = "SEGA";
1134 		return s[offset - 8];
1135 	}
1136 	if (offset & 1) {
1137 		return dir;
1138 	} else {
1139 		return iocnt;
1140 	}
1141 
1142 	return 0xff;
1143 }
1144 
sega_315_5296_write(UINT8 offset,UINT8 data)1145 void sega_315_5296_write(UINT8 offset, UINT8 data)
1146 {
1147 	offset &= 0x3f;
1148 	if (offset <= 0x07) {
1149 		if (dir & (1 << offset)) {
1150 		//	if (offset == 0x03) return; // port D (coin counters)
1151 			if (offset == 0x07) io_porth_write(data);
1152 		}
1153 		output_latch[offset] = data;
1154 		return;
1155 	}
1156 	if (offset == 0x0e) {
1157 		//	for (INT32 i = 0; i < 3; i++) out_cnt_callback[i]((data >> i) & 1);
1158 		if (sound_rom_length) {
1159 			UPD7759ResetWrite(0, (data >> 1) & 1); // cnt1
1160 		}
1161 		iocnt = data;
1162 		return;
1163 	}
1164 	if (offset == 0x0f) {
1165 		for (INT32 i = 0; i < 8; i++) {
1166 			if ((dir ^ data) & (1 << i)) {
1167 		//		if (i == 0x03) continue; // port A (coin counters)
1168 				if (i == 0x07) io_porth_write((data & (1 << i)) ? output_latch[i] : 0);
1169 			}
1170 		}
1171 		dir = data;
1172 		return;
1173 	}
1174 }
1175 
1176 //---------------------------------------------------------------
1177 // Megadrive Video Port Read Write
1178 //---------------------------------------------------------------
1179 
VideoWrite128(UINT32 a,UINT16 d)1180 static void VideoWrite128(UINT32 a, UINT16 d)
1181 {
1182   a = ((a & 2) >> 1) | ((a & 0x400) >> 9) | (a & 0x3FC) | ((a & 0x1F800) >> 1);
1183   ((UINT8 *)RamVid)[a] = d;
1184 }
1185 
GetDmaLength()1186 static INT32 GetDmaLength()
1187 {
1188   INT32 len = 0;
1189   // 16-bit words to transfer:
1190   len  = RamVReg->reg[0x13];
1191   len |= RamVReg->reg[0x14]<<8;
1192   // Charles MacDonald:
1193   len = ((len - 1) & 0xffff) + 1;
1194   return len;
1195 }
1196 
1197 // dma2vram settings are just hacks to unglitch Legend of Galahad (needs <= 104 to work)
1198 // same for Outrunners (92-121, when active is set to 24)
1199 // 96 is VR hack
1200 static const INT32 dma_timings[] = {
1201   167, 167, 166,  83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy
1202   103, 205, 204, 102, // vblank: 40cell:
1203   16,   16,  15,   8, // active: 32cell:
1204   24,   18,  17,   9  // ...
1205 };
1206 
1207 static const INT32 dma_bsycles[] = {
1208   (488<<8)/167, (488<<8)/167, (488<<8)/166, (488<<8)/83,
1209   (488<<8)/103, (488<<8)/233, (488<<8)/204, (488<<8)/102,
1210   (488<<8)/16,  (488<<8)/16,  (488<<8)/15,  (488<<8)/8,
1211   (488<<8)/24,  (488<<8)/18,  (488<<8)/17,  (488<<8)/9
1212 };
1213 
CheckDMA(void)1214 static UINT32 CheckDMA(void)
1215 {
1216   INT32 burn = 0, xfers_can, dma_op = RamVReg->reg[0x17]>>6; // see gens for 00 and 01 modes
1217   INT32 xfers = dma_xfers;
1218   INT32 dma_op1;
1219 
1220   if(!(dma_op&2)) dma_op = (RamVReg->type == 1) ? 0 : 1; // setting dma_timings offset here according to Gens
1221   dma_op1 = dma_op;
1222   if(RamVReg->reg[12] & 1) dma_op |= 4; // 40 cell mode?
1223   if(!(RamVReg->status&8)&&(RamVReg->reg[1]&0x40)) dma_op|=8; // active display?
1224   xfers_can = dma_timings[dma_op];
1225 
1226   if(xfers <= xfers_can)
1227   {
1228     if(dma_op&2) RamVReg->status&=~2; // dma no longer busy
1229     else {
1230       burn = xfers * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division..
1231     }
1232     dma_xfers = 0;
1233   } else {
1234     if(!(dma_op&2)) burn = 488;
1235     dma_xfers -= xfers_can;
1236   }
1237 
1238   //elprintf(EL_VDPDMA, "~Dma %i op=%i can=%i burn=%i [%i]", Pico.m.dma_xfers, dma_op1, xfers_can, burn, SekCyclesDone());
1239   //dprintf("~aim: %i, cnt: %i", SekCycleAim, SekCycleCnt);
1240   //bprintf(0, _T("burn[%d]"), burn);
1241   return burn;
1242 }
1243 
DMABURN()1244 static INT32 DMABURN() { // add cycles to the 68k cpu
1245     if (dma_xfers) {
1246         return CheckDMA();
1247     } else return 0;
1248 }
1249 
DmaSlow(INT32 len)1250 static void DmaSlow(INT32 len)
1251 {
1252 	UINT16 *pd=0, *pdend, *r;
1253 	UINT32 a = RamVReg->addr, a2, d;
1254 	UINT8 inc = RamVReg->reg[0xf];
1255 	UINT32 source;
1256 	UINT32 fromrom = 0;
1257 
1258 	source  = RamVReg->reg[0x15] <<  1;
1259 	source |= RamVReg->reg[0x16] <<  9;
1260 	source |= RamVReg->reg[0x17] << 17;
1261 
1262   //dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc,
1263   //         (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone());
1264 
1265 	dma_xfers += len;
1266 
1267 	INT32 dmab = CheckDMA();
1268 	m68k_ICount -= dmab;
1269 
1270 #ifdef CYCDBUG
1271 //	bprintf(0, _T("dma @ ln %d cyc %d, burnt: %d.\n"), Scanline, SekCyclesLine(), dmab);
1272 #endif
1273 	//SekCyclesBurnRun(dmab);
1274 
1275 	const INT32 RomSize = 0x200000;
1276 
1277 	if ((source & 0xe00000) == 0xe00000) { // RAM
1278 		pd    = (UINT16 *)(Drv68KRAM + (source & 0xfffe));
1279 		pdend = (UINT16 *)(Drv68KRAM + 0x10000);
1280 	} else if( source < RomSize) {	// ROM
1281 		fromrom = 1;
1282 		source &= ~1;
1283 		pd    = (UINT16 *)(Drv68KROM + source);
1284 		pdend = (UINT16 *)(Drv68KROM + RomSize);
1285 	} else return; // Invalid source address
1286 
1287 	// overflow protection, might break something..
1288 	if (len > pdend - pd) {
1289 		len = pdend - pd;
1290 		//bprintf(0, _T("DmaSlow() overflow(!).\n"));
1291 	}
1292 
1293 	switch ( RamVReg->type ) {
1294 	case 1: // vram
1295 		r = RamVid;
1296 		for(; len; len--) {
1297 			d = *pd++;
1298 			if(a&1) d=(d<<8)|(d>>8);
1299 			r[a>>1] = (UINT16)d; // will drop the upper bits
1300 			// AutoIncrement
1301 			a = (UINT16)(a+inc);
1302 			// didn't src overlap?
1303 			//if(pd >= pdend) pd -= 0x8000; // should be good for RAM, bad for ROM
1304 		}
1305 
1306 		RamVReg->rendstatus |= PDRAW_DIRTY_SPRITES;
1307 		break;
1308 
1309 	case 3: // cram
1310 		//dprintf("DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%i|%i]", Pico.video.type, source, a, len, inc,
1311 		//         (Pico.video.status&8)||!(Pico.video.reg[1]&0x40), Pico.m.scanline, SekCyclesDone());
1312 		for(a2 = a&0x7f; len; len--) {
1313 			d = *pd++;
1314 			//CalcCol( a2>>1, BURN_ENDIAN_SWAP_INT16(d) );
1315 			//pd++;
1316 			// AutoIncrement
1317 			a2+=inc;
1318 			// didn't src overlap?
1319 			//if(pd >= pdend) pd-=0x8000;
1320 			// good dest?
1321 			if(a2 >= 0x80) break; // Todds Adventures in Slime World / Andre Agassi tennis
1322 		}
1323 		a = (a&0xff00) | a2;
1324 		break;
1325 
1326 	case 5: // vsram[a&0x003f]=d;
1327 		r = RamSVid;
1328 		for(a2=a&0x7f; len; len--) {
1329 			d = *pd++;
1330 			r[a2>>1] = (UINT16)d;
1331 			// AutoIncrement
1332 			a2+=inc;
1333 			// didn't src overlap?
1334 			//if(pd >= pdend) pd-=0x8000;
1335 			// good dest?
1336 			if(a2 >= 0x80) break;
1337 		}
1338 		a=(a&0xff00)|a2;
1339 		break;
1340 
1341 	case 0x81: // vram 128k
1342       a |= RamVReg->addr_u << 16;
1343       for(; len; len--)
1344       {
1345         VideoWrite128(a, *pd++);
1346         // AutoIncrement
1347         a = (a + inc) & 0x1ffff;
1348       }
1349       RamVReg->addr_u = a >> 16;
1350       break;
1351 
1352 	}
1353 	// remember addr
1354 	RamVReg->reg[0x13] = RamVReg->reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze)
1355 	RamVReg->addr = (UINT16)a;
1356 }
1357 
DmaCopy(INT32 len)1358 static void DmaCopy(INT32 len)
1359 {
1360 	UINT8 * vr = (UINT8 *) RamVid;
1361 	UINT8 * vrs;
1362 	UINT16 a = RamVReg->addr;
1363 	UINT8 inc = RamVReg->reg[0xf];
1364 	INT32 source;
1365 
1366 	//dprintf("DmaCopy len %i [%i|%i]", len, Pico.m.scanline, SekCyclesDone());
1367 
1368 	RamVReg->status |= 2; // dma busy
1369 	dma_xfers += len;
1370 
1371 	source  = RamVReg->reg[0x15];
1372 	source |= RamVReg->reg[0x16]<<8;
1373 	vrs = vr + source;
1374 
1375 	if (source+len > 0x10000)
1376 		len = 0x10000 - source; // clip??
1377 
1378 	for(;len;len--) {
1379 		vr[a] = *vrs++;
1380 		// AutoIncrement
1381 		a = (UINT16)(a + inc);
1382 	}
1383 	// remember addr
1384 	RamVReg->addr = a;
1385 	RamVReg->reg[0x13] = RamVReg->reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze)
1386 	RamVReg->rendstatus |= PDRAW_DIRTY_SPRITES;
1387 }
1388 
DmaFill(INT32 data)1389 static void DmaFill(INT32 data)
1390 {
1391 	INT32 len = GetDmaLength();
1392 	UINT8 *vr = (UINT8 *) RamVid;
1393 	UINT8 high = (UINT8) (data >> 8);
1394 	UINT16 a = RamVReg->addr;
1395 	UINT8 inc = RamVReg->reg[0xf];
1396 
1397 	//dprintf("DmaFill len %i inc %i [%i|%i]", len, inc, Pico.m.scanline, SekCyclesDone());
1398 
1399 	// from Charles MacDonald's genvdp.txt:
1400 	// Write lower byte to address specified
1401 	RamVReg->status |= 2; // dma busy
1402 	dma_xfers += len;
1403 	vr[a] = (UINT8) data;
1404 	a = (UINT16)(a+inc);
1405 
1406 	if(!inc) len=1;
1407 
1408 	for(;len;len--) {
1409 		// Write upper byte to adjacent address
1410 		// (here we are byteswapped, so address is already 'adjacent')
1411 		vr[a] = high;
1412 		// Increment address register
1413 		a = (UINT16)(a+inc);
1414 	}
1415 	// remember addr
1416 	RamVReg->addr = a;
1417 	// update length
1418 	RamVReg->reg[0x13] = RamVReg->reg[0x14] = 0; // Dino Dini's Soccer (E) (by Haze)
1419 
1420 	RamVReg->rendstatus |= PDRAW_DIRTY_SPRITES;
1421 }
1422 
CommandChange()1423 static void CommandChange()
1424 {
1425 	//struct PicoVideo *pvid=&Pico.video;
1426 	UINT32 cmd = RamVReg->command;
1427 	UINT32 addr = 0;
1428 
1429 	// Get type of transfer 0xc0000030 (v/c/vsram read/write)
1430 	RamVReg->type = (UINT8)(((cmd >> 2) & 0xc) | (cmd >> 30));
1431 	if (RamVReg->type == 1) { // vram
1432 		RamVReg->type |= RamVReg->reg[1] & 0x80; // 128k
1433 	}
1434 
1435 	// Get address 0x3fff0003
1436 	addr  = (cmd >> 16) & 0x3fff;
1437 	addr |= (cmd << 14) & 0xc000;
1438 	RamVReg->addr = (UINT16)addr;
1439 	RamVReg->addr_u = (UINT8)((cmd >> 2) & 1);
1440 
1441 	//dprintf("addr set: %04x", addr);
1442 
1443 	// Check for dma:
1444 	if (cmd & 0x80) {
1445 		// Command DMA
1446 		if ((RamVReg->reg[1] & 0x10) == 0) return; // DMA not enabled
1447 		INT32 len = GetDmaLength();
1448 		switch ( RamVReg->reg[0x17]>>6 ) {
1449 		case 0x00:
1450 		case 0x01:
1451 			DmaSlow(len);	// 68000 to VDP
1452 			break;
1453 		case 0x03:
1454 			DmaCopy(len);	// VRAM Copy
1455 			break;
1456 		case 0x02:			// DMA Fill Flag ???
1457 		default:
1458 			;//bprintf(PRINT_NORMAL, _T("Video Command DMA Unknown %02x len %d\n"), RamVReg->reg[0x17]>>6, len);
1459 		}
1460 	}
1461 }
1462 
1463 // H-counter table for hvcounter reads in 40col mode
1464 // based on Gens code
1465 static const UINT8 hcounts_40[] = {
1466 	0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,
1467 	0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x13,0x14,
1468 	0x14,0x15,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,
1469 	0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21,
1470 	0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,
1471 	0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,
1472 	0x2f,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x35,
1473 	0x36,0x36,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3c,0x3c,
1474 	0x3d,0x3d,0x3d,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x41,0x41,0x42,0x42,0x42,0x43,
1475 	0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x49,0x49,0x4a,
1476 	0x4a,0x4a,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,
1477 	0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x57,0x57,
1478 	0x57,0x58,0x58,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5e,
1479 	0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x64,0x64,0x64,
1480 	0x65,0x65,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,
1481 	0x6c,0x6c,0x6c,0x6d,0x6d,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x71,0x71,0x71,0x72,
1482 	0x72,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x79,
1483 	0x79,0x79,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,
1484 	0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x86,0x86,
1485 	0x86,0x87,0x87,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,
1486 	0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,0x92,0x93,0x93,0x94,
1487 	0x94,0x94,0x95,0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,
1488 	0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0xa0,0xa0,0xa1,0xa1,
1489 	0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,0xa8,
1490 	0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xab,0xab,0xab,0xac,0xac,0xad,0xad,0xae,0xae,0xae,
1491 	0xaf,0xaf,0xb0,0xb0,0xe4,0xe4,0xe4,0xe5,0xe5,0xe6,0xe6,0xe6,0xe7,0xe7,0xe8,0xe8,
1492 	0xe9,0xe9,0xe9,0xea,0xea,0xeb,0xeb,0xeb,0xec,0xec,0xed,0xed,0xee,0xee,0xee,0xef,
1493 	0xef,0xf0,0xf0,0xf1,0xf1,0xf1,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf5,0xf5,0xf6,
1494 	0xf6,0xf6,0xf7,0xf7,0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,
1495 	0xfd,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,
1496 	0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,
1497 	0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x10,
1498 };
1499 
1500 // H-counter table for hvcounter reads in 32col mode
1501 static const UINT8 hcounts_32[] = {
1502 	0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,
1503 	0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x0f,0x10,
1504 	0x10,0x10,0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15,
1505 	0x15,0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,
1506 	0x1b,0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20,
1507 	0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x26,0x26,
1508 	0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,
1509 	0x2c,0x2c,0x2c,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,0x31,0x31,
1510 	0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x36,0x36,0x36,0x37,
1511 	0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,0x3b,0x3c,0x3c,
1512 	0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,0x41,0x41,0x41,0x42,
1513 	0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x45,0x45,0x45,0x46,0x46,0x46,0x47,0x47,0x47,
1514 	0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,0x4c,0x4c,0x4d,0x4d,
1515 	0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,0x51,0x51,0x51,0x52,0x52,0x52,
1516 	0x53,0x53,0x53,0x54,0x54,0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,0x57,0x58,0x58,
1517 	0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,
1518 	0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,
1519 	0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69,
1520 	0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,
1521 	0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x74,0x74,
1522 	0x74,0x75,0x75,0x75,0x76,0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79,
1523 	0x7a,0x7a,0x7b,0x7b,0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,
1524 	0x7f,0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85,
1525 	0x85,0x85,0x86,0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,
1526 	0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90,
1527 	0x90,0x90,0x91,0x91,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,0xeb,
1528 	0xec,0xec,0xec,0xed,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf0,0xf1,0xf1,
1529 	0xf1,0xf2,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,0xf6,0xf6,
1530 	0xf7,0xf7,0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,0xfb,0xfc,0xfc,
1531 	0xfc,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0x00,0x00,0x00,0x01,0x01,0x01,0x02,
1532 	0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x06,0x07,0x07,0x07,
1533 	0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,0x0a,0x0b,0x0b,0x0b,0x0c,0x0c,0x0c,0x0d,
1534 };
1535 
MegadriveVideoReadWord(UINT32 sekAddress)1536 static UINT16 __fastcall MegadriveVideoReadWord(UINT32 sekAddress)
1537 {
1538 	if (sekAddress > 0xC0001F)
1539 		bprintf(PRINT_NORMAL, _T("Video Attempt to read word value of location %x\n"), sekAddress);
1540 
1541 	UINT16 res = 0;
1542 
1543 	switch (sekAddress & 0x1c) {
1544 	case 0x00:	// data
1545 		switch (RamVReg->type) {
1546 			case 0: res = BURN_ENDIAN_SWAP_INT16(RamVid [(RamVReg->addr >> 1) & 0x7fff]); break;
1547 			case 4: res = BURN_ENDIAN_SWAP_INT16(RamSVid[(RamVReg->addr >> 1) & 0x003f]); break;
1548 			case 8: res = BURN_ENDIAN_SWAP_INT16(RamPal [(RamVReg->addr >> 1) & 0x003f]); break;
1549 		}
1550 		RamVReg->addr += RamVReg->reg[0xf];
1551 		break;
1552 
1553 	case 0x04:	// command
1554 		{
1555 			UINT16 d = RamVReg->status;
1556 			if (SekCyclesLine() >= (328) && SekCyclesLine() <= (460))
1557 				d|=0x0004; // H-Blank (Sonic3 vs)
1558 
1559 			d |= ((RamVReg->reg[1]&0x40)^0x40) >> 3;  // set V-Blank if display is disabled
1560 			d |= (RamVReg->pending_ints&0x20)<<2;     // V-int pending?
1561 			if (d&0x100) RamVReg->status&=~0x100; // FIFO no longer full
1562 			d |= (nCurrentFrame&1) ? 0x10 : 0x00;
1563 
1564 			RamVReg->pending = 0; // ctrl port reads clear write-pending flag (Charles MacDonald)
1565 			return d;
1566 		}
1567 		break;
1568 	case 0x08: 	// H-counter info
1569 		{
1570 			UINT32 d;
1571 
1572 			d = (SekCyclesLine()) & 0x1ff; // FIXME
1573 
1574 			if (RamVReg->reg[12]&1)
1575 				d = hcounts_40[d];
1576 			else d = hcounts_32[d];
1577 
1578 			//elprintf(EL_HVCNT, "hv: %02x %02x (%i) @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);
1579 			return d | (RamVReg->v_counter << 8);
1580 		}
1581 		break;
1582 
1583 	default:
1584 		bprintf(PRINT_NORMAL, _T("Video Attempt to read word value of location %x, %x\n"), sekAddress, sekAddress & 0x1c);
1585 		break;
1586 	}
1587 
1588 	return res;
1589 }
1590 
MegadriveVideoReadByte(UINT32 sekAddress)1591 static UINT8 __fastcall MegadriveVideoReadByte(UINT32 sekAddress)
1592 {
1593 //	bprintf(PRINT_NORMAL, _T("Video Attempt to read byte value of location %x\n"), sekAddress);
1594 	UINT16 res = MegadriveVideoReadWord(sekAddress & ~1);
1595 	if ((sekAddress&1)==0) res >>= 8;
1596 	return res & 0xff;
1597 }
1598 
MegadriveVideoWriteWord(UINT32 sekAddress,UINT16 wordValue)1599 static void __fastcall MegadriveVideoWriteWord(UINT32 sekAddress, UINT16 wordValue)
1600 {
1601 	if (sekAddress > 0xC0001F)
1602 		bprintf(PRINT_NORMAL, _T("Video Attempt to write word value %x to location %x\n"), wordValue, sekAddress);
1603 
1604 	switch (sekAddress & 0x1c) {
1605 	case 0x00:	// data
1606 		if (RamVReg->pending) {
1607 			CommandChange();
1608 			RamVReg->pending = 0;
1609 		}
1610 		if ((RamVReg->command & 0x80) && (RamVReg->reg[1]&0x10) && (RamVReg->reg[0x17]>>6)==2) {
1611 
1612 			DmaFill(wordValue);
1613 
1614 		} else {
1615 
1616 			// FIFO
1617 			// preliminary FIFO emulation for Chaos Engine, The (E)
1618 			if (!(RamVReg->status&8) && (RamVReg->reg[1]&0x40)) // active display?
1619 			{
1620 				RamVReg->status&=~0x200; // FIFO no longer empty
1621 				RamVReg->lwrite_cnt++;
1622 				if (RamVReg->lwrite_cnt >= 4) RamVReg->status|=0x100; // FIFO full
1623 				if (RamVReg->lwrite_cnt >  4) {
1624 					//SekRunAdjust(0-80);
1625 					//SekIdle(80);
1626 					//SekCyclesBurnRun(32);
1627 				}
1628 				//elprintf(EL_ASVDP, "VDP data write: %04x [%06x] {%i} #%i @ %06x", d, Pico.video.addr,
1629 				//		 Pico.video.type, pvid->lwrite_cnt, SekPc);
1630 			}
1631 
1632 			//UINT32 a=Pico.video.addr;
1633 			switch (RamVReg->type) {
1634 			case 1:
1635 				// If address is odd, bytes are swapped (which game needs this?)
1636 				// williams arcade greatest hits -dink
1637 				if (RamVReg->addr & 1) {
1638 					//bprintf(PRINT_NORMAL, _T("Video address is odd, bytes are swapped!!!\n"));
1639 					wordValue = (wordValue<<8)|(wordValue>>8);
1640 				}
1641 				RamVid[(RamVReg->addr >> 1) & 0x7fff] = BURN_ENDIAN_SWAP_INT16(wordValue);
1642             	RamVReg->rendstatus |= PDRAW_DIRTY_SPRITES;
1643             	break;
1644 			case 3:
1645 				//Pico.m.dirtyPal = 1;
1646 				//dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone());
1647 				//CalcCol((RamVReg->addr >> 1) & 0x003f, wordValue); // no cram in C2
1648 				break;
1649 			case 5:
1650 				RamSVid[(RamVReg->addr >> 1) & 0x003f] = BURN_ENDIAN_SWAP_INT16(wordValue);
1651 				break;
1652 			case 0x81: {
1653 				UINT32 a = RamVReg->addr | (RamVReg->addr_u << 16);
1654 				VideoWrite128(a, wordValue);
1655 				break;
1656 				}
1657 			}
1658 			//dprintf("w[%i] @ %04x, inc=%i [%i|%i]", Pico.video.type, a, Pico.video.reg[0xf], Pico.m.scanline, SekCyclesDone());
1659 			//AutoIncrement();
1660 			RamVReg->addr += RamVReg->reg[0xf];
1661 		}
1662     	return;
1663 
1664 	case 0x04:	// command
1665 		if(RamVReg->pending) {
1666 			// Low word of command:
1667 			RamVReg->command &= 0xffff0000;
1668 			RamVReg->command |= wordValue;
1669 			RamVReg->pending = 0;
1670 			CommandChange();
1671 		} else {
1672 			if((wordValue & 0xc000) == 0x8000) {
1673 				INT32 num = (wordValue >> 8) & 0x1f;
1674 				RamVReg->type = 0; // register writes clear command (else no Sega logo in Golden Axe II)
1675 				if (num > 0x0a && !(RamVReg->reg[1] & 4)) {
1676 					//bprintf(0, _T("%02x written to reg %02x in SMS mode @ %06x"), d, num, SekGetPC(-1));
1677 					return;
1678 				}
1679 
1680 				// Blank last line
1681 				if (num == 1 && !(wordValue&0x40) && SekCyclesLine() <= (488-390)) {
1682 					BlankedLine = 1;
1683 				}
1684 
1685 				UINT8 oldreg = RamVReg->reg[num];
1686 				RamVReg->reg[num] = wordValue & 0xff;
1687 
1688 				// update IRQ level (Lemmings, Wiz 'n' Liz intro, ... )
1689 				// may break if done improperly:
1690 				// International Superstar Soccer Deluxe (crash), Street Racer (logos), Burning Force (gfx), Fatal Rewind (hang), Sesame Street Counting Cafe
1691 				if(num < 2 && !SekShouldInterrupt()) {
1692 
1693 					INT32 irq = 0;
1694 					INT32 lines = (RamVReg->reg[1] & 0x20) | (RamVReg->reg[0] & 0x10);
1695 					INT32 pints = (RamVReg->pending_ints&lines);
1696 					if (pints & 0x20) irq = 6;
1697 					else if (pints & 0x10) irq = 4;
1698 
1699 					if (pints) {
1700 						SekSetVIRQLine(irq, CPU_IRQSTATUS_ACK);
1701 					} else {
1702 						if (irq != 0) SekSetVIRQLine(irq, CPU_IRQSTATUS_NONE);
1703 					}
1704 				}
1705 
1706 				if (num == 5) if (RamVReg->reg[num]^oldreg) RamVReg->rendstatus |= PDRAW_SPRITES_MOVED;
1707 
1708 				if (num == 11) {
1709 					const UINT8 h_msks[4] = { 0x00, 0x07, 0xf8, 0xff };
1710 					RamVReg->h_mask = h_msks[RamVReg->reg[11] & 3];
1711 				}
1712 			} else {
1713 				// High word of command:
1714 				RamVReg->command &= 0x0000ffff;
1715 				RamVReg->command |= wordValue << 16;
1716 				RamVReg->pending = 1;
1717 			}
1718 		}
1719     	return;
1720 
1721 	case 0x10:
1722 	case 0x14:
1723 		// PSG Sound
1724 		//bprintf(PRINT_NORMAL, _T("PSG Attempt to write word value %04x to location %08x\n"), wordValue, sekAddress);
1725 		SN76496Write(0, wordValue & 0xFF);
1726 		return;
1727 
1728 	}
1729 	bprintf(0, _T("vdp unmapped write %X %X\n"), sekAddress, wordValue);
1730 }
1731 
MegadriveVideoWriteByte(UINT32 sekAddress,UINT8 byteValue)1732 static void __fastcall MegadriveVideoWriteByte(UINT32 sekAddress, UINT8 byteValue)
1733 {
1734 	//bprintf(PRINT_NORMAL, _T("Video Attempt to write byte value %x to location %x\n"), byteValue, sekAddress);
1735 	MegadriveVideoWriteWord(sekAddress, (byteValue << 8) | byteValue);
1736 }
1737 
segac2_main_write_word(UINT32 address,UINT16 data)1738 static void __fastcall segac2_main_write_word(UINT32 address, UINT16 data)
1739 {
1740 	if ((address & 0xec0200) == 0x800000) {
1741 		protection_write(data);
1742 		return;
1743 	}
1744 
1745 	if ((address & 0xec0200) == 0x800200) {
1746 		enable_display = ~data & 1;
1747 		if (!(data & 2)) prot_write_buf = prot_read_buf = 0;
1748 		alt_palette_mode = ((~data & 4) >> 2);
1749 		//bprintf(0, _T("alt_pallette_mode: %x  disp_en  %x  (scanline: %d\tframe: %d)\n"), alt_palette_mode, enable_display, Scanline, nCurrentFrame);
1750 		recompute_palette_tables();
1751 		return;
1752 	}
1753 
1754 	if ((address & 0xec0100) == 0x840000) {
1755 		sega_315_5296_write((address & 0x1f) >> 1, data);
1756 		return;
1757 	}
1758 
1759 	if ((address & 0xec0100) == 0x840100) {
1760 		BurnYM3438Write(0, (address >> 1) & 3, data);
1761 		return;
1762 	}
1763 
1764 	if ((address & 0xec0100) == 0x880000) {
1765 		if (sound_rom_length) {
1766 			UPD7759PortWrite(0, data & 0xff);
1767 			UPD7759StartWrite(0, 0);
1768 			UPD7759StartWrite(0, 1);
1769 		}
1770 		return;
1771 	}
1772 
1773 	if ((address & 0xec0100) == 0x880100) {
1774 		// coin counters, other functions?
1775 		return;
1776 	}
1777 
1778 	if ((address & 0xec0000) == 0x8c0000) {
1779 		//bprintf(0, _T("pal_w %x  %x  (scanline: %d\tframe: %d)\n"), address, data, Scanline, nCurrentFrame);
1780 		palette_write(address & 0xfff, data, 0xffff);
1781 		return;
1782 	}
1783 
1784 	if ((address & 0xe70000) == 0xc00000) {
1785 		MegadriveVideoWriteWord(address & 0x1f, data);
1786 		return;
1787 	}
1788 	bprintf(0, _T("ww  %x  %x\n"), address, data);
1789 }
1790 
segac2_main_write_byte(UINT32 address,UINT8 data)1791 static void __fastcall segac2_main_write_byte(UINT32 address, UINT8 data)
1792 {
1793 	if ((address & 0xec0201) == 0x800001) {
1794 		protection_write(data);
1795 		return;
1796 	}
1797 
1798 	if ((address & 0xec0201) == 0x800201) {
1799 		enable_display = ~data & 1;
1800 		if (!(data & 2)) prot_write_buf = prot_read_buf = 0;
1801 		alt_palette_mode = ((~data & 4) >> 2);
1802 		//bprintf(0, _T("alt_pallette_mode.b: %x  disp_en  %x  (scanline: %d\tframe: %d)\n"), alt_palette_mode, enable_display, Scanline, nCurrentFrame);
1803 		recompute_palette_tables();
1804 		return;
1805 	}
1806 
1807 	if ((address & 0xec0101) == 0x840001) {
1808 		sega_315_5296_write((address & 0x1f) >> 1, data);
1809 		return;
1810 	}
1811 
1812 	if ((address & 0xec0101) == 0x840101) {
1813 		BurnYM3438Write(0, (address >> 1) & 3, data);
1814 		return;
1815 	}
1816 
1817 	if ((address & 0xec0101) == 0x880001) {
1818 		if (sound_rom_length) {
1819 			UPD7759PortWrite(0, data);
1820 			UPD7759StartWrite(0, 0);
1821 			UPD7759StartWrite(0, 1);
1822 		}
1823 		return;
1824 	}
1825 
1826 	if ((address & 0xec0100) == 0x880100) {
1827 		// coin counters, other functions?
1828 		return;
1829 	}
1830 
1831 	if ((address & 0xec0000) == 0x8c0000) {
1832 		//bprintf(0, _T("pal_w.b %x  %x  (scanline: %d\tframe: %d)\n"), address, data, Scanline, nCurrentFrame);
1833 		palette_write(address & 0xfff, data << ((~address & 1) * 8), 0xff << ((~address & 1) * 8));
1834 		return;
1835 	}
1836 
1837 	if ((address & 0xe70000) == 0xc00000) {
1838 		MegadriveVideoWriteByte(address & 0x1f, data);
1839 		return;
1840 	}
1841 
1842 	if (address > 0x1fffff) { // puyopuy2 writes to romspace a lot
1843 		bprintf(0, _T("wb  %x  %x\n"), address, data);
1844 	}
1845 }
1846 
segac2_main_read_word(UINT32 address)1847 static UINT16 __fastcall segac2_main_read_word(UINT32 address)
1848 {
1849 	if ((address & 0xec0200) == 0x800000) {
1850 		return prot_read_buf | 0xf0;
1851 	}
1852 
1853 	if ((address & 0xec0100) == 0x840000) {
1854 		return sega_315_5296_read((address & 0x1f) >> 1);
1855 	}
1856 
1857 	if ((address & 0xec0100) == 0x840100) {
1858 		return BurnYM3438Read(0, (address >> 1) & 3);
1859 	}
1860 
1861 	if ((address & 0xec0000) == 0x8c0000) {
1862 		return palette_read(address & 0x3ff);
1863 	}
1864 
1865 	if ((address & 0xe70000) == 0xc00000) {
1866 		return MegadriveVideoReadWord(address & 0x1f);
1867 	}
1868 
1869 	bprintf(0, _T("rw %x\n"), address);
1870 
1871 	return 0;
1872 }
1873 
segac2_main_read_byte(UINT32 address)1874 static UINT8 __fastcall segac2_main_read_byte(UINT32 address)
1875 {
1876 	if ((address & 0xec0200) == 0x800000) {
1877 		return prot_read_buf | 0xf0;
1878 	}
1879 
1880 	if ((address & 0xec0101) == 0x840001) {
1881 		return sega_315_5296_read((address & 0x1f) >> 1);
1882 	}
1883 
1884 	if ((address & 0xec0101) == 0x840101) {
1885 		return BurnYM3438Read(0, (address >> 1) & 3);
1886 	}
1887 
1888 	if ((address & 0xec0101) == 0x880101) {
1889 		// nop? (puyopuy2)
1890 		return 0;
1891 	}
1892 
1893 	if ((address & 0xec0201) == 0x800201) {
1894 		// nop? (puyopuy2)
1895 		return 0;
1896 	}
1897 
1898 	if ((address & 0xec0000) == 0x8c0000) {
1899 		return palette_read(address & 0x3ff) >> ((~address & 1) * 8);
1900 	}
1901 
1902 	if ((address & 0xe70000) == 0xc00000) {
1903 		return MegadriveVideoReadByte(address & 0x1f);
1904 	}
1905 
1906 	bprintf(0, _T("rb %x\n"), address);
1907 
1908 	return 0;
1909 }
1910 
DrvFMIRQHandler(INT32,INT32 state)1911 inline static void DrvFMIRQHandler(INT32, INT32 state)
1912 {
1913 	SekSetVIRQLine(2, state ? CPU_IRQSTATUS_ACK : CPU_IRQSTATUS_NONE);
1914 }
1915 
segac2_irq_callback(INT32 irqline)1916 static INT32 __fastcall segac2_irq_callback(INT32 irqline)
1917 {
1918 	if (irqline == 4) {
1919 		RamVReg->pending_ints &= ~0x10;
1920 		SekSetVIRQLine(irqline, CPU_IRQSTATUS_NONE);
1921 	}
1922 	if (irqline == 6) {
1923 		RamVReg->pending_ints &= ~0x20;
1924 		SekSetVIRQLine(irqline, CPU_IRQSTATUS_NONE);
1925 	}
1926 
1927 	return (0x60 + irqline * 4) / 4; // vector address
1928 }
1929 
DrvDoReset()1930 static INT32 DrvDoReset()
1931 {
1932 	memset (AllRam, 0, RamEnd - AllRam);
1933 
1934 	SekOpen(0);
1935 	SekReset();
1936 	BurnYM3438Reset();
1937 	if (sound_rom_length) UPD7759Reset();
1938 	SekClose();
1939 
1940 	prot_write_buf = 0;
1941 	prot_read_buf = 0;
1942 	enable_display = 0;
1943 	alt_palette_mode = 0;
1944 	palette_bank = 0;
1945 	bg_palbase = 0;
1946 	sp_palbase = 0;
1947 
1948 	// I/O chip
1949 	memset (output_latch, 0, sizeof(output_latch));
1950 	dir = 0;
1951 	iocnt = 0;
1952 	io_porth_write(0);
1953 
1954 	SegaC2BgPalLookup[0] = 0x00;
1955 	SegaC2BgPalLookup[1] = 0x10;
1956 	SegaC2BgPalLookup[2] = 0x20;
1957 	SegaC2BgPalLookup[3] = 0x30;
1958 
1959 	SegaC2SpPalLookup[0] = 0x00;
1960 	SegaC2SpPalLookup[1] = 0x10;
1961 	SegaC2SpPalLookup[2] = 0x20;
1962 	SegaC2SpPalLookup[3] = 0x30;
1963 
1964 	irq4_counter = -1;
1965 	irq6_line = 224;
1966 
1967 	// default VDP register values (based on Fusion)
1968 	memset(RamVReg, 0, sizeof(struct PicoVideo));
1969 	RamVReg->reg[0x00] = 0x04;
1970 	RamVReg->reg[0x01] = 0x04;
1971 	RamVReg->reg[0x0c] = 0x81;
1972 	RamVReg->reg[0x0f] = 0x02;
1973 	RamVReg->status = 0x3408 | 0; // 'always set' bits | vblank | collision | pal
1974 	RamVReg->rotate = 0;
1975 	dma_xfers = 0;
1976 	Scanline = 0;
1977 	RamVReg->rendstatus = 0;
1978 	interlacemode2 = 0;
1979 
1980 	nExtraCycles[0] = 0;
1981 
1982 	return 0;
1983 }
1984 
MemIndex()1985 static INT32 MemIndex()
1986 {
1987 	UINT8 *Next; Next = AllMem;
1988 
1989 	Drv68KROM	= Next; Next += 0x200000;
1990 
1991 	DrvSndROM	= Next; Next += 0x0a0000;
1992 
1993 	DrvPalette	= (UINT32*)Next; Next += 0x3001 * sizeof(UINT32); // +1 for black
1994 
1995 	AllRam		= Next;
1996 
1997 	Drv68KRAM	= Next; Next += 0x010000;
1998 	DrvPalRAM	= Next; Next += 0x001000;
1999 
2000 	// picodrive vdp stuff
2001 	RamPal		= (UINT16 *) Next; Next += 0x000040 * sizeof(UINT16);
2002 	RamSVid		= (UINT16 *) Next; Next += 0x000040 * sizeof(UINT16);	// VSRam
2003 	RamVid		= (UINT16 *) Next; Next += 0x010000 * sizeof(UINT16);	// Video Ram
2004 	RamVReg		= (struct PicoVideo *)Next; Next += sizeof(struct PicoVideo);
2005 
2006 	RamEnd		= Next;
2007 
2008 	HighColFull	= (UINT16*) Next; Next += ((8 + 320 + 8) * ((240 + 1) * 2)) * sizeof(UINT16);
2009 
2010 	HighCacheA	= (INT32 *) Next; Next += (41+1) * sizeof(INT32);	// caches for high layers
2011 	HighCacheB	= (INT32 *) Next; Next += (41+1) * sizeof(INT32);
2012 	HighPreSpr	= (INT32 *) Next; Next += (80*2+1) * sizeof(INT32);	// slightly preprocessed sprites
2013 
2014 	MemEnd		= Next;
2015 
2016 	return 0;
2017 }
2018 
SegaC2Init(UINT8 (* prot_read_cb)(UINT8))2019 static INT32 SegaC2Init(UINT8 (*prot_read_cb)(UINT8))
2020 {
2021 	BurnAllocMemIndex();
2022 
2023 	{
2024 		char* pRomName;
2025 		struct BurnRomInfo ri;
2026 		UINT8 *pLoad = Drv68KROM;
2027 		UINT8 *sLoad = DrvSndROM;
2028 
2029 		for (INT32 i = 0; !BurnDrvGetRomName(&pRomName, i, 0); i++)
2030 		{
2031 			BurnDrvGetRomInfo(&ri, i);
2032 
2033 			if ((ri.nType & BRF_PRG) && (ri.nType & 0x03) == 1)     // everyone else
2034 			{
2035 				if (BurnLoadRom(pLoad + 1, i+0, 2)) return 1;
2036 				if (BurnLoadRom(pLoad + 0, i+1, 2)) return 1;
2037 				pLoad += 0x100000;
2038 				i++;
2039 				continue;
2040 			}
2041 
2042 			if ((ri.nType & BRF_PRG) && (ri.nType & 0x03) == 3)		// Bloxeed is weird
2043 			{
2044 				if (BurnLoadRom(pLoad + 1, i+0, 2)) return 1;
2045 				if (BurnLoadRom(pLoad + 0, i+1, 2)) return 1;
2046 				pLoad += (ri.nLen * 2);
2047 				i++;
2048 				continue;
2049 			}
2050 
2051 			if ((ri.nType & BRF_SND) && (ri.nType & 0x03) == 2)
2052 			{
2053 				if (BurnLoadRom(sLoad, i, 1)) return 1;
2054 				sLoad += ri.nLen;
2055 				sound_rom_length += ri.nLen;
2056 				continue;
2057 			}
2058 		}
2059 
2060 		memcpy (DrvSndROM + 0x80000, DrvSndROM, 0x20000);
2061 	}
2062 
2063 	bprintf (0, _T("soundlen: %5.5x\n"), sound_rom_length);
2064 
2065 	protection_read_cb = prot_read_cb;
2066 
2067 	SekInit(0, 0x68000);
2068 	SekOpen(0);
2069 	SekSetIrqCallback(segac2_irq_callback);
2070 	SekMapMemory(Drv68KROM,			0x000000, 0x1fffff, MAP_ROM);
2071 	for (INT32 i = 0; i < 0x200000; i += 0x10000) {
2072 		SekMapMemory(Drv68KRAM,		0xe00000 + i, 0xe0ffff + i, MAP_RAM);
2073 	}
2074 	SekSetWriteWordHandler(0,	segac2_main_write_word);
2075 	SekSetWriteByteHandler(0,	segac2_main_write_byte);
2076 	SekSetReadWordHandler(0,	segac2_main_read_word);
2077 	SekSetReadByteHandler(0,	segac2_main_read_byte);
2078 	SekClose();
2079 
2080 	BurnYM3438Init(1, 53693175 / 7, &DrvFMIRQHandler, 0);
2081 	BurnTimerAttachNull(53693175 / 6);
2082 	BurnYM3438SetAllRoutes(0, 0.40, BURN_SND_ROUTE_BOTH);
2083 
2084 	SN76496Init(0, 53693175 / 15, 0);
2085 	SN76496SetBuffered(SekTotalCycles, 53693175 / 6);
2086 	SN76496SetRoute(0, 0.35, BURN_SND_ROUTE_BOTH);
2087 
2088 	if (sound_rom_length)
2089 	{
2090 		UPD7759Init(0, UPD7759_STANDARD_CLOCK, DrvSndROM + 0x80000);
2091 		UPD7759SetRoute(0, 0.35, BURN_SND_ROUTE_BOTH);
2092 		UPD7759SetSyncCallback(0, SekTotalCycles, 53693175 / 6);
2093 	}
2094 
2095 	GenericTilesInit();
2096 
2097 	if (has_dial) BurnTrackballInit(2); // twinsqua
2098 
2099 	// I/O Chip
2100 	dir_override = 0xff;
2101 
2102 	DrvDoReset();
2103 
2104 	return 0;
2105 }
2106 
DrvExit()2107 static INT32 DrvExit()
2108 {
2109 	GenericTilesExit();
2110 
2111 	BurnYM3438Exit();
2112 	SN76496Exit();
2113 	if (sound_rom_length) UPD7759Exit();
2114 	SekExit();
2115 
2116 	BurnFreeMemIndex();
2117 
2118 	if (has_dial) BurnTrackballExit();
2119 	has_dial = 0;
2120 
2121 	sound_rom_length = 0;
2122 
2123 	is_wwmarine = 0;
2124 	is_tfrceacb = 0;
2125 	is_ribbit = 0;
2126 
2127 	return 0;
2128 }
2129 
2130 //---------------------------------------------------------------
2131 // Megadrive Draw
2132 //---------------------------------------------------------------
2133 
2134 #define TileNormMaker_(pix_func)                             \
2135 {                                                            \
2136   unsigned int t;                                            \
2137                                                              \
2138   t = (pack&0x0000f000)>>12; pix_func(0);                    \
2139   t = (pack&0x00000f00)>> 8; pix_func(1);                    \
2140   t = (pack&0x000000f0)>> 4; pix_func(2);                    \
2141   t = (pack&0x0000000f)    ; pix_func(3);                    \
2142   t = (pack&0xf0000000)>>28; pix_func(4);                    \
2143   t = (pack&0x0f000000)>>24; pix_func(5);                    \
2144   t = (pack&0x00f00000)>>20; pix_func(6);                    \
2145   t = (pack&0x000f0000)>>16; pix_func(7);                    \
2146 }
2147 
2148 #define TileFlipMaker_(pix_func)                             \
2149 {                                                            \
2150   unsigned int t;                                            \
2151                                                              \
2152   t = (pack&0x000f0000)>>16; pix_func(0);                    \
2153   t = (pack&0x00f00000)>>20; pix_func(1);                    \
2154   t = (pack&0x0f000000)>>24; pix_func(2);                    \
2155   t = (pack&0xf0000000)>>28; pix_func(3);                    \
2156   t = (pack&0x0000000f)    ; pix_func(4);                    \
2157   t = (pack&0x000000f0)>> 4; pix_func(5);                    \
2158   t = (pack&0x00000f00)>> 8; pix_func(6);                    \
2159   t = (pack&0x0000f000)>>12; pix_func(7);                    \
2160 }
2161 
2162 #define TileNormMaker(funcname, pix_func) \
2163 static void funcname(UINT16 *pd, unsigned int pack, int pal) \
2164 TileNormMaker_(pix_func)
2165 
2166 #define TileFlipMaker(funcname, pix_func) \
2167 static void funcname(UINT16 *pd, unsigned int pack, int pal) \
2168 TileFlipMaker_(pix_func)
2169 
2170 #define TileNormMakerAS(funcname, pix_func) \
2171 static void funcname(UINT16 *pd, unsigned char *mb, unsigned int pack, int pal) \
2172 TileNormMaker_(pix_func)
2173 
2174 #define TileFlipMakerAS(funcname, pix_func) \
2175 static void funcname(UINT16 *pd, unsigned char *mb, unsigned int pack, int pal) \
2176 TileFlipMaker_(pix_func)
2177 
2178 #define pix_just_write(x) \
2179   if (t) pd[x]=pal|t
2180 
TileNormMaker(TileNorm,pix_just_write)2181 TileNormMaker(TileNorm,pix_just_write)
2182 TileFlipMaker(TileFlip,pix_just_write)
2183 
2184 // draw a sprite pixel, process operator colors
2185 #define pix_sh(x) \
2186   if (!t); \
2187   else if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \
2188   else pd[x]=pal|t
2189 
2190 TileNormMaker(TileNormSH, pix_sh)
2191 TileFlipMaker(TileFlipSH, pix_sh)
2192 
2193 // draw a sprite pixel, mark operator colors
2194 #define pix_sh_markop(x) \
2195   if (!t); \
2196   else if (t>=0xe) pd[x]|=0x80; \
2197   else pd[x]=pal|t
2198 
2199 TileNormMaker(TileNormSH_markop, pix_sh_markop)
2200 TileFlipMaker(TileFlipSH_markop, pix_sh_markop)
2201 
2202 // process operator pixels only, apply only on low pri tiles and other op pixels
2203 #define pix_sh_onlyop(x) \
2204   if (t>=0xe && (pd[x]&0xc0)) \
2205     pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \
2206 
2207 TileNormMaker(TileNormSH_onlyop_lp, pix_sh_onlyop)
2208 TileFlipMaker(TileFlipSH_onlyop_lp, pix_sh_onlyop)
2209 
2210 // draw a sprite pixel (AS)
2211 #define pix_as(x) \
2212   if (t & mb[x]) mb[x] = 0, pd[x] = pal | t
2213 
2214 TileNormMakerAS(TileNormAS, pix_as)
2215 TileFlipMakerAS(TileFlipAS, pix_as)
2216 
2217 // draw a sprite pixel, process operator colors (AS)
2218 #define pix_sh_as(x) \
2219   if (t & mb[x]) { \
2220     mb[x] = 0; \
2221     if (t>=0xe) pd[x]=(pd[x]&0x3f)|(t<<6); /* c0 shadow, 80 hilight */ \
2222     else pd[x] = pal | t; \
2223   }
2224 
2225 TileNormMakerAS(TileNormSH_AS, pix_sh_as)
2226 TileFlipMakerAS(TileFlipSH_AS, pix_sh_as)
2227 
2228 #define pix_sh_as_onlyop(x) \
2229   if (t & mb[x]) { \
2230     mb[x] = 0; \
2231     pix_sh_onlyop(x); \
2232   }
2233 
2234 TileNormMakerAS(TileNormSH_AS_onlyop_lp, pix_sh_as_onlyop)
2235 TileFlipMakerAS(TileFlipSH_AS_onlyop_lp, pix_sh_as_onlyop)
2236 
2237 // mark pixel as sprite pixel (AS)
2238 #define pix_sh_as_onlymark(x) \
2239   if (t) mb[x] = 0
2240 
2241 TileNormMakerAS(TileNormAS_onlymark, pix_sh_as_onlymark)
2242 TileFlipMakerAS(TileFlipAS_onlymark, pix_sh_as_onlymark)
2243 
2244 // forced both layer draw (through debug reg)
2245 #define pix_and(x) \
2246   pd[x] = (pd[x] & 0xc0) | (pd[x] & (pal | t))
2247 
2248 TileNormMaker(TileNorm_and, pix_and)
2249 TileFlipMaker(TileFlip_and, pix_and)
2250 
2251 // --------------------------------------------
2252 
2253 
2254 static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
2255 {
2256   UINT16 *pd = HighCol;
2257   int tilex,dx,ty,code=0,addr=0,cells;
2258   int oldcode=-1,blank=-1; // The tile we know is blank
2259   int pal=0,sh;
2260 
2261   // Draw tiles across screen:
2262   sh = (lflags & LF_SH) << 5; // 0x40
2263   tilex=((-ts->hscroll)>>3)+cellskip;
2264   ty=(ts->line&7)<<1; // Y-Offset into tile
2265   dx=((ts->hscroll-1)&7)+1;
2266   cells = ts->cells - cellskip;
2267   if(dx != 8) cells++; // have hscroll, need to draw 1 cell more
2268   dx+=cellskip<<3;
2269 
2270   for (; cells > 0; dx+=8, tilex++, cells--)
2271   {
2272     unsigned int pack;
2273 
2274     code = RamVid[ts->nametab + (tilex & ts->xmask)];
2275     if (code == blank)
2276       continue;
2277 	if ((code >> 15) | (lflags & LF_FORCE)) { // high priority tile
2278       int cval = code | (dx<<16) | (ty<<25);
2279       if(code&0x1000) cval^=7<<26;
2280       *ts->hc++ = cval; // cache it
2281       continue;
2282     }
2283 
2284     if (code!=oldcode) {
2285       oldcode = code;
2286       // Get tile address/2:
2287       addr=(code&0x7ff)<<4;
2288       addr+=ty;
2289       if (code&0x1000) addr^=0xe; // Y-flip
2290 
2291       pal=((code>>9)&0x30)|sh;
2292     }
2293 
2294     pack = *(unsigned int *)(RamVid + addr);
2295     if (!pack) {
2296       blank = code;
2297       continue;
2298     }
2299 
2300 	if (~nBurnLayer & 4) return;
2301 
2302     if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2303     else               TileNorm(pd + dx, pack, pal);
2304   }
2305 
2306   // terminate the cache list
2307   *ts->hc = 0;
2308   // if oldcode wasn't changed, it means all layer is hi priority
2309   if (oldcode == -1) RamVReg->rendstatus |= PDRAW_PLANE_HI_PRIO;
2310 }
2311 
DrawStripVSRam(struct TileStrip * ts,int plane_sh,int cellskip)2312 static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
2313 {
2314   UINT16 *pd = HighCol;
2315   int tilex,dx,code=0,addr=0,cell=0;
2316   int oldcode=-1,blank=-1; // The tile we know is blank
2317   int pal=0,scan=Scanline;
2318 
2319   // Draw tiles across screen:
2320   tilex=(-ts->hscroll)>>3;
2321   dx=((ts->hscroll-1)&7)+1;
2322   if (ts->hscroll & 0x0f) {
2323     int adj = ((ts->hscroll ^ dx) >> 3) & 1;
2324     cell -= adj + 1;
2325     ts->cells -= adj;
2326   }
2327   cell+=cellskip;
2328   tilex+=cellskip;
2329   dx+=cellskip<<3;
2330 
2331   for (; cell < ts->cells; dx+=8,tilex++,cell++)
2332   {
2333     int nametabadd, ty;
2334     unsigned int pack;
2335 
2336     //if((cell&1)==0)
2337     {
2338       int line,vscroll;
2339       vscroll=RamSVid[(plane_sh&1)+(cell&~1)];
2340 
2341       // Find the line in the name table
2342       line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..
2343       nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]
2344       ty=(line&7)<<1; // Y-Offset into tile
2345     }
2346 
2347     code=RamVid[ts->nametab+nametabadd+(tilex&ts->xmask)];
2348     if (code==blank) continue;
2349     if (code>>15) { // high priority tile
2350       int cval = code | (dx<<16) | (ty<<25);
2351       if(code&0x1000) cval^=7<<26;
2352       *ts->hc++ = cval; // cache it
2353       continue;
2354     }
2355 
2356     if (code!=oldcode) {
2357       oldcode = code;
2358       // Get tile address/2:
2359       addr=(code&0x7ff)<<4;
2360       if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
2361 
2362       pal=((code>>9)&0x30)|((plane_sh<<5)&0x40);
2363     }
2364 
2365     pack = *(unsigned int *)(RamVid + addr);
2366     if (!pack) {
2367       blank = code;
2368       continue;
2369     }
2370 
2371 	if (~nBurnLayer & 2) return;
2372 
2373     if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2374     else               TileNorm(pd + dx, pack, pal);
2375   }
2376 
2377   // terminate the cache list
2378   *ts->hc = 0;
2379   if (oldcode == -1) RamVReg->rendstatus |= PDRAW_PLANE_HI_PRIO;
2380 }
2381 
DrawStripInterlace(struct TileStrip * ts)2382 void DrawStripInterlace(struct TileStrip *ts)
2383 {
2384   UINT16 *pd = HighCol;
2385   int tilex=0,dx=0,ty=0,code=0,addr=0,cells;
2386   int oldcode=-1,blank=-1; // The tile we know is blank
2387   int pal=0;
2388 
2389   // Draw tiles across screen:
2390   tilex=(-ts->hscroll)>>3;
2391   ty=(ts->line&15)<<1; // Y-Offset into tile
2392   dx=((ts->hscroll-1)&7)+1;
2393   cells = ts->cells;
2394   if(dx != 8) cells++; // have hscroll, need to draw 1 cell more
2395 
2396   for (; cells; dx+=8,tilex++,cells--)
2397   {
2398     unsigned int pack;
2399 
2400     code = RamVid[ts->nametab + (tilex & ts->xmask)];
2401     if (code==blank) continue;
2402     if (code>>15) { // high priority tile
2403       int cval = (code&0xfc00) | (dx<<16) | (ty<<25);
2404       cval|=(code&0x3ff)<<1;
2405       if(code&0x1000) cval^=0xf<<26;
2406       *ts->hc++ = cval; // cache it
2407       continue;
2408     }
2409 
2410     if (code!=oldcode) {
2411       oldcode = code;
2412       // Get tile address/2:
2413       addr=(code&0x7ff)<<5;
2414       if (code&0x1000) addr+=30-ty; else addr+=ty; // Y-flip
2415 
2416 //      pal=Pico.cram+((code>>9)&0x30);
2417       pal=((code>>9)&0x30);
2418     }
2419 
2420     pack = *(unsigned int *)(RamVid + addr);
2421     if (!pack) {
2422       blank = code;
2423       continue;
2424     }
2425 
2426     if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2427     else               TileNorm(pd + dx, pack, pal);
2428   }
2429 
2430   // terminate the cache list
2431   *ts->hc = 0;
2432 }
2433 
2434 // --------------------------------------------
2435 
2436 
DrawLayer(int plane_sh,int * hcache,int cellskip,int maxcells)2437 static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells)
2438 {
2439   const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid)
2440   const unsigned char h_masks[4] = { 0x00, 0x07, 0xf8, 0xff };
2441   struct TileStrip ts;
2442   int width, height, ymask;
2443   int vscroll, htab;
2444 
2445   ts.hc=hcache;
2446   ts.cells=maxcells;
2447 
2448   // Work out the TileStrip to draw
2449 
2450   // Work out the name table size: 32 64 or 128 tiles (0-3)
2451   width=RamVReg->reg[16];
2452   height=(width>>4)&3; width&=3;
2453 
2454   ts.xmask=(1<<shift[width])-1; // X Mask in tiles (0x1f-0x7f)
2455   ymask=(height<<8)|0xff;       // Y Mask in pixels
2456   switch (width) {
2457     case 1: ymask &= 0x1ff; break;
2458     case 2: ymask =  0x007; break;
2459     case 3: ymask =  0x0ff; break;
2460   }
2461 
2462   // Find name table:
2463   if (plane_sh&1) ts.nametab=(RamVReg->reg[4]&0x07)<<12; // B
2464   else            ts.nametab=(RamVReg->reg[2]&0x38)<< 9; // A
2465 
2466   htab=RamVReg->reg[13]<<9; // Horizontal scroll table address
2467   htab+=(Scanline&h_masks[RamVReg->reg[11]&3])<<1; // Point to line (masked)
2468   htab+=plane_sh&1; // A or B
2469 
2470   // Get horizontal scroll value, will be masked later
2471   ts.hscroll = RamVid[htab & 0x7fff];
2472 
2473   if((RamVReg->reg[12]&6) == 6) {
2474     // interlace mode 2
2475     vscroll = RamSVid[plane_sh & 1]; // Get vertical scroll value
2476 
2477     // Find the line in the name table
2478     ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1);
2479     ts.nametab+=(ts.line>>4)<<shift[width];
2480 
2481     DrawStripInterlace(&ts);
2482   } else if( RamVReg->reg[11]&4) {
2483     // shit, we have 2-cell column based vscroll
2484     // luckily this doesn't happen too often
2485     ts.line=ymask|(shift[width]<<24); // save some stuff instead of line
2486     DrawStripVSRam(&ts, plane_sh, cellskip);
2487   } else {
2488     vscroll = RamSVid[plane_sh & 1]; // Get vertical scroll value
2489 
2490     // Find the line in the name table
2491     ts.line=(vscroll+Scanline)&ymask;
2492     ts.nametab+=(ts.line>>3)<<shift[width];
2493 
2494     DrawStrip(&ts, plane_sh, cellskip);
2495   }
2496 }
2497 
2498 // --------------------------------------------
2499 
2500 // tstart & tend are tile pair numbers
DrawWindow(int tstart,int tend,int prio,int sh)2501 static void DrawWindow(int tstart, int tend, int prio, int sh)
2502 {
2503   UINT16 *pd = HighCol;
2504   int tilex,ty,nametab,code=0;
2505   int blank=-1; // The tile we know is blank
2506 
2507   if (~nSpriteEnable & 0x10) return;
2508 
2509   // Find name table line:
2510   if (RamVReg->reg[12]&1)
2511   {
2512     nametab=(RamVReg->reg[3]&0x3c)<<9; // 40-cell mode
2513     nametab+=(Scanline>>3)<<6;
2514   }
2515   else
2516   {
2517     nametab=(RamVReg->reg[3]&0x3e)<<9; // 32-cell mode
2518     nametab+=(Scanline>>3)<<5;
2519   }
2520 
2521   tilex=tstart<<1;
2522 
2523   if (!(RamVReg->rendstatus & PDRAW_WND_DIFF_PRIO)) {
2524     // check the first tile code
2525     code = RamVid[nametab + tilex];
2526     // if the whole window uses same priority (what is often the case), we may be able to skip this field
2527     if ((code>>15) != prio) return;
2528   }
2529 
2530   tend<<=1;
2531   ty=(Scanline&7)<<1; // Y-Offset into tile
2532 
2533   // Draw tiles across screen:
2534   if (!sh)
2535   {
2536     for (; tilex < tend; tilex++)
2537     {
2538       unsigned int pack;
2539       int dx, addr;
2540       int pal;
2541 
2542       code = RamVid[nametab + tilex];
2543       if (code==blank) continue;
2544       if ((code>>15) != prio) {
2545         RamVReg->rendstatus |= PDRAW_WND_DIFF_PRIO;
2546         continue;
2547       }
2548 
2549       // Get tile address/2:
2550       addr=(code&0x7ff)<<4;
2551       if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
2552 
2553       pack = *(unsigned int *)(RamVid + addr);
2554       if (!pack) {
2555         blank = code;
2556         continue;
2557       }
2558 
2559       pal = ((code >> 9) & 0x30);
2560       dx = 8 + (tilex << 3);
2561 
2562       if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2563       else               TileNorm(pd + dx, pack, pal);
2564     }
2565   }
2566   else
2567   {
2568     for (; tilex < tend; tilex++)
2569     {
2570       unsigned int pack;
2571       int dx, addr;
2572       int pal;
2573 
2574       code = RamVid[nametab + tilex];
2575       if(code==blank) continue;
2576       if((code>>15) != prio) {
2577         RamVReg->rendstatus |= PDRAW_WND_DIFF_PRIO;
2578         continue;
2579       }
2580 
2581       pal=((code>>9)&0x30);
2582 
2583       if (prio) {
2584         UINT16 *zb = (UINT16 *)(HighCol+8+(tilex<<3));
2585         *zb &= 0x00bf; zb++;
2586         *zb &= 0x00bf; zb++;
2587         *zb &= 0x00bf; zb++;
2588         *zb &= 0x00bf; zb++;
2589         *zb &= 0x00bf; zb++;
2590         *zb &= 0x00bf; zb++;
2591         *zb &= 0x00bf; zb++;
2592         *zb &= 0x00bf; zb++;
2593       } else {
2594         pal |= 0x40;
2595       }
2596 
2597       // Get tile address/2:
2598       addr=(code&0x7ff)<<4;
2599       if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip
2600 
2601       pack = *(unsigned int *)(RamVid + addr);
2602       if (!pack) {
2603         blank = code;
2604         continue;
2605       }
2606 
2607       dx = 8 + (tilex << 3);
2608 
2609       if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2610       else               TileNorm(pd + dx, pack, pal);
2611     }
2612   }
2613 }
2614 
2615 // --------------------------------------------
2616 
DrawTilesFromCacheShPrep(void)2617 static void DrawTilesFromCacheShPrep(void)
2618 {
2619   // as some layer has covered whole line with hi priority tiles,
2620   // we can process whole line and then act as if sh/hi mode was off,
2621   // but leave lo pri op sprite markers alone
2622 	int c = 320;
2623 	UINT16 *zb = (UINT16 *)(HighCol+8);
2624   RamVReg->rendstatus |= PDRAW_SHHI_DONE;
2625   while (c--)
2626   {
2627     *zb++ &= 0x80bf; // dink maybe 0x80bf ?
2628   }
2629 }
2630 
DrawTilesFromCache(int * hc,int sh,int rlim)2631 static void DrawTilesFromCache(int *hc, int sh, int rlim)
2632 {
2633   UINT16 *pd = HighCol;
2634   int code, addr, dx;
2635   unsigned int pack;
2636   int pal;
2637 
2638   // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it
2639 
2640   if (~nBurnLayer & 1) return;
2641 
2642   if (sh && (RamVReg->rendstatus & (PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO)))
2643   {
2644     if (!(RamVReg->rendstatus & PDRAW_SHHI_DONE))
2645       DrawTilesFromCacheShPrep();
2646     sh = 0;
2647   }
2648 
2649   if (!sh)
2650   {
2651 	  if (~nSpriteEnable & 0x40) return;
2652     short blank=-1; // The tile we know is blank
2653     while ((code=*hc++)) {
2654       if (!(code & 0x8000) || (short)code == blank)
2655         continue;
2656       // Get tile address/2:
2657       addr = (code & 0x7ff) << 4;
2658       addr += code >> 25; // y offset into tile
2659 
2660       pack = *(unsigned int *)(RamVid + addr);
2661       if (!pack) {
2662         blank = (short)code;
2663         continue;
2664       }
2665 
2666       dx = (code >> 16) & 0x1ff;
2667       pal = ((code >> 9) & 0x30);
2668       if (rlim-dx < 0)
2669         goto last_cut_tile;
2670 
2671       if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2672       else               TileNorm(pd + dx, pack, pal);
2673     }
2674   }
2675   else
2676   {
2677 	  if (~nSpriteEnable & 0x80) return;
2678     while ((code=*hc++)) {
2679       UINT16 *zb;
2680 
2681       // Get tile address/2:
2682       addr=(code&0x7ff)<<4;
2683       addr+=(unsigned int)code>>25; // y offset into tile
2684       dx=(code>>16)&0x1ff;
2685       zb = HighCol+dx;
2686       *zb++ &= 0x00bf; *zb++ &= 0x00bf; *zb++ &= 0x00bf; *zb++ &= 0x00bf;
2687       *zb++ &= 0x00bf; *zb++ &= 0x00bf; *zb++ &= 0x00bf; *zb++ &= 0x00bf;
2688 
2689       pack = *(unsigned int *)(RamVid + addr);
2690       if (!pack)
2691         continue;
2692 
2693       pal = ((code >> 9) & 0x30);
2694       if (rlim - dx < 0)
2695         goto last_cut_tile;
2696 
2697       if (code & 0x0800) TileFlip(pd + dx, pack, pal);
2698       else               TileNorm(pd + dx, pack, pal);
2699     }
2700   }
2701   return;
2702 
2703 last_cut_tile:
2704   // for vertical window cutoff
2705   {
2706     unsigned int t;
2707 
2708     pd += dx;
2709     if (code&0x0800)
2710     {
2711       switch (rlim-dx+8)
2712       {
2713         case 7: t=pack&0x00000f00; if (t) pd[6]=(pal|(t>> 8)); // "break" is left out intentionally
2714         case 6: t=pack&0x000000f0; if (t) pd[5]=(pal|(t>> 4));
2715         case 5: t=pack&0x0000000f; if (t) pd[4]=(pal|(t    ));
2716         case 4: t=pack&0xf0000000; if (t) pd[3]=(pal|(t>>28));
2717         case 3: t=pack&0x0f000000; if (t) pd[2]=(pal|(t>>24));
2718         case 2: t=pack&0x00f00000; if (t) pd[1]=(pal|(t>>20));
2719         case 1: t=pack&0x000f0000; if (t) pd[0]=(pal|(t>>16));
2720         default: break;
2721       }
2722     }
2723     else
2724     {
2725       switch (rlim-dx+8)
2726       {
2727         case 7: t=pack&0x00f00000; if (t) pd[6]=(pal|(t>>20));
2728         case 6: t=pack&0x0f000000; if (t) pd[5]=(pal|(t>>24));
2729         case 5: t=pack&0xf0000000; if (t) pd[4]=(pal|(t>>28));
2730         case 4: t=pack&0x0000000f; if (t) pd[3]=(pal|(t    ));
2731         case 3: t=pack&0x000000f0; if (t) pd[2]=(pal|(t>> 4));
2732         case 2: t=pack&0x00000f00; if (t) pd[1]=(pal|(t>> 8));
2733         case 1: t=pack&0x0000f000; if (t) pd[0]=(pal|(t>>12));
2734         default: break;
2735       }
2736     }
2737   }
2738 }
2739 
2740 // Index + 0  :    hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size
2741 // Index + 4  :    xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
2742 
DrawSprite(int * sprite,int sh)2743 static void DrawSprite(int *sprite, int sh)
2744 {
2745   void (*fTileFunc)(UINT16 *pd, unsigned int pack, int pal);
2746   UINT16 *pd = HighCol;
2747   int width=0,height=0;
2748   int row=0,code=0;
2749   int pal;
2750   int tile=0,delta=0;
2751   int sx, sy;
2752 
2753   if (~nSpriteEnable & 0x01) return;
2754 
2755   // parse the sprite data
2756   sy=sprite[0];
2757   code=sprite[1];
2758   sx=code>>16; // X
2759   width=sy>>28;
2760   height=(sy>>24)&7; // Width and height in tiles
2761   sy=(sy<<16)>>16; // Y
2762 
2763   row=Scanline-sy; // Row of the sprite we are on
2764 
2765   if (code&0x1000) row=(height<<3)-1-row; // Flip Y
2766 
2767   tile=code + (row>>3); // Tile number increases going down
2768   delta=height; // Delta to increase tile by going right
2769   if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
2770 
2771   tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address
2772   delta<<=4; // Delta of address
2773 
2774   pal=(code>>9)&0x30;
2775   pal|=(sh<<6)|0x8000; // 0x8000 = c2 sprite (dink)
2776 
2777   if (sh && (code&0x6000) == 0x6000) {
2778     if(code&0x0800) fTileFunc=TileFlipSH_markop;
2779     else            fTileFunc=TileNormSH_markop;
2780   } else {
2781     if(code&0x0800) fTileFunc=TileFlip;
2782     else            fTileFunc=TileNorm;
2783   }
2784 
2785   for (; width; width--,sx+=8,tile+=delta)
2786   {
2787     unsigned int pack;
2788 
2789     if(sx<=0)   continue;
2790     if(sx>=328) break; // Offscreen
2791 
2792     pack = *(unsigned int *)(RamVid + (tile & 0x7fff));
2793     fTileFunc(pd + sx, pack, pal);
2794   }
2795 }
2796 
DrawTilesFromCacheForced(const int * hc)2797 static void DrawTilesFromCacheForced(const int *hc)
2798 {
2799   UINT16 *pd = HighCol;
2800   int code, addr, dx;
2801   unsigned int pack;
2802   int pal;
2803 
2804   // *ts->hc++ = code | (dx<<16) | (ty<<25);
2805   while ((code = *hc++)) {
2806     // Get tile address/2:
2807     addr = (code & 0x7ff) << 4;
2808     addr += (code >> 25) & 0x0e; // y offset into tile
2809 
2810     dx = (code >> 16) & 0x1ff;
2811     pal = ((code >> 9) & 0x30);
2812     pack = *(unsigned int *)(RamVid + addr);
2813 
2814     if (code & 0x0800) TileFlip_and(pd + dx, pack, pal);
2815     else               TileNorm_and(pd + dx, pack, pal);
2816   }
2817 }
2818 
2819 
2820 
DrawSpriteInterlace(unsigned int * sprite)2821 static void DrawSpriteInterlace(unsigned int *sprite)
2822 {
2823   UINT16 *pd = HighCol;
2824   int width=0,height=0;
2825   int row=0,code=0;
2826   int pal;
2827   int tile=0,delta=0;
2828   int sx, sy;
2829 
2830   if (~nSpriteEnable & 0x02) return;
2831 
2832   // parse the sprite data
2833   sy=sprite[0];
2834   height=sy>>24;
2835   sy=(sy&0x3ff)-0x100; // Y
2836   width=(height>>2)&3; height&=3;
2837   width++; height++; // Width and height in tiles
2838 
2839   row=(Scanline<<1)-sy; // Row of the sprite we are on
2840 
2841   code=sprite[1];
2842   sx=((code>>16)&0x1ff)-0x78; // X
2843 
2844   if (code&0x1000) row^=(16<<height)-1; // Flip Y
2845 
2846   tile=code&0x3ff; // Tile number
2847   tile+=row>>4; // Tile number increases going down
2848   delta=height; // Delta to increase tile by going right
2849   if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
2850 
2851   tile<<=5; tile+=(row&15)<<1; // Tile address
2852 
2853   delta<<=5; // Delta of address
2854   pal=((code>>9)&0x30)|0x8000; // Get palette pointer
2855 
2856   for (; width; width--,sx+=8,tile+=delta)
2857   {
2858     unsigned int pack;
2859 
2860     if(sx<=0)   continue;
2861     if(sx>=328) break; // Offscreen
2862 
2863     pack = *(unsigned int *)(RamVid + (tile & 0x7fff));
2864     if (code & 0x0800) TileFlip(pd + sx, pack, pal);
2865     else               TileNorm(pd + sx, pack, pal);
2866   }
2867 }
2868 
2869 
DrawAllSpritesInterlace(int pri,int sh)2870 static void DrawAllSpritesInterlace(int pri, int sh)
2871 {
2872   int i,u,table,link=0,sline=(Scanline<<1)+RamVReg->field;;
2873   unsigned int *sprites[80]; // Sprite index
2874 
2875   table=RamVReg->reg[5]&0x7f;
2876   if (RamVReg->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
2877   table<<=8; // Get sprite table address/2
2878 
2879   for (i=u=0; u < 80 && i < 21; u++)
2880   {
2881     unsigned int *sprite;
2882     int code, sx, sy, height;
2883 
2884     sprite=(unsigned int *)(RamVid+((table+(link<<2))&0x7ffc)); // Find sprite
2885 
2886     // get sprite info
2887     code = sprite[0];
2888     sx = sprite[1];
2889     if(((sx>>15)&1) != pri) goto nextsprite; // wrong priority sprite
2890 
2891     // check if it is on this line
2892     sy = (code&0x3ff)-0x100;
2893     height = (((code>>24)&3)+1)<<4;
2894     if(sline < sy || sline >= sy+height) goto nextsprite; // no
2895 
2896     // check if sprite is not hidden offscreen
2897     sx = (sx>>16)&0x1ff;
2898     sx -= 0x78; // Get X coordinate + 8
2899     if(sx <= -8*3 || sx >= 328) goto nextsprite;
2900 
2901     // sprite is good, save it's pointer
2902     sprites[i++]=sprite;
2903 
2904     nextsprite:
2905     // Find next sprite
2906     link=(code>>16)&0x7f;
2907     if(!link) break; // End of sprites
2908   }
2909 
2910   // Go through sprites backwards:
2911   for (i-- ;i>=0; i--)
2912     DrawSpriteInterlace(sprites[i]);
2913 }
2914 
2915 
2916 /*
2917  * s/h drawing: lo_layers|40, lo_sprites|40 && mark_op,
2918  *        hi_layers&=~40, hi_sprites
2919  *
2920  * Index + 0  :    hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size
2921  * Index + 4  :    xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
2922  */
DrawSpritesSHi(unsigned char * sprited)2923 static void DrawSpritesSHi(unsigned char *sprited)
2924 {
2925   void (*fTileFunc)(UINT16 *pd, unsigned int pack, int pal);
2926   UINT16 *pd = HighCol;
2927   unsigned char *p;
2928   int cnt;
2929 
2930   if (~nSpriteEnable & 0x04) return;
2931 
2932   cnt = sprited[0] & 0x7f;
2933   if (cnt == 0) return;
2934 
2935   p = &sprited[3];
2936 
2937   // Go through sprites backwards:
2938   for (cnt--; cnt >= 0; cnt--)
2939   {
2940     int *sprite, code, pal, tile, sx, sy;
2941     int offs, delta, width, height, row;
2942 
2943     offs = (p[cnt] & 0x7f) * 2;
2944     sprite = HighPreSpr + offs;
2945     code = sprite[1];
2946     pal = (code>>9)&0x30;
2947 
2948     if (pal == 0x30)
2949     {
2950       if (code & 0x8000) // hi priority
2951       {
2952         if (code&0x800) fTileFunc=TileFlipSH;
2953         else            fTileFunc=TileNormSH;
2954       } else {
2955         if (code&0x800) fTileFunc=TileFlipSH_onlyop_lp;
2956         else            fTileFunc=TileNormSH_onlyop_lp;
2957       }
2958     } else {
2959       if (!(code & 0x8000)) continue; // non-operator low sprite, already drawn
2960       if (code&0x800) fTileFunc=TileFlip;
2961       else            fTileFunc=TileNorm;
2962     }
2963 
2964     // parse remaining sprite data
2965     sy=sprite[0];
2966     sx=code>>16; // X
2967     width=sy>>28;
2968     height=(sy>>24)&7; // Width and height in tiles
2969     sy=(sy<<16)>>16; // Y
2970 
2971     row=Scanline-sy; // Row of the sprite we are on
2972 
2973     if (code&0x1000) row=(height<<3)-1-row; // Flip Y
2974 
2975     tile=code + (row>>3); // Tile number increases going down
2976     delta=height; // Delta to increase tile by going right
2977     if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
2978 
2979     tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address
2980     delta<<=4; // Delta of address
2981 
2982     for (; width; width--,sx+=8,tile+=delta)
2983     {
2984       unsigned int pack;
2985 
2986       if(sx<=0)   continue;
2987       if(sx>=328) break; // Offscreen
2988 
2989       pack = *(unsigned int *)(RamVid + (tile & 0x7fff));
2990       fTileFunc(pd + sx, pack, pal|0x8000);
2991     }
2992   }
2993 }
2994 
DrawSpritesHiAS(unsigned char * sprited,int sh)2995 static void DrawSpritesHiAS(unsigned char *sprited, int sh)
2996 {
2997   void (*fTileFunc)(UINT16 *pd, unsigned char *mb,
2998                     unsigned int pack, int pal);
2999   UINT16 *pd = HighCol;
3000   unsigned char mb[8+320+8];
3001   unsigned char *p;
3002   int entry, cnt;
3003 
3004   if (~nSpriteEnable & 0x08) return;
3005 
3006   cnt = sprited[0] & 0x7f;
3007   if (cnt == 0) return;
3008 
3009   memset(mb, 0xff, sizeof(mb));
3010   p = &sprited[3];
3011 
3012   // Go through sprites:
3013   for (entry = 0; entry < cnt; entry++)
3014   {
3015     int *sprite, code, pal, tile, sx, sy;
3016     int offs, delta, width, height, row;
3017 
3018     offs = (p[entry] & 0x7f) * 2;
3019     sprite = HighPreSpr + offs;
3020     code = sprite[1];
3021     pal = (code>>9)&0x30;
3022 
3023     if (sh && pal == 0x30)
3024     {
3025       if (code & 0x8000) // hi priority
3026       {
3027         if (code&0x800) fTileFunc = TileFlipSH_AS;
3028         else            fTileFunc = TileNormSH_AS;
3029       } else {
3030         if (code&0x800) fTileFunc = TileFlipSH_AS_onlyop_lp;
3031         else            fTileFunc = TileNormSH_AS_onlyop_lp;
3032       }
3033     } else {
3034       if (code & 0x8000) // hi priority
3035       {
3036         if (code&0x800) fTileFunc = TileFlipAS;
3037         else            fTileFunc = TileNormAS;
3038       } else {
3039         if (code&0x800) fTileFunc = TileFlipAS_onlymark;
3040         else            fTileFunc = TileNormAS_onlymark;
3041       }
3042     }
3043 
3044     // parse remaining sprite data
3045     sy=sprite[0];
3046     sx=code>>16; // X
3047     width=sy>>28;
3048     height=(sy>>24)&7; // Width and height in tiles
3049     sy=(sy<<16)>>16; // Y
3050 
3051     row=Scanline-sy; // Row of the sprite we are on
3052 
3053     if (code&0x1000) row=(height<<3)-1-row; // Flip Y
3054 
3055     tile=code + (row>>3); // Tile number increases going down
3056     delta=height; // Delta to increase tile by going right
3057     if (code&0x0800) { tile+=delta*(width-1); delta=-delta; } // Flip X
3058 
3059     tile &= 0x7ff; tile<<=4; tile+=(row&7)<<1; // Tile address
3060     delta<<=4; // Delta of address
3061 
3062     for (; width; width--,sx+=8,tile+=delta)
3063     {
3064       unsigned int pack;
3065 
3066       if(sx<=0)   continue;
3067       if(sx>=328) break; // Offscreen
3068 
3069       pack = *(unsigned int *)(RamVid + (tile & 0x7fff));
3070       fTileFunc(pd + sx, mb + sx, pack, pal|0x8000);
3071     }
3072   }
3073 }
3074 
3075 
3076 // Index + 0  :    ----hhvv -lllllll -------y yyyyyyyy
3077 // Index + 4  :    -------x xxxxxxxx pccvhnnn nnnnnnnn
3078 // v
3079 // Index + 0  :    hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size
3080 // Index + 4  :    xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8
3081 
PrepareSprites(int full)3082 static void PrepareSprites(int full)
3083 {
3084   int u,link=0,sh;
3085   int table=0;
3086   int *pd = HighPreSpr;
3087   int max_lines = 224, max_sprites = 80, max_width = 328;
3088   int max_line_sprites = 20; // 20 sprites, 40 tiles
3089 
3090   if (!(RamVReg->reg[12]&1))
3091     max_sprites = 64, max_line_sprites = 16, max_width = 264;
3092   if (0) //PicoIn.opt & POPT_DIS_SPRITE_LIM)
3093     max_line_sprites = MAX_LINE_SPRITES;
3094 
3095   if (RamVReg->reg[1]&8) max_lines = 240;
3096   sh = RamVReg->reg[0xC]&8; // shadow/hilight?
3097 
3098   table=RamVReg->reg[5]&0x7f;
3099   if (RamVReg->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
3100   table<<=8; // Get sprite table address/2
3101 
3102   if (!full)
3103   {
3104     int pack;
3105     // updates: tilecode, sx
3106     for (u=0; u < max_sprites && (pack = *pd); u++, pd+=2)
3107     {
3108       unsigned int *sprite;
3109       int code2, sx, sy, height;
3110 
3111       sprite=(unsigned int *)(RamVid+((table+(link<<2))&0x7ffc)); // Find sprite
3112 
3113       // parse sprite info
3114       code2 = sprite[1];
3115       sx = (code2>>16)&0x1ff;
3116       sx -= 0x78; // Get X coordinate + 8
3117       sy = (pack << 16) >> 16;
3118       height = (pack >> 24) & 0xf;
3119 
3120       if (sy < max_lines &&
3121 	  sy + (height<<3) > Scanline && // sprite onscreen (y)?
3122           (sx > -24 || sx < max_width))                   // onscreen x
3123       {
3124         int y = (sy >= Scanline) ? sy : Scanline;
3125         int entry = ((pd - HighPreSpr) / 2) | ((code2>>8)&0x80);
3126         for (; y < sy + (height<<3) && y < max_lines; y++)
3127         {
3128           int i, cnt;
3129           cnt = HighLnSpr[y][0] & 0x7f;
3130           if (cnt >= max_line_sprites) continue;              // sprite limit?
3131 
3132           for (i = 0; i < cnt; i++)
3133             if (((HighLnSpr[y][3+i] ^ entry) & 0x7f) == 0) goto found;
3134 
3135           // this sprite was previously missing
3136           HighLnSpr[y][3+cnt] = entry;
3137           HighLnSpr[y][0] = cnt + 1;
3138 found:;
3139           if (entry & 0x80)
3140                HighLnSpr[y][1] |= SPRL_HAVE_HI;
3141           else HighLnSpr[y][1] |= SPRL_HAVE_LO;
3142         }
3143       }
3144 
3145       code2 &= ~0xfe000000;
3146       code2 -=  0x00780000; // Get X coordinate + 8 in upper 16 bits
3147       pd[1] = code2;
3148 
3149       // Find next sprite
3150       link=(sprite[0]>>16)&0x7f;
3151       if (!link) break; // End of sprites
3152     }
3153   }
3154   else
3155   {
3156     for (u = 0; u < max_lines; u++)
3157 	  *((int *)&HighLnSpr[u][0]) = 0;
3158 
3159     for (u = 0; u < max_sprites; u++)
3160     {
3161       unsigned int *sprite;
3162       int code, code2, sx, sy, hv, height, width;
3163 
3164       sprite=(unsigned int *)(RamVid+((table+(link<<2))&0x7ffc)); // Find sprite
3165 
3166       // parse sprite info
3167       code = sprite[0];
3168       sy = (code&0x1ff)-0x80;
3169       hv = (code>>24)&0xf;
3170       height = (hv&3)+1;
3171 
3172       width  = (hv>>2)+1;
3173       code2 = sprite[1];
3174       sx = (code2>>16)&0x1ff;
3175       sx -= 0x78; // Get X coordinate + 8
3176 
3177       if (sy < max_lines && sy + (height<<3) > Scanline) // sprite onscreen (y)?
3178       {
3179         int entry, y, sx_min, onscr_x, maybe_op = 0;
3180 
3181         sx_min = 8-(width<<3);
3182         onscr_x = sx_min < sx && sx < max_width;
3183         if (sh && (code2 & 0x6000) == 0x6000)
3184           maybe_op = SPRL_MAY_HAVE_OP;
3185 
3186         entry = ((pd - HighPreSpr) / 2) | ((code2>>8)&0x80);
3187         y = (sy >= Scanline) ? sy : Scanline;
3188         for (; y < sy + (height<<3) && y < max_lines; y++)
3189         {
3190 		  unsigned char *p = &HighLnSpr[y][0];
3191           int cnt = p[0];
3192           if (cnt >= max_line_sprites) continue;              // sprite limit?
3193 
3194           if (p[2] >= max_line_sprites*2) {        // tile limit?
3195             p[0] |= 0x80;
3196             continue;
3197           }
3198           p[2] += width;
3199 
3200 		  if (sx == -0x78) {
3201 			  if (sy == -1 && is_ribbit) continue; // ribbit: bad sprite:sprite masking on the beach level
3202 
3203 			  //bprintf(0, _T("masked @  %d,%d (x,y)\twidth,height  %x,%x\tcnt/pri %x %x\tScanline  %d\ty  %d\n"), sx, sy, width,height, cnt,(entry & 0x80), Scanline, y);
3204 
3205 			  if (cnt > 0)
3206 				  p[0] |= 0x80; // masked, no more sprites for this line
3207 			  continue;
3208           }
3209           // must keep the first sprite even if it's offscreen, for masking
3210           if (cnt > 0 && !onscr_x) continue; // offscreen x
3211 
3212           p[3+cnt] = entry;
3213           p[0] = cnt + 1;
3214           p[1] |= (entry & 0x80) ? SPRL_HAVE_HI : SPRL_HAVE_LO;
3215           p[1] |= maybe_op; // there might be op sprites on this line
3216           if (cnt > 0 && (code2 & 0x8000) && !(p[3+cnt-1]&0x80))
3217             p[1] |= SPRL_LO_ABOVE_HI;
3218         }
3219       }
3220 
3221       *pd++ = (width<<28)|(height<<24)|(hv<<16)|((unsigned short)sy);
3222       *pd++ = (sx<<16)|((unsigned short)code2);
3223 
3224       // Find next sprite
3225       link=(code>>16)&0x7f;
3226       if (!link) break; // End of sprites
3227     }
3228     *pd = 0;
3229 
3230 #if 0
3231     for (u = 0; u < max_lines; u++)
3232     {
3233       int y;
3234       printf("c%03i: %2i, %2i: ", u, HighLnSpr[u][0] & 0x7f, HighLnSpr[u][2]);
3235       for (y = 0; y < HighLnSpr[u][0] & 0x7f; y++)
3236         printf(" %i", HighLnSpr[u][y+3]);
3237       printf("\n");
3238     }
3239 #endif
3240   }
3241 }
3242 
DrawAllSprites(unsigned char * sprited,int prio,int sh)3243 static void DrawAllSprites(unsigned char *sprited, int prio, int sh)
3244 {
3245   unsigned char *p;
3246   int cnt;
3247 
3248   cnt = sprited[0] & 0x7f;
3249   if (cnt == 0) return;
3250 
3251   p = &sprited[3];
3252 
3253   // Go through sprites backwards:
3254   for (cnt--; cnt >= 0; cnt--)
3255   {
3256     int offs;
3257     if ((p[cnt] >> 7) != prio) continue;
3258     offs = (p[cnt]&0x7f) * 2;
3259     DrawSprite(HighPreSpr + offs, sh);
3260   }
3261 }
3262 
3263 
3264 // --------------------------------------------
3265 
BackFill(INT32 reg7,INT32 sh)3266 static void BackFill(INT32 reg7, INT32 sh)
3267 {
3268 	// Start with a blank scanline (background colour):
3269 	UINT16 *pd = (UINT16 *)(HighCol+8);
3270 	UINT16 *end= (UINT16 *)(HighCol+8+320);
3271 	UINT16 back = (reg7 & 0x3f) | (sh<<6);
3272 	back |= back<<8;
3273 	do { pd[0]=pd[1]=back; pd+=2; } while (pd < end);
3274 }
3275 
3276 
DrawDisplay(int sh)3277 static int DrawDisplay(int sh)
3278 {
3279   unsigned char *sprited = &HighLnSpr[Scanline][0];
3280   int win=0, edge=0, hvwind=0, lflags;
3281   int maxw, maxcells;
3282 
3283   if (RamVReg->rendstatus & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES)) {
3284     // elprintf(EL_STATUS, "PrepareSprites(%i)", (est->rendstatus>>4)&1);
3285     PrepareSprites(RamVReg->rendstatus & PDRAW_DIRTY_SPRITES);
3286     RamVReg->rendstatus &= ~(PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES);
3287   }
3288 
3289   RamVReg->rendstatus &= ~(PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO);
3290 
3291   if (RamVReg->reg[12]&1) {
3292     maxw = 328; maxcells = 40;
3293   } else {
3294     maxw = 264; maxcells = 32;
3295   }
3296 
3297   // Find out if the window is on this line:
3298   win=RamVReg->reg[0x12];
3299   edge=(win&0x1f)<<3;
3300 
3301   if (win&0x80) { if (Scanline>=edge) hvwind=1; }
3302   else          { if (Scanline< edge) hvwind=1; }
3303 
3304   if (!hvwind) // we might have a vertical window here
3305   {
3306     win=RamVReg->reg[0x11];
3307     edge=win&0x1f;
3308     if (win&0x80) {
3309       if (!edge) hvwind=1;
3310       else if(edge < (maxcells>>1)) hvwind=2;
3311     } else {
3312       if (!edge);
3313       else if(edge < (maxcells>>1)) hvwind=2;
3314       else hvwind=1;
3315     }
3316   }
3317 
3318 //  if (hvwind) bprintf(0, _T("we have window! %x\n"), hvwind);
3319 
3320   /* - layer B low - */
3321   if (!(RamVReg->debug_p & PVD_KILL_B)) {
3322     lflags = LF_PLANE_1 | (sh << 1);
3323     if (RamVReg->debug_p & PVD_FORCE_B)
3324       lflags |= LF_FORCE;
3325     DrawLayer(lflags, HighCacheB, 0, maxcells);
3326   }
3327   /* - layer A low - */
3328   lflags = 0 | (sh << 1);
3329   if (RamVReg->debug_p & PVD_FORCE_A)
3330     lflags |= LF_FORCE;
3331   if (RamVReg->debug_p & PVD_KILL_A)
3332     ;
3333   else if (hvwind == 1)
3334     DrawWindow(0, maxcells>>1, 0, sh);
3335   else if (hvwind == 2) {
3336     DrawLayer(lflags, HighCacheA, (win&0x80) ?    0 : edge<<1, (win&0x80) ?     edge<<1 : maxcells);
3337     DrawWindow(                   (win&0x80) ? edge :       0, (win&0x80) ? maxcells>>1 : edge, 0, sh);
3338   }
3339   else
3340     DrawLayer(lflags, HighCacheA, 0, maxcells);
3341   /* - sprites low - */
3342   if (RamVReg->debug_p & PVD_KILL_S_LO)
3343     ;
3344   else if (RamVReg->rendstatus & PDRAW_INTERLACE)
3345     DrawAllSpritesInterlace(0, sh);
3346   else if (sprited[1] & SPRL_HAVE_LO)
3347     DrawAllSprites(sprited, 0, sh);
3348 
3349   /* - layer B hi - */
3350   if (!(RamVReg->debug_p & PVD_KILL_B) && HighCacheB[0])
3351     DrawTilesFromCache(HighCacheB, sh, maxw);
3352   /* - layer A hi - */
3353   if (RamVReg->debug_p & PVD_KILL_A)
3354     ;
3355   else if (hvwind == 1)
3356     DrawWindow(0, maxcells>>1, 1, sh);
3357   else if (hvwind == 2) {
3358     if (HighCacheA[0])
3359       DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : maxw);
3360     DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh);
3361   } else
3362     if (HighCacheA[0])
3363       DrawTilesFromCache(HighCacheA, sh, maxw);
3364   /* - sprites hi - */
3365   if (RamVReg->debug_p & PVD_KILL_S_HI)
3366     ;
3367   else if (RamVReg->rendstatus & PDRAW_INTERLACE)
3368     DrawAllSpritesInterlace(1, sh);
3369   // have sprites without layer pri bit ontop of sprites with that bit
3370   else if ((sprited[1] & 0xd0) == 0xd0 && 1)// (PicoIn.opt & POPT_ACC_SPRITES))
3371     DrawSpritesHiAS(sprited, sh);
3372   else if (sh && (sprited[1] & SPRL_MAY_HAVE_OP))
3373     DrawSpritesSHi(sprited);
3374   else if (sprited[1] & SPRL_HAVE_HI)
3375     DrawAllSprites(sprited, 1, 0);
3376 
3377   if (RamVReg->debug_p & PVD_FORCE_B)
3378     DrawTilesFromCacheForced(HighCacheB);
3379   else if (RamVReg->debug_p & PVD_FORCE_A)
3380     DrawTilesFromCacheForced(HighCacheA);
3381 
3382 #if 0
3383   {
3384     int *c, a, b;
3385     for (a = 0, c = HighCacheA; *c; c++, a++);
3386     for (b = 0, c = HighCacheB; *c; c++, b++);
3387     printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count,
3388            Scanline, a, b);
3389   }
3390 #endif
3391 
3392   return 0;
3393 }
3394 
SetHighCol(INT32 line)3395 static void SetHighCol(INT32 line)
3396 {
3397 	INT32 offset = (~RamVReg->reg[1] & 8) ? 8 : 0;
3398 
3399 	HighCol = HighColFull + ( (offset + line) * (8 + 320 + 8) );
3400 }
3401 
PicoFrameStart()3402 static void PicoFrameStart()
3403 {
3404 	// prepare to do this frame
3405 	RamVReg->status &= ~0x0020;                     // mask collision bit
3406 
3407 	INT32 offs = 8, lines = 224;
3408 
3409 	// prepare to do this frame
3410 	RamVReg->rendstatus = 0;
3411 	if ((RamVReg->reg[12] & 6) == 6)
3412 		RamVReg->rendstatus |= PDRAW_INTERLACE; // interlace mode
3413 	if (!(RamVReg->reg[12] & 1))
3414 		RamVReg->rendstatus |= PDRAW_32_COLS;
3415 	if (RamVReg->reg[1] & 8) {
3416 		offs = 0;
3417 		lines = 240;
3418 	}
3419 
3420 	Scanline = 0;
3421 	BlankedLine = 0;
3422 
3423 	interlacemode2 = ((RamVReg->reg[12] & (4|2)) == (4|2));
3424 
3425 	SetHighCol(0); // start rendering here
3426 
3427 	PrepareSprites(1);
3428 
3429 	RamVReg->status &= ~0x88; // clear V-Int, come out of vblank
3430 	RamVReg->v_counter = 0;
3431 }
3432 
fix_palette(UINT8 * dest8,INT32 DestXY,UINT16 * psrc)3433 static void fix_palette(UINT8 *dest8, INT32 DestXY, UINT16 *psrc)
3434 {
3435 	UINT16 *dest16 = (UINT16*)dest8 + DestXY;
3436 	UINT32 *dest32 = (UINT32*)dest8 + DestXY;
3437 	dest8 += DestXY;
3438 
3439 	for (INT32 x = 0; x < nScreenWidth; x++)
3440 	{
3441 		UINT16 src = psrc[x];
3442 		UINT16 *pPalLUT = (src & 0x8000) ? SegaC2SpPalLookup : SegaC2BgPalLookup;
3443 		UINT32 destrgb = 0;
3444 
3445 		switch (src & 0xc0)
3446 		{
3447 			case 0x00:
3448 				destrgb = DrvPalette[(src & 0x0f) | pPalLUT[(src & 0x30) >> 4] | 0x0000];
3449 				break;
3450 
3451 			case 0x40:
3452 			case 0xc0:
3453 				destrgb = DrvPalette[(src & 0x0f) | pPalLUT[(src & 0x30) >> 4] | 0x0800];
3454 				break;
3455 
3456 			case 0x80:
3457 				destrgb = DrvPalette[(src & 0x0f) | pPalLUT[(src & 0x30) >> 4] | 0x1000];
3458 				break;
3459 		}
3460 
3461 		switch (nBurnBpp) {
3462 			case 4: dest32[x] = destrgb; break;
3463 			case 3: dest8[x*3 + 0] = destrgb; dest8[x*3 + 1] = destrgb >> 8; dest8[x*3 + 2] = destrgb >> 16; break;
3464 			case 2: dest16[x] = destrgb; break;
3465 		}
3466 	}
3467 }
3468 
PicoLine(INT32 y)3469 static INT32 PicoLine(INT32 y)
3470 {
3471 	INT32 lines_vis = 224;
3472 	if (RamVReg->reg[1]&8) lines_vis = 240;
3473 	INT32 vcnt_wrap = 0;
3474 
3475 	irq6_line = lines_vis;
3476 
3477 	// handle fifo and vcounter zoop
3478 	RamVReg->v_counter = y;
3479 	if (y < lines_vis) {
3480 		// VDP FIFO
3481 		RamVReg->lwrite_cnt -= 12;
3482 		if (RamVReg->lwrite_cnt <= 0) {
3483 			RamVReg->lwrite_cnt=0;
3484 			RamVReg->status|=0x200;
3485 		}
3486 		if ((RamVReg->reg[12]&6) == 6) { // interlace mode 2
3487 			RamVReg->v_counter <<= 1;
3488 			RamVReg->v_counter |= RamVReg->v_counter >> 8;
3489 			RamVReg->v_counter &= 0xff;
3490 		}
3491 	} else if (y == lines_vis) {
3492 		vcnt_wrap = (Hardware & 0x40) ? 0x103 : 0xEB; // based on Gens, TODO: verify
3493 		if ((RamVReg->reg[12]&6) == 6) RamVReg->v_counter = 0xc1;
3494 		// VDP FIFO
3495 		RamVReg->lwrite_cnt = 0;
3496 		RamVReg->status |= 0x200;
3497 
3498 		return 0; // ---- don't draw ----
3499 	} else if (y > lines_vis) {
3500 		if (y >= vcnt_wrap)
3501 			RamVReg->v_counter -= (Hardware & 0x40) ? 313 : 262;//(Hardware & 0x40) ? 56 : 6;
3502 		if ((RamVReg->reg[12]&6) == 6)
3503 			RamVReg->v_counter = (RamVReg->v_counter << 1) | 1;
3504 		RamVReg->v_counter &= 0xff;
3505 
3506 		return 0; // ---- don't draw ----
3507 	}
3508 
3509 	INT32 sh = (RamVReg->reg[0xC] & 8)>>3; // shadow/hilight?
3510 
3511 	BackFill(RamVReg->reg[7], sh);
3512 
3513 	INT32 offset = (~RamVReg->reg[1] & 8) ? 8 : 0;
3514 
3515 	if (BlankedLine && Scanline > 0 && !interlacemode2)  // blank last line stuff
3516 	{
3517 		{ // copy blanked line to previous line
3518 //			UINT16 *pDest = LineBuf + ((Scanline-1) * 320) + ((interlacemode2 & RamVReg->field) * 240 * 320);
3519 //			UINT16 *pSrc = HighColFull + (Scanline + offset + ((interlacemode2 & RamVReg->field) * 240))*(8+320+8) + 8;
3520 
3521 //			memcpy(pDest, pSrc, 320 * sizeof(UINT16));
3522 		}
3523 	}
3524 	BlankedLine = 0;
3525 
3526 	if (RamVReg->reg[1] & 0x40)
3527 		DrawDisplay(sh);
3528 
3529 	{
3530 		SetHighCol(Scanline + 1); // Set-up pointer to next line to be rendered to (see: PicoFrameStart();)
3531 
3532 		{ // copy current line to linebuf, for mid-screen palette changes (referred to as SONIC rendering mode, for water & etc.)
3533 			UINT32 DestXY = (Scanline * nScreenWidth) + ((interlacemode2 & RamVReg->field) * 240 * 320);
3534 			UINT16 *pSrc = HighColFull + (Scanline + offset + ((interlacemode2 & RamVReg->field) * 240))*(8+320+8) + 8;
3535 
3536 			if (pBurnDraw) fix_palette(pBurnDraw, DestXY, pSrc);
3537 		}
3538 	}
3539 
3540 	return 0;
3541 }
3542 
DrvDrawBegin()3543 static void DrvDrawBegin() // run in-frame
3544 {
3545 	if (DrvRecalc) {
3546 		for (INT32 i = 0; i < 0x800; i++) {
3547 			palette_update(i);
3548 		}
3549 		DrvPalette[0x3000] = 0; // black
3550 		DrvRecalc = 0;
3551 	}
3552 }
3553 
DrvDrawEnd()3554 static void DrvDrawEnd()
3555 {
3556 	if (!enable_display) {
3557 		BurnTransferClear(0x3000);
3558 		BurnTransferCopy(DrvPalette);
3559 	}
3560 }
3561 
DrvDraw()3562 static INT32 DrvDraw() // called when paused for redraw or mode change
3563 {
3564 	DrvDrawBegin();
3565 
3566 	INT32 offset = (~RamVReg->reg[1] & 8) ? 8 : 0;
3567 
3568 	for (INT32 i = 0; i < nScreenHeight; i++)
3569 	{
3570 		UINT32 DestXY = (i * nScreenWidth) + ((interlacemode2 & RamVReg->field) * 240 * 320);
3571 		UINT16 *pSrc = HighColFull + (i + offset + ((interlacemode2 & RamVReg->field) * 240))*(8+320+8) + 8;
3572 
3573 		if (pBurnDraw) fix_palette(pBurnDraw, DestXY, pSrc);
3574 	}
3575 
3576 	DrvDrawEnd();
3577 
3578 	return 0;
3579 }
3580 
DrvFrame()3581 static INT32 DrvFrame()
3582 {
3583 	if (DrvReset) {
3584 		DrvDoReset();
3585 	}
3586 
3587 	SekNewFrame();
3588 	NullNewFrame();
3589 
3590 	{
3591 		memset (DrvInputs, 0xff, sizeof(DrvInputs));
3592 
3593 		for (INT32 i = 0; i < 8; i++) {
3594 			DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
3595 			DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
3596 			DrvInputs[4] ^= (DrvJoy3[i] & 1) << i;
3597 		}
3598 		DrvInputs[5] = DrvDips[0];
3599 		DrvInputs[6] = DrvDips[1];
3600 
3601 		if (is_wwmarine) {
3602 			DrvInputs[0] |= (nCurrentFrame & 1) * 0xc0; // l/r pulsed by digital steering wheel
3603 		}
3604 
3605 		if (has_dial) {
3606 			BurnTrackballConfig(0, AXIS_NORMAL, AXIS_NORMAL);
3607 			BurnTrackballFrame(0, Analog[0], Analog[1], 1, 0x1f);
3608 			BurnTrackballUpdate(0);
3609 			DrvInputs[0] = BurnTrackballRead(0, 0);
3610 			DrvInputs[1] = BurnTrackballRead(0, 1);
3611 		}
3612 	}
3613 
3614 	if (pBurnDraw) DrvDrawBegin(); // re-calc palette if necessary
3615 
3616 	PicoFrameStart();
3617 
3618 	INT32 nInterleave = 262;
3619 	INT32 nCyclesTotal[2] = { (INT32)(53693175 / 6 / 59.922745), (INT32)(53693175 / 6 / 59.922745) };
3620 	INT32 nCyclesDone[2] = { 0, 0 };
3621 
3622 	SekOpen(0);
3623 	SekIdle(nExtraCycles[0]);
3624 
3625 	irq4_counter = RamVReg->reg[0x0a];
3626 
3627 	for (INT32 i = 0; i < nInterleave; i++)
3628 	{
3629 		Scanline = i;
3630 		line_base_cycles = SekTotalCycles();
3631 
3632 		SekIdle(DMABURN());
3633 
3634 		CPU_RUN_SYNCINT(0, Sek);
3635 		CPU_RUN_TIMER(1); // nullcpu for fm timer (we can't have the fm timer breaking Sek execution)
3636 
3637 		PicoLine(Scanline); // draw & blit line
3638 
3639 		if (Scanline <= 224) {
3640 			irq4_counter--;
3641 			if (irq4_counter < 0) {
3642 				irq4_counter = RamVReg->reg[0x0a];
3643 				RamVReg->pending_ints |= 0x10;
3644 				if (RamVReg->reg[0x00] & 0x10) {
3645 					SekSetVIRQLine(4, CPU_IRQSTATUS_ACK);
3646 				}
3647 			}
3648 		}
3649 		if (Scanline == irq6_line) {
3650 			RamVReg->status |= 0x08; // V-Int
3651 			RamVReg->pending_ints |= 0x20;
3652 			SekRun(68); // this is called "v-int lag" on megadrive
3653 			SekSetVIRQLine(6, CPU_IRQSTATUS_ACK);  // irq hooked to z80_irq (vdp), not the usual vdp vblank line!
3654 
3655 			if (pBurnDraw) DrvDrawEnd();
3656 		}
3657 	}
3658 
3659 	if (pBurnSoundOut) {
3660 		BurnYM3438Update(pBurnSoundOut, nBurnSoundLen);
3661 		if (sound_rom_length) {
3662 			UPD7759Render(pBurnSoundOut, nBurnSoundLen);
3663 		}
3664 	}
3665 
3666 	nExtraCycles[0] = SekTotalCycles() - nCyclesTotal[0];
3667 
3668 	SekClose();
3669 
3670 	return 0;
3671 }
3672 
DrvScan(INT32 nAction,INT32 * pnMin)3673 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
3674 {
3675 	struct BurnArea ba;
3676 
3677 	if (pnMin != NULL) {
3678 		*pnMin = 0x029709;
3679 	}
3680 
3681 	if (nAction & ACB_MEMORY_RAM) {
3682 		memset(&ba, 0, sizeof(ba));
3683 		ba.Data	  = AllRam;
3684 		ba.nLen	  = RamEnd-AllRam;
3685 		ba.szName = "All Ram";
3686 		BurnAcb(&ba);
3687 	}
3688 
3689 	if (nAction & ACB_DRIVER_DATA) {
3690 		SekScan(nAction);
3691 
3692 		BurnYM3438Scan(nAction, pnMin);
3693 		if (sound_rom_length) UPD7759Scan(nAction, pnMin);
3694 		SN76496Scan(nAction, pnMin);
3695 
3696 		if (has_dial) BurnTrackballScan();
3697 
3698 		SCAN_VAR(prot_write_buf);
3699 		SCAN_VAR(prot_read_buf);
3700 		SCAN_VAR(enable_display);
3701 		SCAN_VAR(alt_palette_mode);
3702 		SCAN_VAR(palette_bank);
3703 		SCAN_VAR(bg_palbase);
3704 		SCAN_VAR(sp_palbase);
3705 		SCAN_VAR(output_latch);
3706 		SCAN_VAR(dir);
3707 		SCAN_VAR(iocnt);
3708 		SCAN_VAR(sound_bank);
3709 		SCAN_VAR(irq6_line);
3710 		SCAN_VAR(irq4_counter);
3711 		SCAN_VAR(SegaC2BgPalLookup);
3712 		SCAN_VAR(SegaC2SpPalLookup);
3713 
3714 		SCAN_VAR(Hardware);
3715 		SCAN_VAR(dma_xfers);
3716 		SCAN_VAR(BlankedLine);
3717 		SCAN_VAR(interlacemode2);
3718 
3719 		SCAN_VAR(nExtraCycles);
3720 	}
3721 
3722 	if (nAction & ACB_WRITE) {
3723 		recompute_palette_tables();
3724 
3725 		if (sound_rom_length) {
3726 			memcpy (DrvSndROM + 0x80000, DrvSndROM + (sound_bank * 0x20000), 0x20000);
3727 		}
3728 	}
3729 
3730 	return 0;
3731 }
3732 
3733 
3734 // Bloxeed (World, C System)
3735 
3736 static struct BurnRomInfo bloxeedcRomDesc[] = {
3737 	{ "epr-12908.ic32",			0x20000, 0xfc77cb91, 3 | BRF_PRG | BRF_ESS }, //  0 68K Code
3738 	{ "epr-12907.ic31",			0x20000, 0xe5fcbac6, 3 | BRF_PRG | BRF_ESS }, //  1
3739 	{ "epr-12993.ic34",			0x20000, 0x487bc8fc, 3 | BRF_PRG | BRF_ESS }, //  2
3740 	{ "epr-12992.ic33",			0x20000, 0x19b0084c, 3 | BRF_PRG | BRF_ESS }, //  3
3741 };
3742 
3743 STD_ROM_PICK(bloxeedc)
STD_ROM_FN(bloxeedc)3744 STD_ROM_FN(bloxeedc)
3745 
3746 static UINT8 no_protection_callback(UINT8 in)
3747 {
3748 	return 0;
3749 }
3750 
NoProtectionInit()3751 static INT32 NoProtectionInit()
3752 {
3753 	return SegaC2Init(no_protection_callback);
3754 }
3755 
3756 struct BurnDriver BurnDrvBloxeedc = {
3757 	"bloxeedc", "bloxeed", NULL, NULL, "1989",
3758 	"Bloxeed (World, C System)\0", NULL, "Sega / Elorg", "C",
3759 	NULL, NULL, NULL, NULL,
3760 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3761 	NULL, bloxeedcRomInfo, bloxeedcRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, BloxeedcDIPInfo,
3762 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3763 	320, 224, 4, 3
3764 };
3765 
3766 
3767 // Bloxeed (US, C System, Rev A)
3768 
3769 static struct BurnRomInfo bloxeeduRomDesc[] = {
3770 	{ "epr-12997a.ic32",		0x20000, 0x23655bc9, 3 | BRF_PRG | BRF_ESS }, //  0 68K Code
3771 	{ "epr-12996a.ic31",		0x20000, 0x83c83f0c, 3 | BRF_PRG | BRF_ESS }, //  1
3772 	{ "epr-12993.ic34",			0x20000, 0x487bc8fc, 3 | BRF_PRG | BRF_ESS }, //  2
3773 	{ "epr-12992.ic33",			0x20000, 0x19b0084c, 3 | BRF_PRG | BRF_ESS }, //  3
3774 
3775 	{ "315-5393.ic24",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  4 pals
3776 	{ "315-5394.ic25",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  5
3777 	{ "315-5395.ic26",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  6
3778 	{ "317-0140.ic27",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  7
3779 };
3780 
3781 STD_ROM_PICK(bloxeedu)
3782 STD_ROM_FN(bloxeedu)
3783 
3784 struct BurnDriver BurnDrvBloxeedu = {
3785 	"bloxeedu", "bloxeed", NULL, NULL, "1989",
3786 	"Bloxeed (US, C System, Rev A)\0", NULL, "Sega / Elorg", "C",
3787 	NULL, NULL, NULL, NULL,
3788 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3789 	NULL, bloxeeduRomInfo, bloxeeduRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, BloxeeduDIPInfo,
3790 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3791 	320, 224, 4, 3
3792 };
3793 
3794 
3795 // Columns (World)
3796 
3797 static struct BurnRomInfo columnsRomDesc[] = {
3798 	{ "epr-13114.ic32",			0x20000, 0xff78f740, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3799 	{ "epr-13113.ic31",			0x20000, 0x9a426d9b, 1 | BRF_PRG | BRF_ESS }, //  1
3800 };
3801 
3802 STD_ROM_PICK(columns)
STD_ROM_FN(columns)3803 STD_ROM_FN(columns)
3804 
3805 static UINT8 columns_protection_callback(UINT8 in)
3806 {
3807 	static const UINT8 prot_lut_table[0x100] = {
3808 		0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x09, 0x07, 0x06, 0x04, 0x0e, 0x00, 0x05, 0x07, 0x0d, 0x03,
3809 		0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x09, 0x07, 0x06, 0x04, 0x0e, 0x00, 0x05, 0x07, 0x0d, 0x03,
3810 		0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x09, 0x07, 0x06, 0x04, 0x0e, 0x00, 0x05, 0x07, 0x0d, 0x03,
3811 		0x0a, 0x08, 0x02, 0x04, 0x09, 0x0b, 0x01, 0x07, 0x0e, 0x0c, 0x06, 0x00, 0x0d, 0x0f, 0x05, 0x03,
3812 		0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x09, 0x07, 0x06, 0x04, 0x0e, 0x00, 0x05, 0x07, 0x0d, 0x03,
3813 		0x07, 0x05, 0x0f, 0x05, 0x04, 0x06, 0x0c, 0x06, 0x03, 0x01, 0x0b, 0x01, 0x00, 0x02, 0x08, 0x02,
3814 		0x02, 0x00, 0x0a, 0x04, 0x01, 0x03, 0x09, 0x07, 0x06, 0x04, 0x0e, 0x00, 0x05, 0x07, 0x0d, 0x03,
3815 		0x0f, 0x0d, 0x07, 0x05, 0x0c, 0x0e, 0x04, 0x06, 0x0b, 0x09, 0x03, 0x01, 0x08, 0x0a, 0x00, 0x02,
3816 		0x0b, 0x08, 0x03, 0x04, 0x08, 0x0b, 0x00, 0x07, 0x0f, 0x0c, 0x07, 0x00, 0x0c, 0x0f, 0x04, 0x03,
3817 		0x0b, 0x08, 0x03, 0x04, 0x08, 0x0b, 0x00, 0x07, 0x0f, 0x0c, 0x07, 0x00, 0x0c, 0x0f, 0x04, 0x03,
3818 		0x09, 0x0a, 0x01, 0x06, 0x08, 0x0b, 0x00, 0x07, 0x0d, 0x0e, 0x05, 0x02, 0x0c, 0x0f, 0x04, 0x03,
3819 		0x09, 0x0a, 0x01, 0x06, 0x08, 0x0b, 0x00, 0x07, 0x0d, 0x0e, 0x05, 0x02, 0x0c, 0x0f, 0x04, 0x03,
3820 		0x03, 0x00, 0x0b, 0x04, 0x00, 0x03, 0x08, 0x07, 0x07, 0x04, 0x0f, 0x00, 0x04, 0x07, 0x0c, 0x03,
3821 		0x07, 0x05, 0x0f, 0x05, 0x04, 0x06, 0x0c, 0x06, 0x03, 0x01, 0x0b, 0x01, 0x00, 0x02, 0x08, 0x02,
3822 		0x03, 0x00, 0x0b, 0x04, 0x00, 0x03, 0x08, 0x07, 0x07, 0x04, 0x0f, 0x00, 0x04, 0x07, 0x0c, 0x03,
3823 		0x0f, 0x0d, 0x07, 0x05, 0x0c, 0x0e, 0x04, 0x06, 0x0b, 0x09, 0x03, 0x01, 0x08, 0x0a, 0x00, 0x02
3824 	};
3825 
3826 	return prot_lut_table[in];
3827 }
3828 
ColumnsInit()3829 static INT32 ColumnsInit()
3830 {
3831 	return SegaC2Init(columns_protection_callback);
3832 }
3833 
3834 struct BurnDriver BurnDrvColumns = {
3835 	"columns", NULL, NULL, NULL, "1990",
3836 	"Columns (World)\0", NULL, "Sega", "C",
3837 	NULL, NULL, NULL, NULL,
3838 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3839 	NULL, columnsRomInfo, columnsRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, ColumnsDIPInfo,
3840 	ColumnsInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3841 	320, 224, 4, 3
3842 };
3843 
3844 
3845 // Columns (US, cocktail, Rev A)
3846 
3847 static struct BurnRomInfo columnsuRomDesc[] = {
3848 	{ "epr-13116a.ic32",		0x20000, 0xa0284b16, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3849 	{ "epr-13115a.ic31",		0x20000, 0xe37496f3, 1 | BRF_PRG | BRF_ESS }, //  1
3850 };
3851 
3852 STD_ROM_PICK(columnsu)
3853 STD_ROM_FN(columnsu)
3854 
3855 struct BurnDriver BurnDrvColumnsu = {
3856 	"columnsu", "columns", NULL, NULL, "1990",
3857 	"Columns (US, cocktail, Rev A)\0", NULL, "Sega", "C",
3858 	NULL, NULL, NULL, NULL,
3859 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3860 	NULL, columnsuRomInfo, columnsuRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, ColumnsDIPInfo,
3861 	ColumnsInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3862 	320, 224, 4, 3
3863 };
3864 
3865 
3866 // Columns (Japan)
3867 
3868 static struct BurnRomInfo columnsjRomDesc[] = {
3869 	{ "epr-13112.ic32",			0x20000, 0xbae6e53e, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3870 	{ "epr-13111.ic31",			0x20000, 0xaa5ccd6d, 1 | BRF_PRG | BRF_ESS }, //  1
3871 };
3872 
3873 STD_ROM_PICK(columnsj)
3874 STD_ROM_FN(columnsj)
3875 
3876 struct BurnDriver BurnDrvColumnsj = {
3877 	"columnsj", "columns", NULL, NULL, "1990",
3878 	"Columns (Japan)\0", NULL, "Sega", "C",
3879 	NULL, NULL, NULL, NULL,
3880 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3881 	NULL, columnsjRomInfo, columnsjRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, ColumnsDIPInfo,
3882 	ColumnsInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3883 	320, 224, 4, 3
3884 };
3885 
3886 
3887 // Columns II: The Voyage Through Time (World)
3888 
3889 static struct BurnRomInfo columns2RomDesc[] = {
3890 	{ "epr-13363.ic32",			0x20000, 0xc99e4ffd, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3891 	{ "epr-13362.ic31",			0x20000, 0x394e2419, 1 | BRF_PRG | BRF_ESS }, //  1
3892 };
3893 
3894 STD_ROM_PICK(columns2)
STD_ROM_FN(columns2)3895 STD_ROM_FN(columns2)
3896 
3897 static UINT8 columns2_protection_callback(UINT8 in)
3898 {
3899 	static const UINT8 prot_lut_table[0x100] = {
3900 		0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x00, 0x0c,
3901 		0x08, 0x08, 0x09, 0x0d, 0x09, 0x09, 0x08, 0x04, 0x0c, 0x0e, 0x0d, 0x0b, 0x09, 0x0b, 0x08, 0x06,
3902 		0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x04, 0x0c,
3903 		0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x04, 0x09, 0x0b, 0x09, 0x0b, 0x0c, 0x0e, 0x0c, 0x06,
3904 		0x02, 0x02, 0x03, 0x07, 0x03, 0x03, 0x02, 0x0e, 0x02, 0x02, 0x03, 0x07, 0x03, 0x03, 0x02, 0x0e,
3905 		0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0e, 0x02, 0x00, 0x03, 0x01, 0x07, 0x05, 0x06, 0x0c,
3906 		0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0e, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0e,
3907 		0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x0e, 0x03, 0x01, 0x03, 0x01, 0x06, 0x04, 0x06, 0x0c,
3908 		0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x00, 0x0c,
3909 		0x08, 0x08, 0x09, 0x0d, 0x09, 0x09, 0x08, 0x04, 0x0c, 0x0e, 0x0d, 0x0b, 0x09, 0x0b, 0x08, 0x06,
3910 		0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0e, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0e,
3911 		0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x06, 0x0b, 0x09, 0x0b, 0x09, 0x0e, 0x0c, 0x0e, 0x04,
3912 		0x0a, 0x0a, 0x0b, 0x0f, 0x0b, 0x0b, 0x0a, 0x06, 0x0a, 0x0a, 0x0b, 0x0f, 0x0b, 0x0b, 0x0a, 0x06,
3913 		0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x06, 0x0a, 0x08, 0x0b, 0x09, 0x0f, 0x0d, 0x0e, 0x04,
3914 		0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x06, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x06,
3915 		0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x06, 0x0b, 0x09, 0x0b, 0x09, 0x0e, 0x0c, 0x0e, 0x04
3916 	};
3917 
3918 	return prot_lut_table[in];
3919 }
3920 
Columns2Init()3921 static INT32 Columns2Init()
3922 {
3923 	return SegaC2Init(columns2_protection_callback);
3924 }
3925 
3926 struct BurnDriver BurnDrvColumns2 = {
3927 	"columns2", NULL, NULL, NULL, "1990",
3928 	"Columns II: The Voyage Through Time (World)\0", NULL, "Sega", "C",
3929 	NULL, NULL, NULL, NULL,
3930 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3931 	NULL, columns2RomInfo, columns2RomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, Columns2DIPInfo,
3932 	Columns2Init, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3933 	320, 224, 4, 3
3934 };
3935 
3936 
3937 // Columns II: The Voyage Through Time (Japan)
3938 
3939 static struct BurnRomInfo column2jRomDesc[] = {
3940 	{ "epr-13361.ic32",			0x20000, 0xb54b5f12, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3941 	{ "epr-13360.ic31",			0x20000, 0xa59b1d4f, 1 | BRF_PRG | BRF_ESS }, //  1
3942 };
3943 
3944 STD_ROM_PICK(column2j)
3945 STD_ROM_FN(column2j)
3946 
3947 struct BurnDriver BurnDrvColumn2j = {
3948 	"column2j", "columns2", NULL, NULL, "1990",
3949 	"Columns II: The Voyage Through Time (Japan)\0", NULL, "Sega", "C",
3950 	NULL, NULL, NULL, NULL,
3951 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
3952 	NULL, column2jRomInfo, column2jRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, Columns2DIPInfo,
3953 	Columns2Init, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
3954 	320, 224, 4, 3
3955 };
3956 
3957 
3958 // Thunder Force AC
3959 
3960 static struct BurnRomInfo tfrceacRomDesc[] = {
3961 	{ "epr-13675.ic32",			0x40000, 0x95ecf202, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
3962 	{ "epr-13674.ic31",			0x40000, 0xe63d7f1a, 1 | BRF_PRG | BRF_ESS }, //  1
3963 	{ "epr-13659.ic34",			0x40000, 0x29f23461, 1 | BRF_PRG | BRF_ESS }, //  2
3964 	{ "epr-13658.ic33",			0x40000, 0x9e23734f, 1 | BRF_PRG | BRF_ESS }, //  3
3965 
3966 	{ "epr-13655.ic4",			0x40000, 0xe09961f6, 2 | BRF_SND },           //  4 UPD Samples
3967 };
3968 
3969 STD_ROM_PICK(tfrceac)
STD_ROM_FN(tfrceac)3970 STD_ROM_FN(tfrceac)
3971 
3972 static UINT8 tfrceac_protection_callback(UINT8 in)
3973 {
3974 	static const UINT8 prot_lut_table[0x100] = {
3975 		0x03, 0x0a, 0x03, 0x0a, 0x06, 0x0f, 0x06, 0x0f, 0x03, 0x08, 0x03, 0x08, 0x06, 0x0d, 0x06, 0x0d,
3976 		0x03, 0x0a, 0x03, 0x0a, 0x06, 0x0f, 0x06, 0x0f, 0x02, 0x08, 0x02, 0x08, 0x07, 0x0d, 0x07, 0x0d,
3977 		0x03, 0x0a, 0x03, 0x0a, 0x06, 0x0f, 0x06, 0x0f, 0x03, 0x08, 0x03, 0x08, 0x06, 0x0d, 0x06, 0x0d,
3978 		0x03, 0x0a, 0x03, 0x0a, 0x06, 0x0f, 0x06, 0x0f, 0x02, 0x08, 0x02, 0x08, 0x07, 0x0d, 0x07, 0x0d,
3979 		0x07, 0x0e, 0x03, 0x0a, 0x02, 0x0b, 0x06, 0x0f, 0x07, 0x0c, 0x03, 0x08, 0x02, 0x09, 0x06, 0x0d,
3980 		0x07, 0x0e, 0x0b, 0x02, 0x02, 0x0b, 0x0e, 0x07, 0x06, 0x0c, 0x0a, 0x00, 0x03, 0x09, 0x0f, 0x05,
3981 		0x07, 0x0e, 0x03, 0x0a, 0x02, 0x0b, 0x06, 0x0f, 0x07, 0x0c, 0x03, 0x08, 0x02, 0x09, 0x06, 0x0d,
3982 		0x07, 0x0e, 0x0b, 0x02, 0x02, 0x0b, 0x0e, 0x07, 0x06, 0x0c, 0x0a, 0x00, 0x03, 0x09, 0x0f, 0x05,
3983 		0x03, 0x0b, 0x03, 0x0b, 0x06, 0x0e, 0x06, 0x0e, 0x03, 0x09, 0x03, 0x09, 0x06, 0x0c, 0x06, 0x0c,
3984 		0x05, 0x0d, 0x0d, 0x05, 0x00, 0x08, 0x08, 0x00, 0x04, 0x0e, 0x0c, 0x06, 0x01, 0x0b, 0x09, 0x03,
3985 		0x03, 0x0b, 0x03, 0x0b, 0x06, 0x0e, 0x06, 0x0e, 0x03, 0x09, 0x03, 0x09, 0x06, 0x0c, 0x06, 0x0c,
3986 		0x03, 0x0b, 0x0b, 0x03, 0x06, 0x0e, 0x0e, 0x06, 0x02, 0x08, 0x0a, 0x00, 0x07, 0x0d, 0x0f, 0x05,
3987 		0x05, 0x0d, 0x01, 0x09, 0x00, 0x08, 0x04, 0x0c, 0x05, 0x0d, 0x01, 0x09, 0x00, 0x08, 0x04, 0x0c,
3988 		0x07, 0x0f, 0x0f, 0x07, 0x02, 0x0a, 0x0a, 0x02, 0x06, 0x0e, 0x0e, 0x06, 0x03, 0x0b, 0x0b, 0x03,
3989 		0x05, 0x0d, 0x01, 0x09, 0x00, 0x08, 0x04, 0x0c, 0x05, 0x0d, 0x01, 0x09, 0x00, 0x08, 0x04, 0x0c,
3990 		0x05, 0x0d, 0x09, 0x01, 0x00, 0x08, 0x0c, 0x04, 0x04, 0x0c, 0x08, 0x00, 0x01, 0x09, 0x0d, 0x05,
3991 	};
3992 
3993 	return prot_lut_table[in];
3994 }
3995 
TfrceacInit()3996 static INT32 TfrceacInit()
3997 {
3998 	return SegaC2Init(tfrceac_protection_callback);
3999 }
4000 
4001 struct BurnDriver BurnDrvTfrceac = {
4002 	"tfrceac", NULL, NULL, NULL, "1990",
4003 	"Thunder Force AC\0", NULL, "Technosoft / Sega", "C2",
4004 	NULL, NULL, NULL, NULL,
4005 	BDF_GAME_WORKING, 1, HARDWARE_SEGA_MISC, GBF_HORSHOOT, 0,
4006 	NULL, tfrceacRomInfo, tfrceacRomName, NULL, NULL, NULL, NULL, SegaC2_3ButtonInputInfo, TfrceacDIPInfo,
4007 	TfrceacInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4008 	320, 224, 4, 3
4009 };
4010 
4011 
4012 // Thunder Force AC (Japan)
4013 
4014 static struct BurnRomInfo tfrceacjRomDesc[] = {
4015 	{ "epr-13657.ic32",			0x40000, 0xa0f38ffd, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4016 	{ "epr-13656.ic31",			0x40000, 0xb9438d1e, 1 | BRF_PRG | BRF_ESS }, //  1
4017 	{ "epr-13659.ic34",			0x40000, 0x29f23461, 1 | BRF_PRG | BRF_ESS }, //  2
4018 	{ "epr-13658.ic33",			0x40000, 0x9e23734f, 1 | BRF_PRG | BRF_ESS }, //  3
4019 
4020 	{ "epr-13655.ic4",			0x40000, 0xe09961f6, 2 | BRF_SND },           //  4 UPD Samples
4021 };
4022 
4023 STD_ROM_PICK(tfrceacj)
4024 STD_ROM_FN(tfrceacj)
4025 
4026 struct BurnDriver BurnDrvTfrceacj = {
4027 	"tfrceacj", "tfrceac", NULL, NULL, "1990",
4028 	"Thunder Force AC (Japan)\0", NULL, "Technosoft / Sega", "C2",
4029 	NULL, NULL, NULL, NULL,
4030 	BDF_GAME_WORKING | BDF_CLONE, 1, HARDWARE_SEGA_MISC, GBF_HORSHOOT, 0,
4031 	NULL, tfrceacjRomInfo, tfrceacjRomName, NULL, NULL, NULL, NULL, SegaC2_3ButtonInputInfo, TfrceacDIPInfo,
4032 	TfrceacInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4033 	320, 224, 4, 3
4034 };
4035 
4036 
4037 // Thunder Force AC (Japan, prototype, bootleg)
4038 
4039 static struct BurnRomInfo tfrceacjpbRomDesc[] = {
4040 	{ "ic32_t.f.ac_075f.ic32",	0x40000, 0x2167dd93, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4041 	{ "ic31_t.f.ac_0d26.id31",	0x40000, 0xebf02bba, 1 | BRF_PRG | BRF_ESS }, //  1
4042 	{ "ic34_t.f.ac_549d.ic34",	0x40000, 0x902ad2ec, 1 | BRF_PRG | BRF_ESS }, //  2
4043 	{ "ic33_t.f.ac_d131.ic33",	0x40000, 0xb162219d, 1 | BRF_PRG | BRF_ESS }, //  3
4044 };
4045 
4046 STD_ROM_PICK(tfrceacjpb)
STD_ROM_FN(tfrceacjpb)4047 STD_ROM_FN(tfrceacjpb)
4048 
4049 static INT32 TfrceacjpbInit()
4050 {
4051 	INT32 rc = SegaC2Init(tfrceac_protection_callback);
4052 	dir_override = 0xf; // issue w/io chip
4053 
4054 	return rc;
4055 }
4056 
4057 struct BurnDriver BurnDrvTfrceacjpb = {
4058 	"tfrceacjpb", "tfrceac", NULL, NULL, "1990",
4059 	"Thunder Force AC (Japan, prototype, bootleg)\0", NULL, "Technosoft / Sega", "C2",
4060 	NULL, NULL, NULL, NULL,
4061 	BDF_GAME_WORKING | BDF_CLONE | BDF_PROTOTYPE | BDF_BOOTLEG, 1, HARDWARE_SEGA_MISC, GBF_HORSHOOT, 0,
4062 	NULL, tfrceacjpbRomInfo, tfrceacjpbRomName, NULL, NULL, NULL, NULL, SegaC2_3ButtonInputInfo, TfrceacDIPInfo,
4063 	TfrceacjpbInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4064 	320, 224, 4, 3
4065 };
4066 
4067 
4068 // Thunder Force AC (bootleg)
4069 
4070 static struct BurnRomInfo tfrceacbRomDesc[] = {
4071 	{ "4.bin",					0x40000, 0xeba059d3, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4072 	{ "3.bin",					0x40000, 0x3e5dc542, 1 | BRF_PRG | BRF_ESS }, //  1
4073 	{ "epr-13659.ic34",			0x40000, 0x29f23461, 1 | BRF_PRG | BRF_ESS }, //  2
4074 	{ "epr-13658.ic33",			0x40000, 0x9e23734f, 1 | BRF_PRG | BRF_ESS }, //  3
4075 
4076 	{ "epr-13655.ic4",			0x40000, 0xe09961f6, 2 | BRF_SND },           //  4 UPD Samples
4077 };
4078 
4079 STD_ROM_PICK(tfrceacb)
STD_ROM_FN(tfrceacb)4080 STD_ROM_FN(tfrceacb)
4081 
4082 static INT32 TfrceacbInit()
4083 {
4084 	is_tfrceacb = 1;
4085 
4086 	return SegaC2Init(no_protection_callback);
4087 }
4088 
4089 struct BurnDriver BurnDrvTfrceacb = {
4090 	"tfrceacb", "tfrceac", NULL, NULL, "1990",
4091 	"Thunder Force AC (bootleg)\0", NULL, "bootleg", "C2",
4092 	NULL, NULL, NULL, NULL,
4093 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 1, HARDWARE_SEGA_MISC, GBF_HORSHOOT, 0,
4094 	NULL, tfrceacbRomInfo, tfrceacbRomName, NULL, NULL, NULL, NULL, SegaC2_3ButtonInputInfo, TfrceacDIPInfo,
4095 	TfrceacbInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4096 	320, 224, 4, 3
4097 };
4098 
4099 
4100 // Borench (set 1)
4101 
4102 static struct BurnRomInfo borenchRomDesc[] = {
4103 	{ "ic32.bin",				0x40000, 0x2c54457d, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4104 	{ "ic31.bin",				0x40000, 0xb46445fc, 1 | BRF_PRG | BRF_ESS }, //  1
4105 
4106 	{ "epr-13587.ic4",			0x20000, 0x62b85e56, 2 | BRF_SND },           //  2 UPD Samples
4107 };
4108 
4109 STD_ROM_PICK(borench)
STD_ROM_FN(borench)4110 STD_ROM_FN(borench)
4111 
4112 static UINT8 borench_protection_callback(UINT8 in)
4113 {
4114 	static const UINT8 prot_lut_table[0x100] = {
4115 		0x01, 0x02, 0x0f, 0x0e, 0x05, 0x06, 0x0b, 0x0a, 0x05, 0x06, 0x0b, 0x0a, 0x05, 0x06, 0x0b, 0x0a,
4116 		0x00, 0x00, 0x0a, 0x0a, 0x04, 0x04, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e,
4117 		0x01, 0x03, 0x0f, 0x0f, 0x05, 0x07, 0x0b, 0x0b, 0x07, 0x05, 0x09, 0x09, 0x05, 0x07, 0x0b, 0x0b,
4118 		0x01, 0x01, 0x0b, 0x0b, 0x05, 0x05, 0x0f, 0x0f, 0x0f, 0x0f, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f,
4119 		0x01, 0x02, 0x0b, 0x0a, 0x05, 0x06, 0x0f, 0x0e, 0x05, 0x06, 0x0f, 0x0e, 0x05, 0x06, 0x0f, 0x0e,
4120 		0x00, 0x00, 0x0a, 0x0a, 0x04, 0x04, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e,
4121 		0x09, 0x03, 0x03, 0x0b, 0x0d, 0x07, 0x07, 0x0f, 0x0f, 0x05, 0x05, 0x0d, 0x0d, 0x07, 0x07, 0x0f,
4122 		0x09, 0x01, 0x03, 0x0b, 0x0d, 0x05, 0x07, 0x0f, 0x07, 0x0f, 0x05, 0x0d, 0x05, 0x0d, 0x07, 0x0f,
4123 		0x01, 0x02, 0x0f, 0x0e, 0x05, 0x06, 0x0b, 0x0a, 0x05, 0x06, 0x0b, 0x0a, 0x05, 0x06, 0x0a, 0x0b,
4124 		0x00, 0x00, 0x0a, 0x0a, 0x04, 0x04, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0f, 0x0f,
4125 		0x0d, 0x07, 0x03, 0x0b, 0x0d, 0x07, 0x03, 0x0b, 0x0f, 0x05, 0x01, 0x09, 0x0d, 0x07, 0x02, 0x0a,
4126 		0x0d, 0x05, 0x07, 0x0f, 0x0d, 0x05, 0x07, 0x0f, 0x07, 0x0f, 0x05, 0x0d, 0x05, 0x0d, 0x06, 0x0e,
4127 		0x01, 0x02, 0x0b, 0x0a, 0x05, 0x06, 0x0f, 0x0e, 0x05, 0x06, 0x0f, 0x0e, 0x05, 0x06, 0x0e, 0x0f,
4128 		0x00, 0x00, 0x0a, 0x0a, 0x04, 0x04, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0f, 0x0f,
4129 		0x0d, 0x07, 0x07, 0x0f, 0x0d, 0x07, 0x07, 0x0f, 0x0f, 0x05, 0x05, 0x0d, 0x0d, 0x07, 0x06, 0x0e,
4130 		0x0d, 0x05, 0x07, 0x0f, 0x0d, 0x05, 0x07, 0x0f, 0x07, 0x0f, 0x05, 0x0d, 0x05, 0x0d, 0x06, 0x0e
4131 	};
4132 
4133 	return prot_lut_table[in];
4134 }
4135 
BorenchInit()4136 static INT32 BorenchInit()
4137 {
4138 	return SegaC2Init(borench_protection_callback);
4139 }
4140 
4141 struct BurnDriver BurnDrvBorench = {
4142 	"borench", NULL, NULL, NULL, "1990",
4143 	"Borench (set 1)\0", NULL, "Sega", "C2",
4144 	NULL, NULL, NULL, NULL,
4145 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4146 	NULL, borenchRomInfo, borenchRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, BorenchDIPInfo,
4147 	BorenchInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4148 	320, 224, 4, 3
4149 };
4150 
4151 
4152 // Borench (set 2)
4153 
4154 static struct BurnRomInfo borenchaRomDesc[] = {
4155 	{ "epr-13591.ic32",			0x40000, 0x7851078b, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4156 	{ "epr-13590.ic31",			0x40000, 0x01bc6fe6, 1 | BRF_PRG | BRF_ESS }, //  1
4157 
4158 	{ "epr-13587.ic4",			0x20000, 0x62b85e56, 2 | BRF_SND },           //  2 UPD Samples
4159 };
4160 
4161 STD_ROM_PICK(borencha)
4162 STD_ROM_FN(borencha)
4163 
4164 struct BurnDriver BurnDrvBorencha = {
4165 	"borencha", "borench", NULL, NULL, "1990",
4166 	"Borench (set 2)\0", NULL, "Sega", "C2",
4167 	NULL, NULL, NULL, NULL,
4168 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4169 	NULL, borenchaRomInfo, borenchaRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, BorenchDIPInfo,
4170 	BorenchInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4171 	320, 224, 4, 3
4172 };
4173 
4174 
4175 // Borench (Japan)
4176 
4177 static struct BurnRomInfo borenchjRomDesc[] = {
4178 	{ "epr-13586.ic32",			0x40000, 0x62d7f8e8, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4179 	{ "epr-13585.ic31",			0x40000, 0x087b9704, 1 | BRF_PRG | BRF_ESS }, //  1
4180 
4181 	{ "epr-13587.ic4",			0x20000, 0x62b85e56, 2 | BRF_SND },           //  2 UPD Samples
4182 };
4183 
4184 STD_ROM_PICK(borenchj)
4185 STD_ROM_FN(borenchj)
4186 
4187 struct BurnDriver BurnDrvBorenchj = {
4188 	"borenchj", "borench", NULL, NULL, "1990",
4189 	"Borench (Japan)\0", NULL, "Sega", "C2",
4190 	NULL, NULL, NULL, NULL,
4191 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4192 	NULL, borenchjRomInfo, borenchjRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, BorenchDIPInfo,
4193 	BorenchInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4194 	320, 224, 4, 3
4195 };
4196 
4197 
4198 // Ribbit!
4199 
4200 static struct BurnRomInfo ribbitRomDesc[] = {
4201 	{ "epr-13833.ic32",			0x40000, 0x5347f8ce, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4202 	{ "epr-13832.ic31",			0x40000, 0x889c42c2, 1 | BRF_PRG | BRF_ESS }, //  1
4203 	{ "epr-13838.ic34",			0x80000, 0xa5d62ac3, 1 | BRF_PRG | BRF_ESS }, //  2
4204 	{ "epr-13837.ic33",			0x80000, 0x434de159, 1 | BRF_PRG | BRF_ESS }, //  3
4205 
4206 	{ "epr-13834.ic4",			0x20000, 0xab0c1833, 2 | BRF_SND },           //  4 UPD Samples
4207 };
4208 
4209 STD_ROM_PICK(ribbit)
STD_ROM_FN(ribbit)4210 STD_ROM_FN(ribbit)
4211 #include "bitswap.h"
4212 static UINT8 ribbit_protection_callback(UINT8 in)
4213 {
4214 	static const UINT8 prot_lut_table[0x100] = {
4215 		0x0f, 0x0f, 0x0b, 0x0b, 0x07, 0x07, 0x03, 0x0b, 0x0f, 0x0f, 0x0b, 0x0f, 0x07, 0x07, 0x03, 0x0f,
4216 		0x0f, 0x0e, 0x0b, 0x0a, 0x0f, 0x0e, 0x0b, 0x0a, 0x0f, 0x0e, 0x0b, 0x0e, 0x0f, 0x0e, 0x0b, 0x0e,
4217 		0x0e, 0x0e, 0x08, 0x08, 0x06, 0x06, 0x01, 0x09, 0x0f, 0x0f, 0x09, 0x0d, 0x07, 0x07, 0x01, 0x0d,
4218 		0x0e, 0x0f, 0x08, 0x09, 0x0e, 0x0f, 0x09, 0x08, 0x0f, 0x0e, 0x09, 0x0c, 0x0f, 0x0e, 0x09, 0x0c,
4219 		0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x0b, 0x05, 0x07, 0x01, 0x07, 0x0f, 0x0f, 0x0b, 0x07,
4220 		0x0d, 0x0e, 0x09, 0x0a, 0x0d, 0x0e, 0x09, 0x0a, 0x05, 0x06, 0x01, 0x06, 0x07, 0x06, 0x03, 0x06,
4221 		0x0c, 0x0e, 0x0a, 0x08, 0x04, 0x06, 0x03, 0x09, 0x05, 0x07, 0x03, 0x05, 0x0f, 0x0f, 0x09, 0x05,
4222 		0x0c, 0x0f, 0x0a, 0x09, 0x0c, 0x0f, 0x0b, 0x08, 0x05, 0x06, 0x03, 0x04, 0x07, 0x06, 0x01, 0x04,
4223 		0x0f, 0x0f, 0x0f, 0x0f, 0x03, 0x03, 0x03, 0x0b, 0x0f, 0x0f, 0x0f, 0x0f, 0x03, 0x03, 0x03, 0x0b,
4224 		0x0f, 0x0e, 0x0f, 0x0e, 0x0b, 0x0a, 0x0b, 0x0a, 0x0f, 0x0e, 0x0f, 0x0e, 0x0b, 0x0a, 0x0b, 0x0a,
4225 		0x0e, 0x0e, 0x0c, 0x0c, 0x02, 0x02, 0x01, 0x09, 0x0f, 0x0f, 0x0d, 0x0d, 0x03, 0x03, 0x01, 0x09,
4226 		0x0e, 0x0f, 0x0c, 0x0d, 0x0a, 0x0b, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
4227 		0x0d, 0x0f, 0x0d, 0x0f, 0x01, 0x03, 0x01, 0x0b, 0x05, 0x07, 0x05, 0x07, 0x0b, 0x0b, 0x0b, 0x03,
4228 		0x0d, 0x0e, 0x0d, 0x0e, 0x09, 0x0a, 0x09, 0x0a, 0x05, 0x06, 0x05, 0x06, 0x03, 0x02, 0x03, 0x02,
4229 		0x0c, 0x0e, 0x0e, 0x0c, 0x00, 0x02, 0x03, 0x09, 0x05, 0x07, 0x07, 0x05, 0x0b, 0x0b, 0x09, 0x01,
4230 		0x0c, 0x0f, 0x0e, 0x0d, 0x08, 0x0b, 0x0b, 0x08, 0x05, 0x06, 0x07, 0x04, 0x03, 0x02, 0x01, 0x00,
4231 	};
4232 
4233 	return prot_lut_table[in];
4234 }
4235 
RibbitInit()4236 static INT32 RibbitInit()
4237 {
4238 	is_ribbit = 1;
4239 
4240 	INT32 rc = SegaC2Init(ribbit_protection_callback);
4241 
4242 	if (!rc) {
4243 		memmove(Drv68KROM + 0x80000, Drv68KROM + 0x00000, 0x80000);
4244 		UPD7759SetStartDelay(0, 250);
4245 	}
4246 
4247 	return rc;
4248 }
4249 
4250 struct BurnDriver BurnDrvRibbit = {
4251 	"ribbit", NULL, NULL, NULL, "1991",
4252 	"Ribbit!\0", NULL, "Sega", "C2",
4253 	NULL, NULL, NULL, NULL,
4254 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_ACTION, 0,
4255 	NULL, ribbitRomInfo, ribbitRomName, NULL, NULL, NULL, NULL, RibbitInputInfo, RibbitDIPInfo,
4256 	RibbitInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4257 	320, 224, 4, 3
4258 };
4259 
4260 
4261 // Ribbit! (Japan)
4262 
4263 static struct BurnRomInfo ribbitjRomDesc[] = {
4264 	{ "epr-13836.ic32",			0x40000, 0x21f222e2, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4265 	{ "epr-13835.ic31",			0x40000, 0x1c4b291a, 1 | BRF_PRG | BRF_ESS }, //  1
4266 	{ "epr-13838.ic34",			0x80000, 0xa5d62ac3, 1 | BRF_PRG | BRF_ESS }, //  2
4267 	{ "epr-13837.ic33",			0x80000, 0x434de159, 1 | BRF_PRG | BRF_ESS }, //  3
4268 
4269 	{ "epr-13834.ic4",			0x20000, 0xab0c1833, 2 | BRF_SND },           //  4 UPD Samples
4270 };
4271 
4272 STD_ROM_PICK(ribbitj)
4273 STD_ROM_FN(ribbitj)
4274 
4275 struct BurnDriver BurnDrvRibbitj = {
4276 	"ribbitj", "ribbit", NULL, NULL, "1991",
4277 	"Ribbit! (Japan)\0", NULL, "Sega", "C2",
4278 	NULL, NULL, NULL, NULL,
4279 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_ACTION, 0,
4280 	NULL, ribbitjRomInfo, ribbitjRomName, NULL, NULL, NULL, NULL, RibbitInputInfo, RibbitjDIPInfo,
4281 	RibbitInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4282 	320, 224, 4, 3
4283 };
4284 
4285 
4286 // Twin Squash
4287 
4288 static struct BurnRomInfo twinsquaRomDesc[] = {
4289 	{ "epr-14657.ic32",			0x40000, 0xbecbb1a1, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4290 	{ "epr-14656.ic31",			0x40000, 0x411906e7, 1 | BRF_PRG | BRF_ESS }, //  1
4291 
4292 	{ "epr-14588.ic4",			0x20000, 0x5a9b6881, 2 | BRF_SND },           //  2 UPD Samples
4293 };
4294 
4295 STD_ROM_PICK(twinsqua)
STD_ROM_FN(twinsqua)4296 STD_ROM_FN(twinsqua)
4297 
4298 static UINT8 twinsqua_protection_callback(UINT8 in)
4299 {
4300 	static const UINT8 prot_lut_table[0x100] = {
4301 		0x0b, 0x0b, 0x03, 0x03, 0x0a, 0x0a, 0x02, 0x02, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e,
4302 		0x0a, 0x08, 0x02, 0x00, 0x0b, 0x0b, 0x03, 0x03, 0x0f, 0x0d, 0x07, 0x05, 0x0e, 0x0e, 0x06, 0x06,
4303 		0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
4304 		0x0a, 0x08, 0x02, 0x00, 0x0a, 0x0a, 0x02, 0x02, 0x0b, 0x09, 0x03, 0x01, 0x0b, 0x0b, 0x03, 0x03,
4305 		0x03, 0x03, 0x0b, 0x0b, 0x02, 0x02, 0x0a, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e,
4306 		0x02, 0x02, 0x0a, 0x0a, 0x03, 0x01, 0x0b, 0x09, 0x07, 0x07, 0x0f, 0x0f, 0x06, 0x04, 0x0e, 0x0c,
4307 		0x03, 0x03, 0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
4308 		0x02, 0x02, 0x0a, 0x0a, 0x02, 0x00, 0x0a, 0x08, 0x03, 0x03, 0x0b, 0x0b, 0x03, 0x01, 0x0b, 0x09,
4309 		0x0b, 0x0b, 0x03, 0x03, 0x0a, 0x0a, 0x02, 0x02, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e,
4310 		0x0e, 0x0c, 0x06, 0x04, 0x0f, 0x0f, 0x07, 0x07, 0x0b, 0x09, 0x03, 0x01, 0x0a, 0x0a, 0x02, 0x02,
4311 		0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
4312 		0x0e, 0x0c, 0x06, 0x04, 0x0e, 0x0e, 0x06, 0x06, 0x0f, 0x0d, 0x07, 0x05, 0x0f, 0x0f, 0x07, 0x07,
4313 		0x03, 0x03, 0x0b, 0x0b, 0x02, 0x02, 0x0a, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e,
4314 		0x06, 0x06, 0x0e, 0x0e, 0x07, 0x05, 0x0f, 0x0d, 0x03, 0x03, 0x0b, 0x0b, 0x02, 0x00, 0x0a, 0x08,
4315 		0x03, 0x03, 0x0b, 0x0b, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
4316 		0x06, 0x06, 0x0e, 0x0e, 0x06, 0x04, 0x0e, 0x0c, 0x07, 0x07, 0x0f, 0x0f, 0x07, 0x05, 0x0f, 0x0d
4317 	};
4318 
4319 	return prot_lut_table[in];
4320 }
4321 
TwinsquaInit()4322 static INT32 TwinsquaInit()
4323 {
4324 	has_dial = 1;
4325 
4326 	return SegaC2Init(twinsqua_protection_callback);
4327 }
4328 
4329 struct BurnDriver BurnDrvTwinsqua = {
4330 	"twinsqua", NULL, NULL, NULL, "1991",
4331 	"Twin Squash\0", NULL, "Sega", "C2",
4332 	NULL, NULL, NULL, NULL,
4333 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_BREAKOUT, 0,
4334 	NULL, twinsquaRomInfo, twinsquaRomName, NULL, NULL, NULL, NULL, TwinsquaInputInfo, TwinsquaDIPInfo,
4335 	TwinsquaInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4336 	320, 224, 4, 3
4337 };
4338 
4339 
4340 // Waku Waku Sonic Patrol Car
4341 
4342 static struct BurnRomInfo soniccarRomDesc[] = {
4343 	{ "epr-14369.ic32",			0x40000, 0x2ea4c9a3, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4344 	{ "epr-14395.ic31",			0x40000, 0x39622e18, 1 | BRF_PRG | BRF_ESS }, //  1
4345 
4346 	{ "epr-14394.ic4",			0x40000, 0x476e30dd, 2 | BRF_SND },           //  2 UPD Samples
4347 };
4348 
4349 STD_ROM_PICK(soniccar)
4350 STD_ROM_FN(soniccar)
4351 
4352 struct BurnDriver BurnDrvSoniccar = {
4353 	"soniccar", NULL, NULL, NULL, "1991",
4354 	"Waku Waku Sonic Patrol Car\0", NULL, "Sega", "C2",
4355 	NULL, NULL, NULL, NULL,
4356 	BDF_GAME_WORKING, 1, HARDWARE_SEGA_MISC, GBF_ACTION, 0,
4357 	NULL, soniccarRomInfo, soniccarRomName, NULL, NULL, NULL, NULL, SoniccarInputInfo, SoniccarDIPInfo,
4358 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4359 	320, 224, 4, 3
4360 };
4361 
4362 
4363 // SegaSonic Bros. (prototype, hack)
4364 
4365 static struct BurnRomInfo ssonicbrRomDesc[] = {
4366 	{ "ssonicbr.ic32",			0x40000, 0xcf254ecd, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4367 	{ "ssonicbr.ic31",			0x40000, 0x03709746, 1 | BRF_PRG | BRF_ESS }, //  1
4368 
4369 	{ "ssonicbr.ic4",			0x20000, 0x78e56a51, 2 | BRF_SND },           //  2 UPD Samples
4370 };
4371 
4372 STD_ROM_PICK(ssonicbr)
4373 STD_ROM_FN(ssonicbr)
4374 
4375 struct BurnDriver BurnDrvSsonicbr = {
4376 	"ssonicbr", NULL, NULL, NULL, "1992",
4377 	"SegaSonic Bros. (prototype, hack)\0", NULL, "hack", "C2",
4378 	NULL, NULL, NULL, NULL,
4379 	BDF_GAME_WORKING | BDF_PROTOTYPE | BDF_HACK, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4380 	NULL, ssonicbrRomInfo, ssonicbrRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, SsonicbrDIPInfo,
4381 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4382 	320, 224, 4, 3
4383 };
4384 
4385 
4386 // OOPArts (prototype, joystick hack)
4387 
4388 static struct BurnRomInfo oopartsRomDesc[] = {
4389 	{ "ooparts.ic32",			0x80000, 0x8dcf2940, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4390 	{ "ooparts.ic31",			0x80000, 0x35381899, 1 | BRF_PRG | BRF_ESS }, //  1
4391 	{ "ooparts.ic34",			0x80000, 0x7192ac29, 1 | BRF_PRG | BRF_ESS }, //  2
4392 	{ "ooparts.ic33",			0x80000, 0x42755dc2, 1 | BRF_PRG | BRF_ESS }, //  3
4393 
4394 	{ "epr-13655.ic4",			0x40000, 0xe09961f6, 2 | BRF_SND },           //  4 UPD Samples
4395 };
4396 
4397 STD_ROM_PICK(ooparts)
4398 STD_ROM_FN(ooparts)
4399 
4400 struct BurnDriver BurnDrvOoparts = {
4401 	"ooparts", NULL, NULL, NULL, "1992",
4402 	"OOPArts (prototype, joystick hack)\0", NULL, "hack", "C2",
4403 	NULL, NULL, NULL, NULL,
4404 	BDF_GAME_WORKING | BDF_PROTOTYPE | BDF_HACK | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_SEGA_MISC, GBF_BREAKOUT, 0,
4405 	NULL, oopartsRomInfo, oopartsRomName, NULL, NULL, NULL, NULL, OopartsInputInfo, OopartsDIPInfo,
4406 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4407 	224, 320, 3, 4
4408 };
4409 
4410 
4411 // Puyo Puyo (World)
4412 
4413 static struct BurnRomInfo puyoRomDesc[] = {
4414 	{ "epr-15198.ic32",			0x20000, 0x9610d80c, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4415 	{ "epr-15197.ic31",			0x20000, 0x7b1f3229, 1 | BRF_PRG | BRF_ESS }, //  1
4416 	{ "epr-15200.ic34",			0x20000, 0x0a0692e5, 1 | BRF_PRG | BRF_ESS }, //  2
4417 	{ "epr-15199.ic33",			0x20000, 0x353109b8, 1 | BRF_PRG | BRF_ESS }, //  3
4418 
4419 	{ "epr-15196.ic4",			0x20000, 0x79112b3b, 2 | BRF_SND },           //  4 UPD Samples
4420 };
4421 
4422 STD_ROM_PICK(puyo)
STD_ROM_FN(puyo)4423 STD_ROM_FN(puyo)
4424 
4425 static UINT8 puyo_protection_callback(UINT8 in)
4426 {
4427 	static const UINT8 prot_lut_table[0x100] = {
4428 		0x03, 0x03, 0x0a, 0x0a, 0x05, 0x05, 0x0c, 0x0c, 0x03, 0x03, 0x0a, 0x0a, 0x05, 0x05, 0x0c, 0x0c,
4429 		0x0b, 0x0a, 0x02, 0x02, 0x0f, 0x0e, 0x06, 0x06, 0x0b, 0x0a, 0x02, 0x02, 0x0f, 0x0e, 0x06, 0x06,
4430 		0x07, 0x07, 0x0e, 0x0e, 0x05, 0x05, 0x0c, 0x0c, 0x05, 0x05, 0x0c, 0x0c, 0x07, 0x07, 0x0e, 0x0e,
4431 		0x0f, 0x0e, 0x06, 0x06, 0x0f, 0x0e, 0x06, 0x06, 0x0d, 0x0c, 0x04, 0x04, 0x0d, 0x0c, 0x04, 0x04,
4432 		0x03, 0x03, 0x0a, 0x0a, 0x07, 0x07, 0x0e, 0x0e, 0x07, 0x07, 0x0a, 0x0a, 0x03, 0x03, 0x0e, 0x0e,
4433 		0x0b, 0x0a, 0x02, 0x02, 0x0f, 0x0e, 0x06, 0x06, 0x0f, 0x0e, 0x02, 0x02, 0x0b, 0x0a, 0x06, 0x06,
4434 		0x07, 0x07, 0x0e, 0x0e, 0x07, 0x07, 0x0e, 0x0e, 0x01, 0x01, 0x0c, 0x0c, 0x01, 0x01, 0x0c, 0x0c,
4435 		0x0f, 0x0e, 0x06, 0x06, 0x0f, 0x0e, 0x06, 0x06, 0x09, 0x08, 0x04, 0x04, 0x09, 0x08, 0x04, 0x04,
4436 		0x02, 0x02, 0x0b, 0x0b, 0x04, 0x04, 0x0d, 0x0d, 0x03, 0x0b, 0x0a, 0x02, 0x05, 0x0d, 0x0c, 0x04,
4437 		0x0a, 0x0b, 0x03, 0x03, 0x0e, 0x0f, 0x07, 0x07, 0x0b, 0x0a, 0x02, 0x02, 0x0f, 0x0e, 0x06, 0x06,
4438 		0x06, 0x06, 0x0f, 0x0f, 0x04, 0x04, 0x0d, 0x0d, 0x05, 0x0d, 0x0c, 0x04, 0x07, 0x0f, 0x0e, 0x06,
4439 		0x0e, 0x0f, 0x07, 0x07, 0x0e, 0x0f, 0x07, 0x07, 0x0d, 0x0c, 0x04, 0x04, 0x0d, 0x0c, 0x04, 0x04,
4440 		0x02, 0x02, 0x0b, 0x0b, 0x06, 0x06, 0x0f, 0x0f, 0x07, 0x0f, 0x0a, 0x02, 0x03, 0x0b, 0x0e, 0x06,
4441 		0x0a, 0x0b, 0x03, 0x03, 0x0e, 0x0f, 0x07, 0x07, 0x0f, 0x0e, 0x02, 0x02, 0x0b, 0x0a, 0x06, 0x06,
4442 		0x06, 0x06, 0x0f, 0x0f, 0x06, 0x06, 0x0f, 0x0f, 0x01, 0x09, 0x0c, 0x04, 0x01, 0x09, 0x0c, 0x04,
4443 		0x0e, 0x0f, 0x07, 0x07, 0x0e, 0x0f, 0x07, 0x07, 0x09, 0x08, 0x04, 0x04, 0x09, 0x08, 0x04, 0x04,
4444 	};
4445 
4446 	return prot_lut_table[in];
4447 }
4448 
PuyoInit()4449 static INT32 PuyoInit()
4450 {
4451 	return SegaC2Init(puyo_protection_callback);
4452 }
4453 
4454 struct BurnDriver BurnDrvPuyo = {
4455 	"puyo", NULL, NULL, NULL, "1992",
4456 	"Puyo Puyo (World)\0", NULL, "Compile / Sega", "C2",
4457 	NULL, NULL, NULL, NULL,
4458 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4459 	NULL, puyoRomInfo, puyoRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, PuyoDIPInfo,
4460 	PuyoInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4461 	320, 224, 4, 3
4462 };
4463 
4464 
4465 // Puyo Puyo (Japan, Rev B)
4466 
4467 static struct BurnRomInfo puyojRomDesc[] = {
4468 	{ "epr-15036b.ic32",		0x20000, 0x5310ca1b, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4469 	{ "epr-15035b.ic31",		0x20000, 0xbc62e400, 1 | BRF_PRG | BRF_ESS }, //  1
4470 	{ "epr-15038.ic34",			0x20000, 0x3b9eea0c, 1 | BRF_PRG | BRF_ESS }, //  2
4471 	{ "epr-15037.ic33",			0x20000, 0xbe2f7974, 1 | BRF_PRG | BRF_ESS }, //  3
4472 
4473 	{ "epr-15034.ic4",			0x20000, 0x5688213b, 2 | BRF_SND },           //  4 UPD Samples
4474 
4475 	{ "315-5452.ic24",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  5 pals
4476 	{ "315-5394.ic25",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  6
4477 	{ "315-5395.ic26",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  7
4478 	{ "317-0203.ic27",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  8
4479 };
4480 
4481 STD_ROM_PICK(puyoj)
4482 STD_ROM_FN(puyoj)
4483 
4484 struct BurnDriver BurnDrvPuyoj = {
4485 	"puyoj", "puyo", NULL, NULL, "1992",
4486 	"Puyo Puyo (Japan, Rev B)\0", NULL, "Compile / Sega", "C2",
4487 	NULL, NULL, NULL, NULL,
4488 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4489 	NULL, puyojRomInfo, puyojRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, PuyoDIPInfo,
4490 	PuyoInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4491 	320, 224, 4, 3
4492 };
4493 
4494 
4495 // Puyo Puyo (Japan, Rev A)
4496 
4497 static struct BurnRomInfo puyojaRomDesc[] = {
4498 	{ "epr-15036a.ic32",		0x20000, 0x61b35257, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4499 	{ "epr-15035a.ic31",		0x20000, 0xdfebb6d9, 1 | BRF_PRG | BRF_ESS }, //  1
4500 	{ "epr-15038.ic34",			0x20000, 0x3b9eea0c, 1 | BRF_PRG | BRF_ESS }, //  2
4501 	{ "epr-15037.ic33",			0x20000, 0xbe2f7974, 1 | BRF_PRG | BRF_ESS }, //  3
4502 
4503 	{ "epr-15034.ic4",			0x20000, 0x5688213b, 2 | BRF_SND },           //  4 UPD Samples
4504 
4505 	{ "315-5452.ic24",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  5 pals
4506 	{ "315-5394.ic25",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  6
4507 	{ "315-5395.ic26",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  7
4508 	{ "317-0203.ic27",			0x00001, 0x00000000, 0 | BRF_NODUMP | BRF_OPT },           //  8
4509 };
4510 
4511 STD_ROM_PICK(puyoja)
4512 STD_ROM_FN(puyoja)
4513 
4514 struct BurnDriver BurnDrvPuyoja = {
4515 	"puyoja", "puyo", NULL, NULL, "1992",
4516 	"Puyo Puyo (Japan, Rev A)\0", NULL, "Compile / Sega", "C2",
4517 	NULL, NULL, NULL, NULL,
4518 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4519 	NULL, puyojaRomInfo, puyojaRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, PuyoDIPInfo,
4520 	PuyoInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4521 	320, 224, 4, 3
4522 };
4523 
4524 
4525 // Puyo Puyo (World, bootleg)
4526 
4527 static struct BurnRomInfo puyoblRomDesc[] = {
4528 	{ "puyopuyb.4bo",			0x20000, 0x89ea4d33, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4529 	{ "puyopuyb.3bo",			0x20000, 0xc002e545, 1 | BRF_PRG | BRF_ESS }, //  1
4530 	{ "puyopuyb.6bo",			0x20000, 0x0a0692e5, 1 | BRF_PRG | BRF_ESS }, //  2
4531 	{ "puyopuyb.5bo",			0x20000, 0x353109b8, 1 | BRF_PRG | BRF_ESS }, //  3
4532 
4533 	{ "puyopuyb.abo",			0x20000, 0x79112b3b, 2 | BRF_SND },           //  4 UPD Samples
4534 };
4535 
4536 STD_ROM_PICK(puyobl)
4537 STD_ROM_FN(puyobl)
4538 
4539 struct BurnDriver BurnDrvPuyobl = {
4540 	"puyobl", "puyo", NULL, NULL, "1992",
4541 	"Puyo Puyo (World, bootleg)\0", NULL, "bootleg", "C2",
4542 	NULL, NULL, NULL, NULL,
4543 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4544 	NULL, puyoblRomInfo, puyoblRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, PuyoDIPInfo,
4545 	PuyoInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4546 	320, 224, 4, 3
4547 };
4548 
4549 
4550 // Puzzle & Action: Tant-R (Japan)
4551 
4552 static struct BurnRomInfo tantrRomDesc[] = {
4553 	{ "epr-15614.ic32",			0x80000, 0x557782bc, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4554 	{ "epr-15613.ic31",			0x80000, 0x14bbb235, 1 | BRF_PRG | BRF_ESS }, //  1
4555 	{ "mpr-15616.ic34",			0x80000, 0x17b80202, 1 | BRF_PRG | BRF_ESS }, //  2
4556 	{ "mpr-15615.ic33",			0x80000, 0x36a88bd4, 1 | BRF_PRG | BRF_ESS }, //  3
4557 
4558 	{ "epr-15617.ic4",			0x40000, 0x338324a1, 2 | BRF_SND },           //  4 UPD Samples
4559 };
4560 
4561 STD_ROM_PICK(tantr)
STD_ROM_FN(tantr)4562 STD_ROM_FN(tantr)
4563 
4564 static UINT8 tantr_protection_callback(UINT8 in)
4565 {
4566 	static const UINT8 prot_lut_table[0x100] = {
4567 		0x09, 0x01, 0x0d, 0x0d, 0x0d, 0x01, 0x09, 0x0d, 0x09, 0x01, 0x0d, 0x0d, 0x0d, 0x01, 0x09, 0x0d,
4568 		0x0d, 0x04, 0x0d, 0x0c, 0x09, 0x04, 0x09, 0x0c, 0x0f, 0x06, 0x0f, 0x0e, 0x0b, 0x06, 0x0b, 0x0e,
4569 		0x09, 0x01, 0x0b, 0x0b, 0x0d, 0x01, 0x0f, 0x0b, 0x09, 0x01, 0x0b, 0x0b, 0x0d, 0x01, 0x0f, 0x0b,
4570 		0x0d, 0x04, 0x0f, 0x0e, 0x09, 0x04, 0x0b, 0x0e, 0x0f, 0x06, 0x0f, 0x0e, 0x0b, 0x06, 0x0b, 0x0e,
4571 		0x08, 0x00, 0x0c, 0x0c, 0x0e, 0x02, 0x0a, 0x0e, 0x08, 0x08, 0x0c, 0x0c, 0x0e, 0x0a, 0x0a, 0x0e,
4572 		0x0c, 0x05, 0x0c, 0x0d, 0x0a, 0x07, 0x0a, 0x0f, 0x0e, 0x0f, 0x0e, 0x0f, 0x08, 0x0d, 0x08, 0x0d,
4573 		0x09, 0x01, 0x0b, 0x0b, 0x0f, 0x03, 0x0d, 0x09, 0x09, 0x09, 0x0b, 0x0b, 0x0f, 0x0b, 0x0d, 0x09,
4574 		0x0d, 0x04, 0x0f, 0x0e, 0x0b, 0x06, 0x09, 0x0c, 0x0f, 0x0e, 0x0f, 0x0e, 0x09, 0x0c, 0x09, 0x0c,
4575 		0x05, 0x0d, 0x05, 0x05, 0x09, 0x05, 0x09, 0x0d, 0x05, 0x0d, 0x05, 0x05, 0x09, 0x05, 0x09, 0x0d,
4576 		0x05, 0x0c, 0x05, 0x04, 0x09, 0x04, 0x09, 0x0c, 0x07, 0x0e, 0x07, 0x06, 0x0b, 0x06, 0x0b, 0x0e,
4577 		0x05, 0x0d, 0x07, 0x07, 0x09, 0x05, 0x0b, 0x0f, 0x05, 0x0d, 0x07, 0x07, 0x09, 0x05, 0x0b, 0x0f,
4578 		0x05, 0x0c, 0x07, 0x06, 0x09, 0x04, 0x0b, 0x0e, 0x07, 0x0e, 0x07, 0x06, 0x0b, 0x06, 0x0b, 0x0e,
4579 		0x05, 0x0d, 0x05, 0x05, 0x0b, 0x07, 0x0b, 0x0f, 0x04, 0x04, 0x04, 0x04, 0x0a, 0x0e, 0x0a, 0x0e,
4580 		0x05, 0x0c, 0x05, 0x04, 0x0b, 0x06, 0x0b, 0x0e, 0x06, 0x07, 0x06, 0x07, 0x08, 0x0d, 0x08, 0x0d,
4581 		0x05, 0x0d, 0x07, 0x07, 0x0b, 0x07, 0x09, 0x0d, 0x05, 0x05, 0x07, 0x07, 0x0b, 0x0f, 0x09, 0x0d,
4582 		0x05, 0x0c, 0x07, 0x06, 0x0b, 0x06, 0x09, 0x0c, 0x07, 0x06, 0x07, 0x06, 0x09, 0x0c, 0x09, 0x0c,
4583 	};
4584 
4585 	return prot_lut_table[in];
4586 }
4587 
TantrInit()4588 static INT32 TantrInit()
4589 {
4590 	return SegaC2Init(tantr_protection_callback);
4591 }
4592 
4593 struct BurnDriver BurnDrvTantr = {
4594 	"tantr", NULL, NULL, NULL, "1992",
4595 	"Puzzle & Action: Tant-R (Japan)\0", NULL, "Sega", "C2",
4596 	NULL, NULL, NULL, NULL,
4597 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4598 	NULL, tantrRomInfo, tantrRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4599 	TantrInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4600 	320, 224, 4, 3
4601 };
4602 
4603 
4604 // Puzzle & Action: Tant-R (Korea)
4605 
4606 static struct BurnRomInfo tantrkorRomDesc[] = {
4607 	{ "mpr-15592b.ic32",		0x80000, 0x7efe26b3, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4608 	{ "mpr-15592b.ic31",		0x80000, 0xaf5a860f, 1 | BRF_PRG | BRF_ESS }, //  1
4609 	{ "mpr-15992b.ic34",		0x80000, 0x6282a5d4, 1 | BRF_PRG | BRF_ESS }, //  2
4610 	{ "mpr-15592b.ic33",		0x80000, 0x82d78413, 1 | BRF_PRG | BRF_ESS }, //  3
4611 
4612 	{ "epr-15617.ic4",			0x40000, 0x338324a1, 2 | BRF_SND },           //  4 UPD Samples
4613 };
4614 
4615 STD_ROM_PICK(tantrkor)
STD_ROM_FN(tantrkor)4616 STD_ROM_FN(tantrkor)
4617 
4618 static UINT8 tantrkor_protection_callback(UINT8 in)
4619 {
4620 	static const UINT8 prot_lut_table[0x100] = {
4621 		0x08, 0x00, 0x09, 0x03, 0x01, 0x01, 0x00, 0x02, 0x0c, 0x04, 0x0d, 0x07, 0x05, 0x05, 0x04, 0x06,
4622 		0x0d, 0x05, 0x08, 0x02, 0x05, 0x05, 0x00, 0x02, 0x09, 0x01, 0x0c, 0x06, 0x01, 0x01, 0x04, 0x06,
4623 		0x00, 0x08, 0x01, 0x0b, 0x09, 0x09, 0x08, 0x0a, 0x04, 0x0c, 0x05, 0x0f, 0x0d, 0x0d, 0x0c, 0x0e,
4624 		0x05, 0x0d, 0x00, 0x0a, 0x0d, 0x0d, 0x08, 0x0a, 0x01, 0x09, 0x04, 0x0e, 0x09, 0x09, 0x0c, 0x0e,
4625 		0x0c, 0x04, 0x0d, 0x07, 0x07, 0x07, 0x06, 0x04, 0x0c, 0x04, 0x0d, 0x07, 0x07, 0x07, 0x06, 0x04,
4626 		0x09, 0x01, 0x0c, 0x06, 0x03, 0x03, 0x06, 0x04, 0x09, 0x01, 0x0c, 0x06, 0x03, 0x03, 0x06, 0x04,
4627 		0x0c, 0x04, 0x0d, 0x07, 0x07, 0x07, 0x06, 0x04, 0x0c, 0x04, 0x0d, 0x07, 0x07, 0x07, 0x06, 0x04,
4628 		0x09, 0x01, 0x0c, 0x06, 0x03, 0x03, 0x06, 0x04, 0x09, 0x01, 0x0c, 0x06, 0x03, 0x03, 0x06, 0x04,
4629 		0x09, 0x01, 0x09, 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x05, 0x0d, 0x07, 0x04, 0x04, 0x04, 0x06,
4630 		0x0c, 0x04, 0x08, 0x02, 0x04, 0x04, 0x00, 0x02, 0x08, 0x00, 0x0c, 0x06, 0x00, 0x00, 0x04, 0x06,
4631 		0x01, 0x09, 0x01, 0x0b, 0x08, 0x08, 0x08, 0x0a, 0x05, 0x0d, 0x05, 0x0f, 0x0c, 0x0c, 0x0c, 0x0e,
4632 		0x04, 0x0c, 0x00, 0x0a, 0x0c, 0x0c, 0x08, 0x0a, 0x00, 0x08, 0x04, 0x0e, 0x08, 0x08, 0x0c, 0x0e,
4633 		0x0d, 0x05, 0x0d, 0x07, 0x06, 0x06, 0x06, 0x04, 0x0d, 0x05, 0x0d, 0x07, 0x06, 0x06, 0x06, 0x04,
4634 		0x08, 0x00, 0x0c, 0x06, 0x02, 0x02, 0x06, 0x04, 0x08, 0x00, 0x0c, 0x06, 0x02, 0x02, 0x06, 0x04,
4635 		0x0d, 0x05, 0x0d, 0x07, 0x06, 0x06, 0x06, 0x04, 0x0d, 0x05, 0x0d, 0x07, 0x06, 0x06, 0x06, 0x04,
4636 		0x08, 0x00, 0x0c, 0x06, 0x02, 0x02, 0x06, 0x04, 0x08, 0x00, 0x0c, 0x06, 0x02, 0x02, 0x06, 0x04
4637 	};
4638 
4639 	return prot_lut_table[in];
4640 }
4641 
TantrkorInit()4642 static INT32 TantrkorInit()
4643 {
4644 	return SegaC2Init(tantrkor_protection_callback);
4645 }
4646 
4647 struct BurnDriver BurnDrvTantrkor = {
4648 	"tantrkor", "tantr", NULL, NULL, "1993",
4649 	"Puzzle & Action: Tant-R (Korea)\0", NULL, "Sega", "C2",
4650 	NULL, NULL, NULL, NULL,
4651 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4652 	NULL, tantrkorRomInfo, tantrkorRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4653 	TantrkorInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4654 	320, 224, 4, 3
4655 };
4656 
4657 
4658 // Puzzle & Action: Tant-R (Japan) (bootleg set 1)
4659 
4660 static struct BurnRomInfo tantrblRomDesc[] = {
4661 	{ "pa_e10.bin",				0x80000, 0x6c3f711f, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4662 	{ "pa_f10.bin",				0x80000, 0x75526786, 1 | BRF_PRG | BRF_ESS }, //  1
4663 	{ "mpr-15616.ic34",			0x80000, 0x17b80202, 1 | BRF_PRG | BRF_ESS }, //  2
4664 	{ "mpr-15615.ic33",			0x80000, 0x36a88bd4, 1 | BRF_PRG | BRF_ESS }, //  3
4665 
4666 	{ "pa_e03.bin",				0x20000, 0x72918c58, 2 | BRF_SND },           //  4 UPD Samples
4667 	{ "pa_e02.bin",				0x20000, 0x4e85b2a3, 2 | BRF_SND },           //  5
4668 };
4669 
4670 STD_ROM_PICK(tantrbl)
4671 STD_ROM_FN(tantrbl)
4672 
4673 struct BurnDriver BurnDrvTantrbl = {
4674 	"tantrbl", "tantr", NULL, NULL, "1992",
4675 	"Puzzle & Action: Tant-R (Japan) (bootleg set 1)\0", NULL, "bootleg", "C2",
4676 	NULL, NULL, NULL, NULL,
4677 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4678 	NULL, tantrblRomInfo, tantrblRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4679 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4680 	320, 224, 4, 3
4681 };
4682 
4683 
4684 // Puzzle & Action: Tant-R (Japan) (bootleg set 2)
4685 
4686 static struct BurnRomInfo tantrbl2RomDesc[] = {
4687 	{ "trb2_2.32",				0x80000, 0x8fc99c48, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4688 	{ "trb2_1.31",				0x80000, 0xc318d00d, 1 | BRF_PRG | BRF_ESS }, //  1
4689 	{ "mpr-15616.ic34",			0x80000, 0x17b80202, 1 | BRF_PRG | BRF_ESS }, //  2
4690 	{ "mpr-15615.ic33",			0x80000, 0x36a88bd4, 1 | BRF_PRG | BRF_ESS }, //  3
4691 };
4692 
4693 STD_ROM_PICK(tantrbl2)
4694 STD_ROM_FN(tantrbl2)
4695 
4696 struct BurnDriver BurnDrvTantrbl2 = {
4697 	"tantrbl2", "tantr", NULL, NULL, "1994",
4698 	"Puzzle & Action: Tant-R (Japan) (bootleg set 2)\0", NULL, "bootleg", "C2",
4699 	NULL, NULL, NULL, NULL,
4700 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4701 	NULL, tantrbl2RomInfo, tantrbl2RomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4702 	TantrInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4703 	320, 224, 4, 3
4704 };
4705 
4706 
4707 // Puzzle & Action: Tant-R (Japan) (bootleg set 3)
4708 
4709 static struct BurnRomInfo tantrbl3RomDesc[] = {
4710 	{ "2.u29",					0x80000, 0xfaecb7b1, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4711 	{ "1.u28",					0x80000, 0x3304556d, 1 | BRF_PRG | BRF_ESS }, //  1
4712 	{ "4.u31",					0x80000, 0x17b80202, 1 | BRF_PRG | BRF_ESS }, //  2
4713 	{ "3.u30",					0x80000, 0x36a88bd4, 1 | BRF_PRG | BRF_ESS }, //  3
4714 };
4715 
4716 STD_ROM_PICK(tantrbl3)
4717 STD_ROM_FN(tantrbl3)
4718 
4719 struct BurnDriver BurnDrvTantrbl3 = {
4720 	"tantrbl3", "tantr", NULL, NULL, "1994",
4721 	"Puzzle & Action: Tant-R (Japan) (bootleg set 3)\0", NULL, "bootleg", "C2",
4722 	NULL, NULL, NULL, NULL,
4723 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4724 	NULL, tantrbl3RomInfo, tantrbl3RomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4725 	TantrInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4726 	320, 224, 4, 3
4727 };
4728 
4729 
4730 // Puzzle & Action: Tant-R (Japan) (bootleg set 4)
4731 
4732 static struct BurnRomInfo tantrbl4RomDesc[] = {
4733 	{ "a.bin",					0x80000, 0x25cafec2, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4734 	{ "b.bin",					0x80000, 0x8cf5ffd5, 1 | BRF_PRG | BRF_ESS }, //  1
4735 	{ "d.bin",					0x80000, 0x17b80202, 1 | BRF_PRG | BRF_ESS }, //  2
4736 	{ "c.bin",					0x80000, 0x36a88bd4, 1 | BRF_PRG | BRF_ESS }, //  3
4737 
4738 	{ "2.bin",					0x20000, 0x72918c58, 2 | BRF_SND },           //  4 UPD Samples
4739 	{ "1.bin",					0x20000, 0x4e85b2a3, 2 | BRF_SND },           //  5
4740 };
4741 
4742 STD_ROM_PICK(tantrbl4)
4743 STD_ROM_FN(tantrbl4)
4744 
4745 struct BurnDriver BurnDrvTantrbl4 = {
4746 	"tantrbl4", "tantr", NULL, NULL, "1992",
4747 	"Puzzle & Action: Tant-R (Japan) (bootleg set 4)\0", NULL, "bootleg", "C2",
4748 	NULL, NULL, NULL, NULL,
4749 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
4750 	NULL, tantrbl4RomInfo, tantrbl4RomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
4751 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4752 	320, 224, 4, 3
4753 };
4754 
4755 
4756 // Waku Waku Marine
4757 
4758 static struct BurnRomInfo wwmarineRomDesc[] = {
4759 	{ "epr-15097.ic32",			0x40000, 0x1223a77a, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4760 	{ "epr-15096.ic31",			0x40000, 0x1b833932, 1 | BRF_PRG | BRF_ESS }, //  1
4761 
4762 	{ "epr-15095.ic4",			0x40000, 0xdf13755b, 2 | BRF_SND },           //  2 UPD Samples
4763 };
4764 
4765 STD_ROM_PICK(wwmarine)
STD_ROM_FN(wwmarine)4766 STD_ROM_FN(wwmarine)
4767 
4768 static INT32 WwmarineInit()
4769 {
4770 	is_wwmarine = 1;
4771 	return NoProtectionInit();
4772 }
4773 
4774 struct BurnDriver BurnDrvWwmarine = {
4775 	"wwmarine", NULL, NULL, NULL, "1992",
4776 	"Waku Waku Marine\0", NULL, "Sega", "C2",
4777 	NULL, NULL, NULL, NULL,
4778 	BDF_GAME_WORKING, 1, HARDWARE_SEGA_MISC, GBF_MISC, 0,
4779 	NULL, wwmarineRomInfo, wwmarineRomName, NULL, NULL, NULL, NULL, WwmarineInputInfo, WwmarineDIPInfo,
4780 	WwmarineInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4781 	320, 224, 4, 3
4782 };
4783 
4784 
4785 // SegaSonic Cosmo Fighter
4786 
4787 static struct BurnRomInfo sonicfgtRomDesc[] = {
4788 	{ "epr-16001.ic32",			0x40000, 0x8ed1dc11, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4789 	{ "epr-16000.ic31",			0x40000, 0x1440caec, 1 | BRF_PRG | BRF_ESS }, //  1
4790 	{ "epr-16003.ic34",			0x40000, 0x8933e91c, 1 | BRF_PRG | BRF_ESS }, //  2
4791 	{ "epr-16002.ic33",			0x40000, 0x0ae979cd, 1 | BRF_PRG | BRF_ESS }, //  3
4792 
4793 	{ "epr-16004.ic4",			0x40000, 0xe87e8433, 2 | BRF_SND },           //  4 UPD Samples
4794 };
4795 
4796 STD_ROM_PICK(sonicfgt)
4797 STD_ROM_FN(sonicfgt)
4798 
4799 struct BurnDriver BurnDrvSonicfgt = {
4800 	"sonicfgt", NULL, NULL, NULL, "1993",
4801 	"SegaSonic Cosmo Fighter\0", NULL, "Sega", "C2",
4802 	NULL, NULL, NULL, NULL,
4803 	BDF_GAME_WORKING, 1, HARDWARE_SEGA_MISC, GBF_VERSHOOT, 0,
4804 	NULL, sonicfgtRomInfo, sonicfgtRomName, NULL, NULL, NULL, NULL, SonicfgtInputInfo, SonicfgtDIPInfo,
4805 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4806 	320, 224, 4, 3
4807 };
4808 
4809 
4810 
4811 // Poto Poto (Japan, Rev A)
4812 
4813 static struct BurnRomInfo potopotoRomDesc[] = {
4814 	{ "epr-16662a.ic32",		0x40000, 0xbbd305d6, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4815 	{ "epr-16661a.ic31",		0x40000, 0x5a7d14f4, 1 | BRF_PRG | BRF_ESS }, //  1
4816 
4817 	{ "epr-16660.ic4",			0x40000, 0x8251c61c, 2 | BRF_SND },           //  2 UPD Samples
4818 };
4819 
4820 STD_ROM_PICK(potopoto)
STD_ROM_FN(potopoto)4821 STD_ROM_FN(potopoto)
4822 
4823 static UINT8 potopoto_protection_callback(UINT8 in)
4824 {
4825 	static const UINT8 prot_lut_table[0x100] = {
4826 		0x0b, 0x03, 0x03, 0x0b, 0x0a, 0x02, 0x02, 0x0a, 0x0a, 0x02, 0x03, 0x0b, 0x0b, 0x03, 0x02, 0x0a,
4827 		0x0a, 0x02, 0x02, 0x0a, 0x0a, 0x02, 0x02, 0x0a, 0x0b, 0x03, 0x02, 0x0a, 0x0b, 0x03, 0x02, 0x0a,
4828 		0x0b, 0x01, 0x03, 0x09, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x03, 0x09, 0x0b, 0x01, 0x02, 0x08,
4829 		0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0b, 0x01, 0x02, 0x08, 0x0b, 0x01, 0x02, 0x08,
4830 		0x03, 0x0f, 0x03, 0x0f, 0x02, 0x0e, 0x02, 0x0e, 0x02, 0x0e, 0x03, 0x0f, 0x03, 0x0f, 0x02, 0x0e,
4831 		0x02, 0x0e, 0x02, 0x0e, 0x02, 0x0e, 0x02, 0x0e, 0x03, 0x0f, 0x02, 0x0e, 0x03, 0x0f, 0x02, 0x0e,
4832 		0x03, 0x0d, 0x03, 0x0d, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x03, 0x0d, 0x03, 0x0d, 0x02, 0x0c,
4833 		0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x03, 0x0d, 0x02, 0x0c, 0x03, 0x0d, 0x02, 0x0c,
4834 		0x0d, 0x0d, 0x01, 0x01, 0x0e, 0x0e, 0x02, 0x02, 0x0c, 0x0c, 0x01, 0x01, 0x0f, 0x0f, 0x02, 0x02,
4835 		0x0c, 0x0c, 0x00, 0x00, 0x0e, 0x0e, 0x02, 0x02, 0x0d, 0x0d, 0x00, 0x00, 0x0f, 0x0f, 0x02, 0x02,
4836 		0x0d, 0x0f, 0x01, 0x03, 0x0e, 0x0c, 0x02, 0x00, 0x0c, 0x0e, 0x01, 0x03, 0x0f, 0x0d, 0x02, 0x00,
4837 		0x0c, 0x0e, 0x00, 0x02, 0x0e, 0x0c, 0x02, 0x00, 0x0d, 0x0f, 0x00, 0x02, 0x0f, 0x0d, 0x02, 0x00,
4838 		0x05, 0x01, 0x01, 0x05, 0x06, 0x02, 0x02, 0x06, 0x04, 0x00, 0x01, 0x05, 0x07, 0x03, 0x02, 0x06,
4839 		0x04, 0x00, 0x00, 0x04, 0x06, 0x02, 0x02, 0x06, 0x05, 0x01, 0x00, 0x04, 0x07, 0x03, 0x02, 0x06,
4840 		0x05, 0x03, 0x01, 0x07, 0x06, 0x00, 0x02, 0x04, 0x04, 0x02, 0x01, 0x07, 0x07, 0x01, 0x02, 0x04,
4841 		0x04, 0x02, 0x00, 0x06, 0x06, 0x00, 0x02, 0x04, 0x05, 0x03, 0x00, 0x06, 0x07, 0x01, 0x02, 0x04
4842 	};
4843 
4844 	return prot_lut_table[in];
4845 }
4846 
PotopotoInit()4847 static INT32 PotopotoInit()
4848 {
4849 	return SegaC2Init(potopoto_protection_callback);
4850 }
4851 
4852 struct BurnDriver BurnDrvPotopoto = {
4853 	"potopoto", NULL, NULL, NULL, "1994",
4854 	"Poto Poto (Japan, Rev A)\0", NULL, "Sega", "C2",
4855 	NULL, NULL, NULL, NULL,
4856 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4857 	NULL, potopotoRomInfo, potopotoRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, PotopotoDIPInfo,
4858 	PotopotoInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4859 	320, 224, 4, 3
4860 };
4861 
4862 
4863 
4864 // Stack Columns (World)
4865 
4866 static struct BurnRomInfo stkclmnsRomDesc[] = {
4867 	{ "epr-16874.ic32",	0x80000, 0xd78a871c, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
4868 	{ "epr-16873.ic31",	0x80000, 0x1def1da4, 1 | BRF_PRG | BRF_ESS }, //  1
4869 	{ "mpr-16797.ic34",	0x80000, 0xb28e9bd5, 1 | BRF_PRG | BRF_ESS }, //  2
4870 	{ "mpr-16796.ic33",	0x80000, 0xec7de52d, 1 | BRF_PRG | BRF_ESS }, //  3
4871 
4872 	{ "epr-16793.ic4",	0x20000, 0xebb2d057, 2 | BRF_SND },           //  4 upd
4873 };
4874 
4875 STD_ROM_PICK(stkclmns)
STD_ROM_FN(stkclmns)4876 STD_ROM_FN(stkclmns)
4877 
4878 static UINT8 stkclmns_protection_callback(UINT8 in)
4879 {
4880 	static const UINT8 prot_lut_table[0x100] = {
4881 		0x01, 0x0d, 0x05, 0x09, 0x01, 0x0d, 0x05, 0x09, 0x00, 0x0c, 0x05, 0x09, 0x00, 0x0c, 0x05, 0x09,
4882 		0x01, 0x0d, 0x05, 0x09, 0x00, 0x0c, 0x04, 0x08, 0x00, 0x0c, 0x05, 0x09, 0x01, 0x0d, 0x04, 0x08,
4883 		0x01, 0x0f, 0x05, 0x0b, 0x01, 0x0f, 0x05, 0x0b, 0x00, 0x0e, 0x05, 0x0b, 0x00, 0x0e, 0x05, 0x0b,
4884 		0x01, 0x0f, 0x05, 0x0b, 0x00, 0x0e, 0x04, 0x0a, 0x00, 0x0e, 0x05, 0x0b, 0x01, 0x0f, 0x04, 0x0a,
4885 		0x09, 0x01, 0x05, 0x0d, 0x09, 0x01, 0x05, 0x0d, 0x08, 0x00, 0x05, 0x0d, 0x08, 0x00, 0x05, 0x0d,
4886 		0x09, 0x01, 0x05, 0x0d, 0x08, 0x00, 0x04, 0x0c, 0x08, 0x00, 0x05, 0x0d, 0x09, 0x01, 0x04, 0x0c,
4887 		0x09, 0x03, 0x05, 0x0f, 0x09, 0x03, 0x05, 0x0f, 0x08, 0x02, 0x05, 0x0f, 0x08, 0x02, 0x05, 0x0f,
4888 		0x09, 0x03, 0x05, 0x0f, 0x08, 0x02, 0x04, 0x0e, 0x08, 0x02, 0x05, 0x0f, 0x09, 0x03, 0x04, 0x0e,
4889 		0x01, 0x05, 0x01, 0x05, 0x03, 0x07, 0x03, 0x07, 0x00, 0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07,
4890 		0x01, 0x05, 0x01, 0x05, 0x02, 0x06, 0x02, 0x06, 0x00, 0x04, 0x01, 0x05, 0x03, 0x07, 0x02, 0x06,
4891 		0x01, 0x07, 0x01, 0x07, 0x03, 0x05, 0x03, 0x05, 0x00, 0x06, 0x01, 0x07, 0x02, 0x04, 0x03, 0x05,
4892 		0x01, 0x07, 0x01, 0x07, 0x02, 0x04, 0x02, 0x04, 0x00, 0x06, 0x01, 0x07, 0x03, 0x05, 0x02, 0x04,
4893 		0x09, 0x09, 0x01, 0x01, 0x0b, 0x0b, 0x03, 0x03, 0x08, 0x08, 0x01, 0x01, 0x0a, 0x0a, 0x03, 0x03,
4894 		0x09, 0x09, 0x01, 0x01, 0x0a, 0x0a, 0x02, 0x02, 0x08, 0x08, 0x01, 0x01, 0x0b, 0x0b, 0x02, 0x02,
4895 		0x09, 0x0b, 0x01, 0x03, 0x0b, 0x09, 0x03, 0x01, 0x08, 0x0a, 0x01, 0x03, 0x0a, 0x08, 0x03, 0x01,
4896 		0x09, 0x0b, 0x01, 0x03, 0x0a, 0x08, 0x02, 0x00, 0x08, 0x0a, 0x01, 0x03, 0x0b, 0x09, 0x02, 0x00
4897 	};
4898 
4899 	return prot_lut_table[in];
4900 }
4901 
StkclmnsInit()4902 static INT32 StkclmnsInit()
4903 {
4904 	return SegaC2Init(stkclmns_protection_callback);
4905 }
4906 
4907 struct BurnDriver BurnDrvStkclmns = {
4908 	"stkclmns", NULL, NULL, NULL, "1994",
4909 	"Stack Columns (World)\0", NULL, "Sega", "C2",
4910 	NULL, NULL, NULL, NULL,
4911 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4912 	NULL, stkclmnsRomInfo, stkclmnsRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, StkclmnsDIPInfo,
4913 	StkclmnsInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4914 	320, 224, 4, 3
4915 };
4916 
4917 
4918 // Stack Columns (Japan)
4919 
4920 static struct BurnRomInfo stkclmnsjRomDesc[] = {
4921 	{ "epr-16795.ic32",			0x80000, 0xb478fd02, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4922 	{ "epr-16794.ic31",			0x80000, 0x6d0e8c56, 1 | BRF_PRG | BRF_ESS }, //  1
4923 	{ "mpr-16797.ic34",			0x80000, 0xb28e9bd5, 1 | BRF_PRG | BRF_ESS }, //  2
4924 	{ "mpr-16796.ic33",			0x80000, 0xec7de52d, 1 | BRF_PRG | BRF_ESS }, //  3
4925 
4926 	{ "epr-16793.ic4",			0x20000, 0xebb2d057, 2 | BRF_SND },           //  4 UPD Samples
4927 };
4928 
4929 STD_ROM_PICK(stkclmnsj)
STD_ROM_FN(stkclmnsj)4930 STD_ROM_FN(stkclmnsj)
4931 
4932 static UINT8 stkclmnsj_protection_callback(UINT8 in)
4933 {
4934 	static const UINT8 prot_lut_table[0x100] = {
4935 		0x0c, 0x0c, 0x08, 0x08, 0x0c, 0x0c, 0x08, 0x08, 0x0c, 0x0c, 0x08, 0x08, 0x0c, 0x0c, 0x08, 0x08,
4936 		0x0c, 0x0c, 0x09, 0x09, 0x0c, 0x0c, 0x09, 0x09, 0x0c, 0x0c, 0x09, 0x09, 0x0c, 0x0c, 0x09, 0x09,
4937 		0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
4938 		0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08,
4939 		0x0a, 0x0a, 0x0e, 0x0e, 0x08, 0x08, 0x0c, 0x0c, 0x0e, 0x0e, 0x0a, 0x0a, 0x0c, 0x0c, 0x08, 0x08,
4940 		0x0a, 0x0a, 0x0f, 0x0f, 0x08, 0x08, 0x0d, 0x0d, 0x0e, 0x0e, 0x0b, 0x0b, 0x0c, 0x0c, 0x09, 0x09,
4941 		0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
4942 		0x06, 0x06, 0x07, 0x07, 0x05, 0x05, 0x04, 0x04, 0x0a, 0x0a, 0x0b, 0x0b, 0x09, 0x09, 0x08, 0x08,
4943 		0x0e, 0x0e, 0x0a, 0x0a, 0x0e, 0x0e, 0x0a, 0x0a, 0x0e, 0x0e, 0x0a, 0x0a, 0x0e, 0x0e, 0x0a, 0x0a,
4944 		0x0e, 0x0e, 0x0b, 0x0b, 0x0e, 0x0e, 0x0b, 0x0b, 0x0e, 0x0e, 0x0b, 0x0b, 0x0e, 0x0e, 0x0b, 0x0b,
4945 		0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
4946 		0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08,
4947 		0x00, 0x00, 0x04, 0x04, 0x02, 0x02, 0x06, 0x06, 0x04, 0x04, 0x00, 0x00, 0x06, 0x06, 0x02, 0x02,
4948 		0x00, 0x00, 0x05, 0x05, 0x02, 0x02, 0x07, 0x07, 0x04, 0x04, 0x01, 0x01, 0x06, 0x06, 0x03, 0x03,
4949 		0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
4950 		0x0e, 0x0e, 0x0f, 0x0f, 0x0d, 0x0d, 0x0c, 0x0c, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00
4951 	};
4952 
4953 	return prot_lut_table[in];
4954 }
4955 
StkclmnsjInit()4956 static INT32 StkclmnsjInit()
4957 {
4958 	return SegaC2Init(stkclmnsj_protection_callback);
4959 }
4960 
4961 struct BurnDriver BurnDrvStkclmnsj = {
4962 	"stkclmnsj", "stkclmns", NULL, NULL, "1994",
4963 	"Stack Columns (Japan)\0", NULL, "Sega", "C2",
4964 	NULL, NULL, NULL, NULL,
4965 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
4966 	NULL, stkclmnsjRomInfo, stkclmnsjRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, StkclmnsDIPInfo,
4967 	StkclmnsjInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
4968 	320, 224, 4, 3
4969 };
4970 
4971 
4972 // Puzzle & Action: Ichidant-R (World)
4973 
4974 static struct BurnRomInfo ichirRomDesc[] = {
4975 	{ "pa2_32.bin",				0x80000, 0x7ba0c025, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
4976 	{ "pa2_31.bin",				0x80000, 0x5f86e5cc, 1 | BRF_PRG | BRF_ESS }, //  1
4977 	{ "epr-16888.ic34",			0x80000, 0x85d73722, 1 | BRF_PRG | BRF_ESS }, //  2
4978 	{ "epr-16887.ic33",			0x80000, 0xbc3bbf25, 1 | BRF_PRG | BRF_ESS }, //  3
4979 
4980 	{ "pa2_02.bin",				0x80000, 0xfc7b0da5, 2 | BRF_SND },           //  4 UPD Samples
4981 };
4982 
4983 STD_ROM_PICK(ichir)
STD_ROM_FN(ichir)4984 STD_ROM_FN(ichir)
4985 
4986 static UINT8 ichir_protection_callback(UINT8 in)
4987 {
4988 	static const UINT8 prot_lut_table[0x100] = {
4989 		0x04, 0x0c, 0x04, 0x0c, 0x04, 0x0c, 0x04, 0x0c, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
4990 		0x05, 0x0d, 0x05, 0x0d, 0x04, 0x0c, 0x04, 0x0c, 0x01, 0x09, 0x01, 0x09, 0x00, 0x08, 0x00, 0x08,
4991 		0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02,
4992 		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
4993 		0x00, 0x08, 0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a,
4994 		0x01, 0x09, 0x03, 0x0b, 0x00, 0x08, 0x02, 0x0a, 0x01, 0x09, 0x03, 0x0b, 0x00, 0x08, 0x02, 0x0a,
4995 		0x07, 0x07, 0x05, 0x05, 0x06, 0x06, 0x04, 0x04, 0x03, 0x03, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00,
4996 		0x06, 0x06, 0x04, 0x04, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
4997 		0x06, 0x0e, 0x06, 0x0e, 0x06, 0x0e, 0x06, 0x0e, 0x02, 0x0a, 0x02, 0x0a, 0x02, 0x0a, 0x02, 0x0a,
4998 		0x07, 0x0f, 0x07, 0x0f, 0x06, 0x0e, 0x06, 0x0e, 0x03, 0x0b, 0x03, 0x0b, 0x02, 0x0a, 0x02, 0x0a,
4999 		0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a,
5000 		0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
5001 		0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a, 0x00, 0x08, 0x02, 0x0a, 0x00, 0x08,
5002 		0x03, 0x0b, 0x01, 0x09, 0x02, 0x0a, 0x00, 0x08, 0x03, 0x0b, 0x01, 0x09, 0x02, 0x0a, 0x00, 0x08,
5003 		0x0f, 0x0f, 0x0d, 0x0d, 0x0e, 0x0e, 0x0c, 0x0c, 0x0b, 0x0b, 0x09, 0x09, 0x0a, 0x0a, 0x08, 0x08,
5004 		0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0a, 0x0a, 0x08, 0x08, 0x0a, 0x0a, 0x08, 0x08
5005 	};
5006 
5007 	return prot_lut_table[in];
5008 }
5009 
IchirInit()5010 static INT32 IchirInit()
5011 {
5012 	return SegaC2Init(ichir_protection_callback);
5013 }
5014 
5015 struct BurnDriver BurnDrvIchir = {
5016 	"ichir", NULL, NULL, NULL, "1994",
5017 	"Puzzle & Action: Ichidant-R (World)\0", NULL, "Sega", "C2",
5018 	NULL, NULL, NULL, NULL,
5019 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
5020 	NULL, ichirRomInfo, ichirRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
5021 	IchirInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5022 	320, 224, 4, 3
5023 };
5024 
5025 
5026 // Puzzle & Action: Ichidant-R (Korea)
5027 
5028 static struct BurnRomInfo ichirkRomDesc[] = {
5029 	{ "epr_ichi.32",			0x80000, 0x804dea11, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5030 	{ "epr_ichi.31",			0x80000, 0x92452353, 1 | BRF_PRG | BRF_ESS }, //  1
5031 	{ "epr-16888.ic34",			0x80000, 0x85d73722, 1 | BRF_PRG | BRF_ESS }, //  2
5032 	{ "epr-16887.ic33",			0x80000, 0xbc3bbf25, 1 | BRF_PRG | BRF_ESS }, //  3
5033 
5034 	{ "pa2_02.bin",				0x80000, 0xfc7b0da5, 2 | BRF_SND },           //  4 UPD Samples
5035 };
5036 
5037 STD_ROM_PICK(ichirk)
STD_ROM_FN(ichirk)5038 STD_ROM_FN(ichirk)
5039 
5040 static UINT8 ichirk_protection_callback(UINT8 in)
5041 {
5042 	static const UINT8 prot_lut_table[0x100] = {
5043 		0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
5044 		0x05, 0x05, 0x01, 0x01, 0x04, 0x04, 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x04, 0x04,
5045 		0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08,
5046 		0x06, 0x06, 0x0b, 0x0b, 0x07, 0x07, 0x0a, 0x0a, 0x06, 0x06, 0x0b, 0x0b, 0x07, 0x07, 0x0a, 0x0a,
5047 		0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x04, 0x06, 0x04, 0x06, 0x04, 0x06, 0x04, 0x06,
5048 		0x01, 0x03, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x05, 0x07, 0x05, 0x07, 0x04, 0x06, 0x04, 0x06,
5049 		0x01, 0x03, 0x08, 0x0a, 0x01, 0x03, 0x08, 0x0a, 0x01, 0x03, 0x08, 0x0a, 0x01, 0x03, 0x08, 0x0a,
5050 		0x02, 0x00, 0x0b, 0x09, 0x03, 0x01, 0x0a, 0x08, 0x02, 0x00, 0x0b, 0x09, 0x03, 0x01, 0x0a, 0x08,
5051 		0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04,
5052 		0x05, 0x05, 0x01, 0x01, 0x04, 0x04, 0x00, 0x00, 0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x04, 0x04,
5053 		0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08, 0x05, 0x05, 0x08, 0x08,
5054 		0x06, 0x06, 0x0b, 0x0b, 0x07, 0x07, 0x0a, 0x0a, 0x06, 0x06, 0x0b, 0x0b, 0x07, 0x07, 0x0a, 0x0a,
5055 		0x08, 0x0a, 0x08, 0x0a, 0x08, 0x0a, 0x08, 0x0a, 0x0c, 0x0e, 0x0c, 0x0e, 0x0c, 0x0e, 0x0c, 0x0e,
5056 		0x09, 0x0b, 0x09, 0x0b, 0x08, 0x0a, 0x08, 0x0a, 0x0d, 0x0f, 0x0d, 0x0f, 0x0c, 0x0e, 0x0c, 0x0e,
5057 		0x09, 0x0b, 0x00, 0x02, 0x09, 0x0b, 0x00, 0x02, 0x09, 0x0b, 0x00, 0x02, 0x09, 0x0b, 0x00, 0x02,
5058 		0x0a, 0x08, 0x03, 0x01, 0x0b, 0x09, 0x02, 0x00, 0x0a, 0x08, 0x03, 0x01, 0x0b, 0x09, 0x02, 0x00,
5059 	};
5060 
5061 	return prot_lut_table[in];
5062 }
5063 
IchirkInit()5064 static INT32 IchirkInit()
5065 {
5066 	return SegaC2Init(ichirk_protection_callback);
5067 }
5068 
5069 struct BurnDriver BurnDrvIchirk = {
5070 	"ichirk", "ichir", NULL, NULL, "1994",
5071 	"Puzzle & Action: Ichidant-R (Korea)\0", NULL, "Sega", "C2",
5072 	NULL, NULL, NULL, NULL,
5073 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
5074 	NULL, ichirkRomInfo, ichirkRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
5075 	IchirkInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5076 	320, 224, 4, 3
5077 };
5078 
5079 
5080 // Puzzle & Action: Ichidant-R (Japan)
5081 
5082 static struct BurnRomInfo ichirjRomDesc[] = {
5083 	{ "epr-16886.ic32",			0x80000, 0x38208e28, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5084 	{ "epr-16885.ic31",			0x80000, 0x1ce4e837, 1 | BRF_PRG | BRF_ESS }, //  1
5085 	{ "epr-16888.ic34",			0x80000, 0x85d73722, 1 | BRF_PRG | BRF_ESS }, //  2
5086 	{ "epr-16887.ic33",			0x80000, 0xbc3bbf25, 1 | BRF_PRG | BRF_ESS }, //  3
5087 
5088 	{ "epr-16884.ic4",			0x80000, 0xfd9dcdd6, 2 | BRF_SND },           //  4 UPD Samples
5089 };
5090 
5091 STD_ROM_PICK(ichirj)
STD_ROM_FN(ichirj)5092 STD_ROM_FN(ichirj)
5093 
5094 static UINT8 ichirj_protection_callback(UINT8 in)
5095 {
5096 	static const UINT8 prot_lut_table[0x100] = {
5097 		0x05, 0x05, 0x01, 0x01, 0x06, 0x06, 0x02, 0x02, 0x05, 0x05, 0x01, 0x01, 0x06, 0x06, 0x02, 0x02,
5098 		0x05, 0x05, 0x01, 0x01, 0x07, 0x07, 0x03, 0x03, 0x05, 0x05, 0x01, 0x01, 0x07, 0x07, 0x03, 0x03,
5099 		0x08, 0x08, 0x00, 0x00, 0x0a, 0x0a, 0x02, 0x02, 0x08, 0x08, 0x00, 0x00, 0x0a, 0x0a, 0x02, 0x02,
5100 		0x08, 0x08, 0x00, 0x00, 0x0b, 0x0b, 0x03, 0x03, 0x08, 0x08, 0x00, 0x00, 0x0b, 0x0b, 0x03, 0x03,
5101 		0x01, 0x01, 0x05, 0x05, 0x00, 0x00, 0x04, 0x04, 0x05, 0x05, 0x01, 0x01, 0x04, 0x04, 0x00, 0x00,
5102 		0x01, 0x01, 0x05, 0x05, 0x01, 0x01, 0x05, 0x05, 0x05, 0x05, 0x01, 0x01, 0x05, 0x05, 0x01, 0x01,
5103 		0x0c, 0x0c, 0x04, 0x04, 0x0c, 0x0c, 0x04, 0x04, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
5104 		0x0c, 0x0c, 0x04, 0x04, 0x0d, 0x0d, 0x05, 0x05, 0x08, 0x08, 0x00, 0x00, 0x09, 0x09, 0x01, 0x01,
5105 		0x0d, 0x0d, 0x09, 0x09, 0x0e, 0x0e, 0x0a, 0x0a, 0x0d, 0x0d, 0x09, 0x09, 0x0e, 0x0e, 0x0a, 0x0a,
5106 		0x0d, 0x0d, 0x09, 0x09, 0x0f, 0x0f, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x09, 0x0f, 0x0f, 0x0b, 0x0b,
5107 		0x0a, 0x0a, 0x02, 0x02, 0x08, 0x08, 0x00, 0x00, 0x0a, 0x0a, 0x02, 0x02, 0x08, 0x08, 0x00, 0x00,
5108 		0x0a, 0x0a, 0x02, 0x02, 0x09, 0x09, 0x01, 0x01, 0x0a, 0x0a, 0x02, 0x02, 0x09, 0x09, 0x01, 0x01,
5109 		0x09, 0x09, 0x0d, 0x0d, 0x08, 0x08, 0x0c, 0x0c, 0x0d, 0x0d, 0x09, 0x09, 0x0c, 0x0c, 0x08, 0x08,
5110 		0x09, 0x09, 0x0d, 0x0d, 0x09, 0x09, 0x0d, 0x0d, 0x0d, 0x0d, 0x09, 0x09, 0x0d, 0x0d, 0x09, 0x09,
5111 		0x0e, 0x0e, 0x06, 0x06, 0x0e, 0x0e, 0x06, 0x06, 0x0a, 0x0a, 0x02, 0x02, 0x0a, 0x0a, 0x02, 0x02,
5112 		0x0e, 0x0e, 0x06, 0x06, 0x0f, 0x0f, 0x07, 0x07, 0x0a, 0x0a, 0x02, 0x02, 0x0b, 0x0b, 0x03, 0x03,
5113 	};
5114 
5115 	return prot_lut_table[in];
5116 }
5117 
IchirjInit()5118 static INT32 IchirjInit()
5119 {
5120 	return SegaC2Init(ichirj_protection_callback);
5121 }
5122 
5123 struct BurnDriver BurnDrvIchirj = {
5124 	"ichirj", "ichir", NULL, NULL, "1994",
5125 	"Puzzle & Action: Ichidant-R (Japan)\0", NULL, "Sega", "C2",
5126 	NULL, NULL, NULL, NULL,
5127 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
5128 	NULL, ichirjRomInfo, ichirjRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
5129 	IchirjInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5130 	320, 224, 4, 3
5131 };
5132 
5133 
5134 // Puzzle & Action: Ichidant-R (Japan) (bootleg)
5135 
5136 static struct BurnRomInfo ichirjblRomDesc[] = {
5137 	{ "27c4000.2",				0x80000, 0x5a194f44, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5138 	{ "27c4000.1",				0x80000, 0xde209f84, 1 | BRF_PRG | BRF_ESS }, //  1
5139 	{ "epr-16888",				0x80000, 0x85d73722, 1 | BRF_PRG | BRF_ESS }, //  2
5140 	{ "epr-16887",				0x80000, 0xbc3bbf25, 1 | BRF_PRG | BRF_ESS }, //  3
5141 };
5142 
5143 STD_ROM_PICK(ichirjbl)
5144 STD_ROM_FN(ichirjbl)
5145 
5146 struct BurnDriver BurnDrvIchirjbl = {
5147 	"ichirjbl", "ichir", NULL, NULL, "1994",
5148 	"Puzzle & Action: Ichidant-R (Japan) (bootleg)\0", NULL, "bootleg", "C2",
5149 	NULL, NULL, NULL, NULL,
5150 	BDF_GAME_WORKING | BDF_CLONE | BDF_BOOTLEG, 2, HARDWARE_SEGA_MISC, GBF_MINIGAMES | GBF_PUZZLE, 0,
5151 	NULL, ichirjblRomInfo, ichirjblRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, IchirDIPInfo,
5152 	IchirInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5153 	320, 224, 4, 3
5154 };
5155 
5156 
5157 // Puyo Puyo 2 (Japan)
5158 
5159 static struct BurnRomInfo puyopuy2RomDesc[] = {
5160 	{ "epr-17241.ic32",			0x80000, 0x1cad1149, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5161 	{ "epr-17240.ic31",			0x80000, 0xbeecf96d, 1 | BRF_PRG | BRF_ESS }, //  1
5162 
5163 	{ "epr-17239.ic4",			0x80000, 0x020ff6ef, 2 | BRF_SND },           //  2 UPD Samples
5164 };
5165 
5166 STD_ROM_PICK(puyopuy2)
STD_ROM_FN(puyopuy2)5167 STD_ROM_FN(puyopuy2)
5168 
5169 static UINT8 puyopuy2_protection_callback(UINT8 in)
5170 {
5171 	static const UINT8 prot_lut_table[0x100] = {
5172 		0x00, 0x03, 0x00, 0x03, 0x08, 0x0b, 0x08, 0x0b, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
5173 		0x0c, 0x0f, 0x04, 0x07, 0x04, 0x07, 0x0c, 0x0f, 0x0c, 0x0f, 0x04, 0x07, 0x0c, 0x0f, 0x04, 0x07,
5174 		0x00, 0x03, 0x00, 0x03, 0x08, 0x0b, 0x08, 0x0b, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
5175 		0x0c, 0x0f, 0x04, 0x07, 0x04, 0x07, 0x0c, 0x0f, 0x0e, 0x0d, 0x06, 0x05, 0x0e, 0x0d, 0x06, 0x05,
5176 		0x04, 0x01, 0x04, 0x01, 0x0c, 0x09, 0x0c, 0x09, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01,
5177 		0x09, 0x0c, 0x00, 0x05, 0x01, 0x04, 0x08, 0x0d, 0x09, 0x0c, 0x00, 0x05, 0x09, 0x0c, 0x00, 0x05,
5178 		0x04, 0x01, 0x04, 0x01, 0x0c, 0x09, 0x0c, 0x09, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03,
5179 		0x09, 0x0c, 0x00, 0x05, 0x01, 0x04, 0x08, 0x0d, 0x0b, 0x0e, 0x02, 0x07, 0x0b, 0x0e, 0x02, 0x07,
5180 		0x05, 0x07, 0x05, 0x07, 0x0d, 0x0f, 0x0d, 0x0f, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07,
5181 		0x0d, 0x0f, 0x05, 0x07, 0x05, 0x07, 0x0d, 0x0f, 0x0d, 0x0f, 0x05, 0x07, 0x0d, 0x0f, 0x05, 0x07,
5182 		0x05, 0x07, 0x05, 0x07, 0x0d, 0x0f, 0x0d, 0x0f, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05,
5183 		0x0d, 0x0f, 0x05, 0x07, 0x05, 0x07, 0x0d, 0x0f, 0x0f, 0x0d, 0x07, 0x05, 0x0f, 0x0d, 0x07, 0x05,
5184 		0x01, 0x05, 0x01, 0x05, 0x09, 0x0d, 0x09, 0x0d, 0x01, 0x05, 0x01, 0x05, 0x01, 0x05, 0x01, 0x05,
5185 		0x08, 0x0c, 0x01, 0x05, 0x00, 0x04, 0x09, 0x0d, 0x08, 0x0c, 0x01, 0x05, 0x08, 0x0c, 0x01, 0x05,
5186 		0x01, 0x05, 0x01, 0x05, 0x09, 0x0d, 0x09, 0x0d, 0x03, 0x07, 0x03, 0x07, 0x03, 0x07, 0x03, 0x07,
5187 		0x08, 0x0c, 0x01, 0x05, 0x00, 0x04, 0x09, 0x0d, 0x0a, 0x0e, 0x03, 0x07, 0x0a, 0x0e, 0x03, 0x07
5188 	};
5189 
5190 	return prot_lut_table[in];
5191 }
5192 
Puyopuy2Init()5193 static INT32 Puyopuy2Init()
5194 {
5195 	return SegaC2Init(puyopuy2_protection_callback);
5196 }
5197 
5198 struct BurnDriver BurnDrvPuyopuy2 = {
5199 	"puyopuy2", NULL, NULL, NULL, "1994",
5200 	"Puyo Puyo 2 (Japan)\0", NULL, "Compile (Sega license)", "C2",
5201 	NULL, NULL, NULL, NULL,
5202 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_PUZZLE, 0,
5203 	NULL, puyopuy2RomInfo, puyopuy2RomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, Puyopuy2DIPInfo,
5204 	Puyopuy2Init, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5205 	320, 224, 4, 3
5206 };
5207 
5208 
5209 // Zunzunkyou no Yabou (Japan)
5210 
5211 static struct BurnRomInfo zunkyouRomDesc[] = {
5212 	{ "epr-16812.ic32",			0x80000, 0xeb088fb0, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5213 	{ "epr-16811.ic31",			0x80000, 0x9ac7035b, 1 | BRF_PRG | BRF_ESS }, //  1
5214 	{ "epr-16814.ic34",			0x80000, 0x821b3b77, 1 | BRF_PRG | BRF_ESS }, //  2
5215 	{ "epr-16813.ic33",			0x80000, 0x3cba9e8f, 1 | BRF_PRG | BRF_ESS }, //  3
5216 
5217 	{ "epr-16810.ic4",			0x80000, 0xd542f0fe, 2 | BRF_SND },           //  4 UPD Samples
5218 };
5219 
5220 STD_ROM_PICK(zunkyou)
STD_ROM_FN(zunkyou)5221 STD_ROM_FN(zunkyou)
5222 
5223 static UINT8 zunkyou_protection_callback(UINT8 in)
5224 {
5225 	static const UINT8 prot_lut_table[0x100] = {
5226 		0x0a, 0x00, 0x0a, 0x00, 0x06, 0x0c, 0x06, 0x0c, 0x08, 0x02, 0x08, 0x02, 0x00, 0x0a, 0x00, 0x0a,
5227 		0x0e, 0x0c, 0x0e, 0x0c, 0x02, 0x00, 0x02, 0x00, 0x0e, 0x0c, 0x0e, 0x0c, 0x06, 0x04, 0x06, 0x04,
5228 		0x0a, 0x02, 0x0a, 0x02, 0x06, 0x0e, 0x06, 0x0e, 0x08, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x08,
5229 		0x0a, 0x0a, 0x0a, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, 0x02, 0x02, 0x02,
5230 		0x03, 0x09, 0x02, 0x08, 0x07, 0x0d, 0x06, 0x0c, 0x01, 0x0b, 0x00, 0x0a, 0x01, 0x0b, 0x00, 0x0a,
5231 		0x07, 0x05, 0x06, 0x04, 0x03, 0x01, 0x02, 0x00, 0x07, 0x05, 0x06, 0x04, 0x07, 0x05, 0x06, 0x04,
5232 		0x03, 0x0b, 0x02, 0x0a, 0x07, 0x0f, 0x06, 0x0e, 0x01, 0x09, 0x00, 0x08, 0x01, 0x09, 0x00, 0x08,
5233 		0x03, 0x03, 0x02, 0x02, 0x07, 0x07, 0x06, 0x06, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x02, 0x02,
5234 		0x0b, 0x01, 0x0b, 0x01, 0x07, 0x0d, 0x07, 0x0d, 0x09, 0x03, 0x09, 0x03, 0x01, 0x0b, 0x01, 0x0b,
5235 		0x0f, 0x0d, 0x0f, 0x0d, 0x03, 0x01, 0x03, 0x01, 0x0f, 0x0d, 0x0f, 0x0d, 0x07, 0x05, 0x07, 0x05,
5236 		0x0a, 0x02, 0x0a, 0x02, 0x06, 0x0e, 0x06, 0x0e, 0x08, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x08,
5237 		0x0a, 0x0a, 0x0a, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, 0x02, 0x02, 0x02,
5238 		0x02, 0x08, 0x03, 0x09, 0x06, 0x0c, 0x07, 0x0d, 0x00, 0x0a, 0x01, 0x0b, 0x00, 0x0a, 0x01, 0x0b,
5239 		0x06, 0x04, 0x07, 0x05, 0x02, 0x00, 0x03, 0x01, 0x06, 0x04, 0x07, 0x05, 0x06, 0x04, 0x07, 0x05,
5240 		0x03, 0x0b, 0x02, 0x0a, 0x07, 0x0f, 0x06, 0x0e, 0x01, 0x09, 0x00, 0x08, 0x01, 0x09, 0x00, 0x08,
5241 		0x03, 0x03, 0x02, 0x02, 0x07, 0x07, 0x06, 0x06, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x02, 0x02,
5242 	};
5243 
5244 	return prot_lut_table[in];
5245 }
5246 
ZunkyouInit()5247 static INT32 ZunkyouInit()
5248 {
5249 	return SegaC2Init(zunkyou_protection_callback);
5250 }
5251 
5252 struct BurnDriver BurnDrvZunkyou = {
5253 	"zunkyou", NULL, NULL, NULL, "1994",
5254 	"Zunzunkyou no Yabou (Japan)\0", NULL, "Sega", "C2",
5255 	NULL, NULL, NULL, NULL,
5256 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_VERSHOOT, 0,
5257 	NULL, zunkyouRomInfo, zunkyouRomName, NULL, NULL, NULL, NULL, SegaC2_2ButtonInputInfo, ZunkyouDIPInfo,
5258 	ZunkyouInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5259 	320, 224, 4, 3
5260 };
5261 
5262 
5263 // Monita to Rimoko no Head On Channel (prototype, hack)
5264 
5265 static struct BurnRomInfo headonchRomDesc[] = {
5266 	{ "headonch.ic32",			0x80000, 0x091cf538, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
5267 	{ "headonch.ic31",			0x80000, 0x91f3b5f1, 1 | BRF_PRG | BRF_ESS }, //  1
5268 	{ "headonch.ic34",			0x80000, 0xd8dc6323, 1 | BRF_PRG | BRF_ESS }, //  2
5269 	{ "headonch.ic33",			0x80000, 0x3268e38b, 1 | BRF_PRG | BRF_ESS }, //  3
5270 
5271 	{ "headonch.ic4",			0x40000, 0x90af7301, 2 | BRF_SND },           //  4 upd
5272 };
5273 
5274 STD_ROM_PICK(headonch)
5275 STD_ROM_FN(headonch)
5276 
5277 struct BurnDriver BurnDrvHeadonch = {
5278 	"headonch", NULL, NULL, NULL, "1994",
5279 	"Monita to Rimoko no Head On Channel (prototype, hack)\0", NULL, "hack", "C2",
5280 	NULL, NULL, NULL, NULL,
5281 	BDF_GAME_WORKING | BDF_PROTOTYPE | BDF_HACK, 2, HARDWARE_SEGA_MISC, GBF_MAZE | GBF_ACTION, 0,
5282 	NULL, headonchRomInfo, headonchRomName, NULL, NULL, NULL, NULL, SegaC2_1ButtonInputInfo, HeadonchDIPInfo,
5283 	NoProtectionInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x1800,
5284 	320, 224, 4, 3
5285 };
5286 
5287 
5288 /*
5289 // Soreike! Anpanman Popcorn Koujou (Rev B)
5290 
5291 static struct BurnRomInfo anpanmanRomDesc[] = {
5292 	{ "epr-14804b.ic32",		0x40000, 0x7ce88c49, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5293 	{ "epr-14803b.ic31",		0x40000, 0xeb3ca1b9, 1 | BRF_PRG | BRF_ESS }, //  1
5294 	{ "epr-14806.ic34",			0x40000, 0x40f398db, 1 | BRF_PRG | BRF_ESS }, //  2
5295 	{ "epr-14805.ic33",			0x40000, 0xf27229ed, 1 | BRF_PRG | BRF_ESS }, //  3
5296 
5297 	{ "epr-14807.ic4",			0x40000, 0x9827549f, 2 | BRF_SND },           //  4 UPD Samples
5298 };
5299 
5300 STD_ROM_PICK(anpanman)
5301 STD_ROM_FN(anpanman)
5302 
5303 struct BurnDriverD BurnDrvAnpanman = {
5304 	"anpanman", NULL, NULL, NULL, "1992",
5305 	"Soreike! Anpanman Popcorn Koujou (Rev B)\0", NULL, "Sega", "C2",
5306 	NULL, NULL, NULL, NULL,
5307 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5308 	NULL, anpanmanRomInfo, anpanmanRomName, NULL, NULL, NULL, NULL, AnpanmanInputInfo, AnpanmanDIPInfo,
5309 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5310 	320, 224, 4, 3
5311 };
5312 
5313 
5314 // SegaSonic Popcorn Shop (Rev B)
5315 
5316 static struct BurnRomInfo sonicpopRomDesc[] = {
5317 	{ "epr-14592b.ic32",		0x40000, 0xbac586a1, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5318 	{ "epr-15491b.ic31",		0x40000, 0x527106c3, 1 | BRF_PRG | BRF_ESS }, //  1
5319 	{ "epr-15494.ic34",			0x40000, 0x0520df5e, 1 | BRF_PRG | BRF_ESS }, //  2
5320 	{ "epr-15493.ic33",			0x40000, 0xd51b3b85, 1 | BRF_PRG | BRF_ESS }, //  3
5321 
5322 	{ "epr-15495.ic4",			0x40000, 0xd3ee4c68, 2 | BRF_SND },           //  4 UPD Samples
5323 };
5324 
5325 STD_ROM_PICK(sonicpop)
5326 STD_ROM_FN(sonicpop)
5327 
5328 struct BurnDriverD BurnDrvSonicpop = {
5329 	"sonicpop", NULL, NULL, NULL, "1993",
5330 	"SegaSonic Popcorn Shop (Rev B)\0", NULL, "Sega", "C2",
5331 	NULL, NULL, NULL, NULL,
5332 	BDF_GAME_WORKING, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5333 	NULL, sonicpopRomInfo, sonicpopRomName, NULL, NULL, NULL, NULL, SonicpopInputInfo, SonicpopDIPInfo,
5334 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5335 	320, 224, 4, 3
5336 };
5337 
5338 
5339 // Print Club (Japan Vol.1)
5340 
5341 static struct BurnRomInfo pclubjRomDesc[] = {
5342 	{ "epr18171.32",			0x80000, 0x6c8eb8e2, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5343 	{ "epr18170.31",			0x80000, 0x72c631e6, 1 | BRF_PRG | BRF_ESS }, //  1
5344 	{ "epr18173.34",			0x80000, 0x9809dc72, 1 | BRF_PRG | BRF_ESS }, //  2
5345 	{ "epr18172.33",			0x80000, 0xc61d819b, 1 | BRF_PRG | BRF_ESS }, //  3
5346 
5347 	{ "epr18169.4",				0x80000, 0x5c00ccfb, 2 | BRF_SND },           //  4 UPD Samples
5348 };
5349 
5350 STD_ROM_PICK(pclubj)
5351 STD_ROM_FN(pclubj)
5352 
5353 struct BurnDriver BurnDrvPclubj = {
5354 	"pclubj", NULL, NULL, NULL, "1995",
5355 	"Print Club (Japan Vol.1)\0", NULL, "Atlus", "C2",
5356 	NULL, NULL, NULL, NULL,
5357 	0, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5358 	NULL, pclubjRomInfo, pclubjRomName, NULL, NULL, NULL, NULL, PclubInputInfo, PclubDIPInfo,
5359 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5360 	320, 224, 4, 3
5361 };
5362 
5363 
5364 // Print Club (Japan Vol.2)
5365 
5366 static struct BurnRomInfo pclubjv2RomDesc[] = {
5367 	{ "p2jwn.u32",				0x80000, 0xdfc0f7f1, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5368 	{ "p2jwn.u31",				0x80000, 0x6ab4c694, 1 | BRF_PRG | BRF_ESS }, //  1
5369 	{ "p2jwn.u34",				0x80000, 0x854fd456, 1 | BRF_PRG | BRF_ESS }, //  2
5370 	{ "p2jwn.u33",				0x80000, 0x64428a69, 1 | BRF_PRG | BRF_ESS }, //  3
5371 
5372 	{ "epr18169.4",				0x80000, 0x5c00ccfb, 2 | BRF_SND },           //  4 UPD Samples
5373 };
5374 
5375 STD_ROM_PICK(pclubjv2)
5376 STD_ROM_FN(pclubjv2)
5377 
5378 struct BurnDriverD BurnDrvPclubjv2 = {
5379 	"pclubjv2", NULL, NULL, NULL, "1995",
5380 	"Print Club (Japan Vol.2)\0", NULL, "Atlus", "C2",
5381 	NULL, NULL, NULL, NULL,
5382 	0, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5383 	NULL, pclubjv2RomInfo, pclubjv2RomName, NULL, NULL, NULL, NULL, Pclubjv2InputInfo, Pclubjv2DIPInfo,
5384 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5385 	320, 224, 4, 3
5386 };
5387 
5388 
5389 // Print Club (Japan Vol.4)
5390 
5391 static struct BurnRomInfo pclubjv4RomDesc[] = {
5392 	{ "p4jsm.u32",				0x80000, 0x36ff5f80, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5393 	{ "p4jsm.u31",				0x80000, 0xf3c021ad, 1 | BRF_PRG | BRF_ESS }, //  1
5394 	{ "p4jsm.u34",				0x80000, 0xd0fd4b33, 1 | BRF_PRG | BRF_ESS }, //  2
5395 	{ "p4jsm.u33",				0x80000, 0xec667875, 1 | BRF_PRG | BRF_ESS }, //  3
5396 
5397 	{ "epr-18169.ic4",			0x80000, 0x5c00ccfb, 2 | BRF_SND },           //  4 UPD Samples
5398 };
5399 
5400 STD_ROM_PICK(pclubjv4)
5401 STD_ROM_FN(pclubjv4)
5402 
5403 struct BurnDriverD BurnDrvPclubjv4 = {
5404 	"pclubjv4", NULL, NULL, NULL, "1996",
5405 	"Print Club (Japan Vol.4)\0", NULL, "Atlus", "C2",
5406 	NULL, NULL, NULL, NULL,
5407 	0, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5408 	NULL, pclubjv4RomInfo, pclubjv4RomName, NULL, NULL, NULL, NULL, Pclubjv2InputInfo, Pclubjv2DIPInfo,
5409 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5410 	320, 224, 4, 3
5411 };
5412 
5413 
5414 // Print Club (Japan Vol.5)
5415 
5416 static struct BurnRomInfo pclubjv5RomDesc[] = {
5417 	{ "p5jat.u32",				0x80000, 0x72220e69, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5418 	{ "p5jat.u31",				0x80000, 0x06d83fde, 1 | BRF_PRG | BRF_ESS }, //  1
5419 	{ "p5jat.u34",				0x80000, 0xb172ab58, 1 | BRF_PRG | BRF_ESS }, //  2
5420 	{ "p5jat.u33",				0x80000, 0xba38ec50, 1 | BRF_PRG | BRF_ESS }, //  3
5421 
5422 	{ "epr-18169.ic4",			0x80000, 0x5c00ccfb, 2 | BRF_SND },           //  4 UPD Samples
5423 };
5424 
5425 STD_ROM_PICK(pclubjv5)
5426 STD_ROM_FN(pclubjv5)
5427 
5428 struct BurnDriverD BurnDrvPclubjv5 = {
5429 	"pclubjv5", NULL, NULL, NULL, "1996",
5430 	"Print Club (Japan Vol.5)\0", NULL, "Atlus", "C2",
5431 	NULL, NULL, NULL, NULL,
5432 	0, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5433 	NULL, pclubjv5RomInfo, pclubjv5RomName, NULL, NULL, NULL, NULL, Pclubjv2InputInfo, Pclubjv2DIPInfo,
5434 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5435 	320, 224, 4, 3
5436 };
5437 
5438 
5439 // Print Club (Japan Vol.1)
5440 
5441 static struct BurnRomInfo pclubRomDesc[] = {
5442 	{ "epr-ic32.32",			0x80000, 0x3fe9bda7, 1 | BRF_PRG | BRF_ESS }, //  0 68K Code
5443 	{ "epr-ic31.31",			0x80000, 0x90f994d0, 1 | BRF_PRG | BRF_ESS }, //  1
5444 	{ "epr-ic34.34",			0x80000, 0x4d1ebb55, 1 | BRF_PRG | BRF_ESS }, //  2
5445 	{ "epr-ic33.33",			0x80000, 0xbdfdc797, 1 | BRF_PRG | BRF_ESS }, //  3
5446 
5447 	{ "epr-ic4.4",				0x80000, 0x84eed1c4, 2 | BRF_SND },           //  4 UPD Samples
5448 };
5449 
5450 STD_ROM_PICK(pclub)
5451 STD_ROM_FN(pclub)
5452 
5453 struct BurnDriverD BurnDrvPclub = {
5454 	"pclub", NULL, NULL, NULL, "1995",
5455 	"Print Club (Japan Vol.1)\0", NULL, "Atlus", "C2",
5456 	NULL, NULL, NULL, NULL,
5457 	0, 2, HARDWARE_SEGA_MISC, GBF_MISC, 0,
5458 	NULL, pclubRomInfo, pclubRomName, NULL, NULL, NULL, NULL, PclubInputInfo, PclubDIPInfo,
5459 	DrvInit, DrvExit, DrvFrame, DrvDraw, NULL, &DrvRecalc, 0,
5460 	320, 224, 4, 3
5461 };
5462 */
5463